]> git.saurik.com Git - apple/mdnsresponder.git/commitdiff
mDNSResponder-1096.0.2.tar.gz macos-1015 v1096.0.2
authorApple <opensource@apple.com>
Fri, 31 Jan 2020 03:01:55 +0000 (03:01 +0000)
committerApple <opensource@apple.com>
Fri, 31 Jan 2020 03:01:55 +0000 (03:01 +0000)
442 files changed:
.gitignore
Clients/FirefoxExtension/CDNSSDService.cpp [deleted file]
Clients/FirefoxExtension/CDNSSDService.h [deleted file]
Clients/FirefoxExtension/CDNSSDServiceModule.cpp [deleted file]
Clients/FirefoxExtension/DNSSDService.sln [deleted file]
Clients/FirefoxExtension/FirefoxExtension.rc [deleted file]
Clients/FirefoxExtension/FirefoxExtension.vcproj [deleted file]
Clients/FirefoxExtension/FirefoxExtension.vcxproj [deleted file]
Clients/FirefoxExtension/FirefoxExtension.vcxproj.filters [deleted file]
Clients/FirefoxExtension/IDNSSDService.h [deleted file]
Clients/FirefoxExtension/IDNSSDService.idl [deleted file]
Clients/FirefoxExtension/extension/chrome.manifest [deleted file]
Clients/FirefoxExtension/extension/components/IDNSSDService.xpt [deleted file]
Clients/FirefoxExtension/extension/content/_internal_bonjour4firefox.png [deleted file]
Clients/FirefoxExtension/extension/content/_internal_listImage.png [deleted file]
Clients/FirefoxExtension/extension/content/bonjour4firefox.css [deleted file]
Clients/FirefoxExtension/extension/content/bonjour4firefox.xul [deleted file]
Clients/FirefoxExtension/extension/content/browserOverlay.xul [deleted file]
Clients/FirefoxExtension/extension/content/overlay.js [deleted file]
Clients/FirefoxExtension/extension/defaults/preferences/bonjour4firefox.js [deleted file]
Clients/FirefoxExtension/extension/install.rdf [deleted file]
Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.dtd [deleted file]
Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.properties [deleted file]
Clients/FirefoxExtension/extension/readme.txt [deleted file]
Clients/FirefoxExtension/extension/skin-darwin/_internal_toobar-button.png [deleted file]
Clients/FirefoxExtension/extension/skin-darwin/overlay.css [deleted file]
Clients/FirefoxExtension/extension/skin/_internal_toobar-button.png [deleted file]
Clients/FirefoxExtension/extension/skin/overlay.css [deleted file]
Clients/FirefoxExtension/readme.txt [deleted file]
Clients/FirefoxExtension/resource.h [deleted file]
Clients/Makefile
Clients/dns-sd.c
Clients/dnsctl.c [deleted file]
Clients/dnssdutil.c [deleted file]
Clients/dnssdutil/DNSMessage.c [new file with mode: 0644]
Clients/dnssdutil/DNSMessage.h [new file with mode: 0644]
Clients/dnssdutil/dnssdutil-entitlements.plist [new file with mode: 0644]
Clients/dnssdutil/dnssdutil.c [new file with mode: 0644]
DSO/dso-transport.c [new file with mode: 0644]
DSO/dso-transport.h [new file with mode: 0644]
DSO/dso.c [new file with mode: 0644]
DSO/dso.h [new file with mode: 0644]
Makefile
README.txt
ServiceRegistration/.gitignore [new file with mode: 0644]
ServiceRegistration/Makefile [new file with mode: 0644]
ServiceRegistration/dns-msg.h [new file with mode: 0644]
ServiceRegistration/dnssd-proxy.c [new file with mode: 0644]
ServiceRegistration/dnssd-proxy.h [new file with mode: 0644]
ServiceRegistration/fromwire.c [new file with mode: 0644]
ServiceRegistration/ioloop.c [new file with mode: 0644]
ServiceRegistration/ioloop.h [new file with mode: 0644]
ServiceRegistration/keydump.c [new file with mode: 0644]
ServiceRegistration/sign-mbedtls.c [new file with mode: 0644]
ServiceRegistration/srp-crypto.h [new file with mode: 0644]
ServiceRegistration/srp-gw.c [new file with mode: 0644]
ServiceRegistration/srp-simple.c [new file with mode: 0644]
ServiceRegistration/srp.c [new file with mode: 0644]
ServiceRegistration/srp.h [new file with mode: 0644]
ServiceRegistration/towire.c [new file with mode: 0644]
ServiceRegistration/verify-mbedtls.c [new file with mode: 0644]
mDNSCore/CryptoAlg.c
mDNSCore/DNSCommon.c
mDNSCore/DNSCommon.h
mDNSCore/DNSDigest.c
mDNSCore/anonymous.c [deleted file]
mDNSCore/anonymous.h [deleted file]
mDNSCore/dnsproxy.c
mDNSCore/dnssec.c
mDNSCore/dnssec.h
mDNSCore/mDNS.c
mDNSCore/mDNSDebug.h
mDNSCore/mDNSEmbeddedAPI.h
mDNSCore/nsec.c
mDNSCore/nsec3.c
mDNSCore/uDNS.c
mDNSCore/uDNS.h
mDNSMacOSX/ApplePlatformFeatures.h [new file with mode: 0644]
mDNSMacOSX/BATS/mDNSResponder.plist [deleted file]
mDNSMacOSX/BLE.c
mDNSMacOSX/Bonjour Safari Extension/Base.lproj/SafariExtensionViewController.xib [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/BonjourSafariExtension.entitlements [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/CNServiceBrowserView.h [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/CNServiceBrowserView.m [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/Info.plist [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/Localizable.strings [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/SafariExtensionHandler.h [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/SafariExtensionHandler.m [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/SafariExtensionViewController.h [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/SafariExtensionViewController.m [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/ToolbarItemIcon.png [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Extension/script.js [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/AppDelegate.h [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/AppDelegate.m [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/Assets.xcassets/AppIcon.appiconset/Contents.json [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/Base.lproj/Main.storyboard [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/BonjourSafariMenu.entitlements [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/Info.plist [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/ViewController.h [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/ViewController.m [new file with mode: 0644]
mDNSMacOSX/Bonjour Safari Menu/main.m [new file with mode: 0644]
mDNSMacOSX/BonjourTop/source/BonjourTop.cpp
mDNSMacOSX/BonjourTop/source/BonjourTop.h
mDNSMacOSX/BonjourTop/source/CollectBy.cpp
mDNSMacOSX/BonjourTop/source/DNSFrame.cpp
mDNSMacOSX/BonjourTop/source/bjstring.cpp
mDNSMacOSX/CryptoSupport.c
mDNSMacOSX/D2D.c
mDNSMacOSX/D2D.h
mDNSMacOSX/DNS64.c
mDNSMacOSX/DNSProxySupport.c
mDNSMacOSX/DNSSECSupport.c
mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.h
mDNSMacOSX/DomainBrowser/Shared/_CNDomainBrowser.m
mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.h
mDNSMacOSX/DomainBrowser/macOS/CNDomainBrowserView.m
mDNSMacOSX/LegacyNATTraversal.c
mDNSMacOSX/LoggingProfiles/liblog_mdnsresponder.m [new file with mode: 0644]
mDNSMacOSX/Metrics.h
mDNSMacOSX/Metrics.m
mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/designable.nib [deleted file]
mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib [deleted file]
mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.xib [new file with mode: 0644]
mDNSMacOSX/PreferencePane/ConfigurationRights.h [deleted file]
mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings [deleted file]
mDNSMacOSX/PreferencePane/en.lproj/InfoPlist.strings [new file with mode: 0644]
mDNSMacOSX/Private/dns_services.c
mDNSMacOSX/Private/dns_services.h
mDNSMacOSX/Private/dns_xpc.h [deleted file]
mDNSMacOSX/Private/dnsctl_server.c [deleted file]
mDNSMacOSX/Private/xpc_services.c [deleted file]
mDNSMacOSX/Private/xpc_services.h [deleted file]
mDNSMacOSX/Scripts/bonjour-mcast-diagnose
mDNSMacOSX/SymptomReporter.c
mDNSMacOSX/SymptomReporter.h [new file with mode: 0644]
mDNSMacOSX/Tests/BATS Scripts/bats_test_proxy.sh [new file with mode: 0755]
mDNSMacOSX/Tests/BATS Scripts/bats_test_state_dump.sh [new file with mode: 0644]
mDNSMacOSX/Tests/CNameRecordTest.m [new file with mode: 0644]
mDNSMacOSX/Tests/DNSMessageTest.m [new file with mode: 0644]
mDNSMacOSX/Tests/HelperFunctionTest.m [new file with mode: 0644]
mDNSMacOSX/Tests/Info.plist [new file with mode: 0644]
mDNSMacOSX/Tests/LocalOnlyTimeoutTest.m [new file with mode: 0644]
mDNSMacOSX/Tests/ResourceRecordTest.m [new file with mode: 0644]
mDNSMacOSX/Tests/mDNSCoreReceiveTest.m [new file with mode: 0644]
mDNSMacOSX/Tests/mDNSResponder.plist [new file with mode: 0644]
mDNSMacOSX/com.apple.mDNSResponder.plist
mDNSMacOSX/command_line_client_entitlements/dns-sd-entitlements.plist [new file with mode: 0644]
mDNSMacOSX/daemon.c
mDNSMacOSX/dnsctl-entitlements.plist [deleted file]
mDNSMacOSX/dnssd.c [new file with mode: 0644]
mDNSMacOSX/dnssd_object.h [new file with mode: 0644]
mDNSMacOSX/dnssd_object.m [new file with mode: 0644]
mDNSMacOSX/dnssd_private.h [new file with mode: 0644]
mDNSMacOSX/dnssd_server.c [new file with mode: 0644]
mDNSMacOSX/dnssd_server.h [new file with mode: 0644]
mDNSMacOSX/dnssd_xpc.c [new file with mode: 0644]
mDNSMacOSX/dnssd_xpc.h [new file with mode: 0644]
mDNSMacOSX/dnssdutil-entitlements.plist [deleted file]
mDNSMacOSX/helper-main.c
mDNSMacOSX/helper-stubs.c
mDNSMacOSX/helper.c
mDNSMacOSX/helper.h
mDNSMacOSX/ipsec_strerror.h [deleted file]
mDNSMacOSX/libpfkey.h [deleted file]
mDNSMacOSX/mDNSMacOSX.c
mDNSMacOSX/mDNSMacOSX.h
mDNSMacOSX/mDNSResponder-entitlements.plist
mDNSMacOSX/mDNSResponder.plist [deleted file]
mDNSMacOSX/mDNSResponder.sb
mDNSMacOSX/mDNSResponder.txt [deleted file]
mDNSMacOSX/mDNSResponder.xcodeproj/project.pbxproj
mDNSMacOSX/mDNSResponder.xcodeproj/xcshareddata/xcschemes/mDNSResponder.xcscheme
mDNSMacOSX/mdns.c [new file with mode: 0644]
mDNSMacOSX/mdns_object.h [new file with mode: 0644]
mDNSMacOSX/mdns_object.m [new file with mode: 0644]
mDNSMacOSX/mdns_private.h [new file with mode: 0644]
mDNSMacOSX/pfkey.c [deleted file]
mDNSMacOSX/uDNSPathEvalulation.c
mDNSMacOSX/utilities/system_utilities.c [new file with mode: 0644]
mDNSMacOSX/utilities/system_utilities.h [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_client_dns_proxy.h [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_client_log_utility.h [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_clients.h [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_service_dns_proxy.c [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_service_dns_proxy.h [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_service_log_utility.c [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_service_log_utility.h [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_services.c [new file with mode: 0644]
mDNSMacOSX/xpc_services/xpc_services.h [new file with mode: 0644]
mDNSPosix/Client.c
mDNSPosix/ExampleClientApp.c
mDNSPosix/Identify.c
mDNSPosix/Makefile
mDNSPosix/NetMonitor.c
mDNSPosix/PosixDaemon.c
mDNSPosix/ProxyResponder.c
mDNSPosix/Responder.c
mDNSPosix/mDNSPosix.c
mDNSPosix/mDNSPosix.h
mDNSPosix/mDNSUNP.c
mDNSPosix/mDNSUNP.h
mDNSPosix/posix_utilities.c [new file with mode: 0644]
mDNSPosix/posix_utilities.h [new file with mode: 0644]
mDNSShared/ClientRequests.c [new file with mode: 0644]
mDNSShared/ClientRequests.h [new file with mode: 0644]
mDNSShared/CommonServices.h
mDNSShared/DebugServices.c
mDNSShared/DebugServices.h
mDNSShared/GenLinkedList.c
mDNSShared/PlatformCommon.c
mDNSShared/PlatformCommon.h
mDNSShared/dns_sd.h
mDNSShared/dns_sd_private.h
mDNSShared/dnsextd.c
mDNSShared/dnsextd.h
mDNSShared/dnssd_clientshim.c
mDNSShared/dnssd_clientstub.c
mDNSShared/dnssd_ipc.c
mDNSShared/mDNSDebug.c
mDNSShared/mDNSFeatures.h [new file with mode: 0644]
mDNSShared/uds_daemon.c
mDNSShared/uds_daemon.h
mDNSVxWorks/README.txt [deleted file]
mDNSVxWorks/mDNSVxWorks.c [deleted file]
mDNSVxWorks/mDNSVxWorks.h [deleted file]
mDNSVxWorks/mDNSVxWorksIPv4Only.c [deleted file]
mDNSVxWorks/mDNSVxWorksIPv4Only.h [deleted file]
mDNSWindows/BonjourQuickLooks.sln [deleted file]
mDNSWindows/BonjourQuickLooksInstaller/BonjourQuickLooksInstaller.wixproj [deleted file]
mDNSWindows/BonjourQuickLooksInstaller/Product.wxs [deleted file]
mDNSWindows/ControlPanel/BrowsingPage.cpp [deleted file]
mDNSWindows/ControlPanel/BrowsingPage.h [deleted file]
mDNSWindows/ControlPanel/ConfigDialog.cpp [deleted file]
mDNSWindows/ControlPanel/ConfigDialog.h [deleted file]
mDNSWindows/ControlPanel/ConfigPropertySheet.cpp [deleted file]
mDNSWindows/ControlPanel/ConfigPropertySheet.h [deleted file]
mDNSWindows/ControlPanel/ControlPanel.cpp [deleted file]
mDNSWindows/ControlPanel/ControlPanel.def [deleted file]
mDNSWindows/ControlPanel/ControlPanel.h [deleted file]
mDNSWindows/ControlPanel/ControlPanel.rc [deleted file]
mDNSWindows/ControlPanel/ControlPanel.vcproj [deleted file]
mDNSWindows/ControlPanel/ControlPanel.vcxproj [deleted file]
mDNSWindows/ControlPanel/ControlPanel.vcxproj.filters [deleted file]
mDNSWindows/ControlPanel/ControlPanelDll.rc [deleted file]
mDNSWindows/ControlPanel/ControlPanelExe.cpp [deleted file]
mDNSWindows/ControlPanel/ControlPanelExe.h [deleted file]
mDNSWindows/ControlPanel/ControlPanelExe.rc [deleted file]
mDNSWindows/ControlPanel/ControlPanelExe.vcproj [deleted file]
mDNSWindows/ControlPanel/ControlPanelLocRes.rc [deleted file]
mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj [deleted file]
mDNSWindows/ControlPanel/ControlPanelLocRes.vcxproj [deleted file]
mDNSWindows/ControlPanel/ControlPanelLocRes.vcxproj.filters [deleted file]
mDNSWindows/ControlPanel/ControlPanelRes.rc [deleted file]
mDNSWindows/ControlPanel/ControlPanelRes.vcproj [deleted file]
mDNSWindows/ControlPanel/ControlPanelRes.vcxproj [deleted file]
mDNSWindows/ControlPanel/ControlPanelRes.vcxproj.filters [deleted file]
mDNSWindows/ControlPanel/FourthPage.cpp [deleted file]
mDNSWindows/ControlPanel/FourthPage.h [deleted file]
mDNSWindows/ControlPanel/RegistrationPage.cpp [deleted file]
mDNSWindows/ControlPanel/RegistrationPage.h [deleted file]
mDNSWindows/ControlPanel/SecondPage.cpp [deleted file]
mDNSWindows/ControlPanel/SecondPage.h [deleted file]
mDNSWindows/ControlPanel/ServicesPage.cpp [deleted file]
mDNSWindows/ControlPanel/ServicesPage.h [deleted file]
mDNSWindows/ControlPanel/SharedSecret.cpp [deleted file]
mDNSWindows/ControlPanel/SharedSecret.h [deleted file]
mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest [deleted file]
mDNSWindows/ControlPanel/res/ControlPanel.exe.manifest [deleted file]
mDNSWindows/ControlPanel/res/ControlPanel.manifest [deleted file]
mDNSWindows/ControlPanel/res/ControlPanel.rc2 [deleted file]
mDNSWindows/ControlPanel/res/ControlPanel64.manifest [deleted file]
mDNSWindows/ControlPanel/res/EnergySaver.ico [deleted file]
mDNSWindows/ControlPanel/res/controlpanel.ico [deleted file]
mDNSWindows/ControlPanel/res/failure.ico [deleted file]
mDNSWindows/ControlPanel/res/success.ico [deleted file]
mDNSWindows/ControlPanel/resource.h [deleted file]
mDNSWindows/ControlPanel/stdafx.cpp [deleted file]
mDNSWindows/ControlPanel/stdafx.h [deleted file]
mDNSWindows/DLL.NET/AssemblyInfo.cpp [deleted file]
mDNSWindows/DLL.NET/PString.h [deleted file]
mDNSWindows/DLL.NET/Stdafx.cpp [deleted file]
mDNSWindows/DLL.NET/Stdafx.h [deleted file]
mDNSWindows/DLL.NET/dnssd_NET.cpp [deleted file]
mDNSWindows/DLL.NET/dnssd_NET.h [deleted file]
mDNSWindows/DLL.NET/dnssd_NET.ico [deleted file]
mDNSWindows/DLL.NET/dnssd_NET.rc [deleted file]
mDNSWindows/DLL.NET/dnssd_NET.vcproj [deleted file]
mDNSWindows/DLL.NET/resource.h [deleted file]
mDNSWindows/DLL/dll.aps [deleted file]
mDNSWindows/DLL/dll.rc [deleted file]
mDNSWindows/DLL/dllmain.c [deleted file]
mDNSWindows/DLL/dnssd.def [deleted file]
mDNSWindows/DLL/dnssd.vcproj [deleted file]
mDNSWindows/DLL/dnssd.vcxproj [deleted file]
mDNSWindows/DLL/dnssd.vcxproj.filters [deleted file]
mDNSWindows/DLL/resource.h [deleted file]
mDNSWindows/DLLStub/DLLStub.cpp [deleted file]
mDNSWindows/DLLStub/DLLStub.h [deleted file]
mDNSWindows/DLLStub/DLLStub.vcproj [deleted file]
mDNSWindows/DLLStub/DLLStub.vcxproj [deleted file]
mDNSWindows/DLLStub/DLLStub.vcxproj.filters [deleted file]
mDNSWindows/DLLX/DLLX.cpp [deleted file]
mDNSWindows/DLLX/DLLX.def [deleted file]
mDNSWindows/DLLX/DLLX.idl [deleted file]
mDNSWindows/DLLX/DLLX.rc [deleted file]
mDNSWindows/DLLX/DLLX.rgs [deleted file]
mDNSWindows/DLLX/DLLX.vcproj [deleted file]
mDNSWindows/DLLX/DLLX.vcxproj [deleted file]
mDNSWindows/DLLX/DLLX.vcxproj.filters [deleted file]
mDNSWindows/DLLX/DNSSD.cpp [deleted file]
mDNSWindows/DLLX/DNSSDEventManager.cpp [deleted file]
mDNSWindows/DLLX/DNSSDEventManager.h [deleted file]
mDNSWindows/DLLX/DNSSDEventManager.rgs [deleted file]
mDNSWindows/DLLX/DNSSDRecord.cpp [deleted file]
mDNSWindows/DLLX/DNSSDRecord.h [deleted file]
mDNSWindows/DLLX/DNSSDRecord.rgs [deleted file]
mDNSWindows/DLLX/DNSSDService.cpp [deleted file]
mDNSWindows/DLLX/DNSSDService.h [deleted file]
mDNSWindows/DLLX/DNSSDService.rgs [deleted file]
mDNSWindows/DLLX/StringServices.cpp [deleted file]
mDNSWindows/DLLX/StringServices.h [deleted file]
mDNSWindows/DLLX/TXTRecord.cpp [deleted file]
mDNSWindows/DLLX/TXTRecord.h [deleted file]
mDNSWindows/DLLX/TXTRecord.rgs [deleted file]
mDNSWindows/DLLX/_IDNSSDEvents_CP.h [deleted file]
mDNSWindows/DLLX/dlldatax.c [deleted file]
mDNSWindows/DLLX/dlldatax.h [deleted file]
mDNSWindows/DLLX/resource.h [deleted file]
mDNSWindows/DLLX/stdafx.h [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.sln [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.sln [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.ico [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2 [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Resources/Resource.h [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcc [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcp [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcw [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.ico [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc2 [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/newres.h [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/resource.h [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp [deleted file]
mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h [deleted file]
mDNSWindows/Java/Java.vcproj [deleted file]
mDNSWindows/Java/Java.vcxproj [deleted file]
mDNSWindows/Java/jdns_sd.rc [deleted file]
mDNSWindows/Java/makefile [deleted file]
mDNSWindows/Java/makefile64 [deleted file]
mDNSWindows/NSPTool/NSPTool.aps [deleted file]
mDNSWindows/NSPTool/NSPTool.c [deleted file]
mDNSWindows/NSPTool/NSPTool.rc [deleted file]
mDNSWindows/NSPTool/NSPTool.vcproj [deleted file]
mDNSWindows/NSPTool/NSPTool.vcxproj [deleted file]
mDNSWindows/NSPTool/NSPTool.vcxproj.filters [deleted file]
mDNSWindows/NSPTool/Prefix.h [deleted file]
mDNSWindows/NSPTool/resource.h [deleted file]
mDNSWindows/Poll.c [deleted file]
mDNSWindows/Poll.h [deleted file]
mDNSWindows/PosixCompat.c [deleted file]
mDNSWindows/PosixCompat.h [deleted file]
mDNSWindows/README.txt [deleted file]
mDNSWindows/RegNames.h [deleted file]
mDNSWindows/Secret.c [deleted file]
mDNSWindows/Secret.h [deleted file]
mDNSWindows/SystemService/EventLog.mc [deleted file]
mDNSWindows/SystemService/EventLogMessages.bin [deleted file]
mDNSWindows/SystemService/Firewall.cpp [deleted file]
mDNSWindows/SystemService/Firewall.h [deleted file]
mDNSWindows/SystemService/Prefix.h [deleted file]
mDNSWindows/SystemService/Service.aps [deleted file]
mDNSWindows/SystemService/Service.c [deleted file]
mDNSWindows/SystemService/Service.h [deleted file]
mDNSWindows/SystemService/Service.mcp [deleted file]
mDNSWindows/SystemService/Service.rc [deleted file]
mDNSWindows/SystemService/Service.vcproj [deleted file]
mDNSWindows/SystemService/Service.vcxproj [deleted file]
mDNSWindows/SystemService/Service.vcxproj.filters [deleted file]
mDNSWindows/SystemService/main.c [deleted file]
mDNSWindows/SystemService/res/mDNSResponder.manifest [deleted file]
mDNSWindows/SystemService/res/mDNSResponder64.manifest [deleted file]
mDNSWindows/SystemService/resource.h [deleted file]
mDNSWindows/SystemService/resrc1.h [deleted file]
mDNSWindows/VPCDetect.cpp [deleted file]
mDNSWindows/VPCDetect.h [deleted file]
mDNSWindows/WinServices.cpp [deleted file]
mDNSWindows/WinServices.h [deleted file]
mDNSWindows/WinVersRes.h [deleted file]
mDNSWindows/isocode.h [deleted file]
mDNSWindows/loclibrary.c [deleted file]
mDNSWindows/loclibrary.h [deleted file]
mDNSWindows/mDNSWin32.c [deleted file]
mDNSWindows/mDNSWin32.h [deleted file]
mDNSWindows/mdnsNSP/ReadMe.txt [deleted file]
mDNSWindows/mdnsNSP/mdnsNSP.aps [deleted file]
mDNSWindows/mdnsNSP/mdnsNSP.c [deleted file]
mDNSWindows/mdnsNSP/mdnsNSP.def [deleted file]
mDNSWindows/mdnsNSP/mdnsNSP.rc [deleted file]
mDNSWindows/mdnsNSP/mdnsNSP.vcproj [deleted file]
mDNSWindows/mdnsNSP/mdnsNSP.vcxproj [deleted file]
mDNSWindows/mdnsNSP/mdnsNSP.vcxproj.filters [deleted file]
mDNSWindows/mdnsNSP/resource.h [deleted file]
unittests/CNameRecordTests.c [deleted file]
unittests/CNameRecordTests.h [deleted file]
unittests/DNSMessageTest.c [deleted file]
unittests/DNSMessageTest.h [deleted file]
unittests/DomainNameTest.c [deleted file]
unittests/DomainNameTest.h [deleted file]
unittests/InterfaceTest.c [deleted file]
unittests/InterfaceTest.h [deleted file]
unittests/LocalOnlyTimeoutTests.c [deleted file]
unittests/LocalOnlyTimeoutTests.h [deleted file]
unittests/ResourceRecordTest.c [deleted file]
unittests/ResourceRecordTest.h [deleted file]
unittests/daemon_ut.c
unittests/mDNSCoreReceiveTest.c [deleted file]
unittests/mDNSCoreReceiveTest.h [deleted file]
unittests/main.c [deleted file]
unittests/mdns_macosx_ut.c
unittests/mdns_ut.c
unittests/uds_daemon_ut.c
unittests/unittest.c [deleted file]
unittests/unittest.h
unittests/unittest_common.c
unittests/unittest_common.h

index 119688daad7255f5127ed86810b6a1fd02e4e2d5..a5a43a0ebc645aa51acf2c1e091cb5a3468461f7 100644 (file)
@@ -1,7 +1,10 @@
 mDNSMacOSX/*.xcodeproj/project.xcworkspace
 mDNSMacOSX/*.xcodeproj/xcuserdata
 .svn
+.DS_Store
 build
+objects
 *~.m
 *~.c
 *~.h
+*~
diff --git a/Clients/FirefoxExtension/CDNSSDService.cpp b/Clients/FirefoxExtension/CDNSSDService.cpp
deleted file mode 100755 (executable)
index ae57da9..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "CDNSSDService.h"
-#include "nsThreadUtils.h"
-#include "nsIEventTarget.h"
-#include "private/pprio.h"
-#include <string>
-#include <stdio.h>
-
-
-NS_IMPL_ISUPPORTS2(CDNSSDService, IDNSSDService, nsIRunnable)
-
-CDNSSDService::CDNSSDService()
-:
-       m_master( 1 ),
-       m_threadPool( NULL ),
-       m_mainRef( NULL ),
-       m_subRef( NULL ),
-       m_listener( NULL ),
-       m_fileDesc( NULL ),
-       m_job( NULL )
-{
-       nsresult err;
-
-       if ( DNSServiceCreateConnection( &m_mainRef ) != kDNSServiceErr_NoError )
-       {
-               err = NS_ERROR_FAILURE;
-               goto exit;
-       }
-
-       if ( ( m_fileDesc = PR_ImportTCPSocket( DNSServiceRefSockFD( m_mainRef ) ) ) == NULL )
-       {
-               err = NS_ERROR_FAILURE;
-               goto exit;
-       }
-
-       if ( ( m_threadPool = PR_CreateThreadPool( 1, 1, 8192 ) ) == NULL )
-       {
-               err = NS_ERROR_FAILURE;
-               goto exit;
-       }
-       
-       err = SetupNotifications();
-
-exit:
-
-       if ( err != NS_OK )
-       {
-               Cleanup();
-       }
-}
-
-
-CDNSSDService::CDNSSDService( DNSServiceRef ref, nsISupports * listener )
-:
-       m_master( 0 ),
-       m_threadPool( NULL ),
-       m_mainRef( ref ),
-       m_subRef( ref ),
-       m_listener( listener ),
-       m_fileDesc( NULL ),
-       m_job( NULL )
-{
-}
-
-
-CDNSSDService::~CDNSSDService()
-{
-       Cleanup();
-}
-
-
-void
-CDNSSDService::Cleanup()
-{
-       if ( m_master )
-       {
-               if ( m_job )
-               {
-                       PR_CancelJob( m_job );
-                       m_job = NULL;
-               }
-
-               if ( m_threadPool != NULL )
-               {       
-                       PR_ShutdownThreadPool( m_threadPool );
-                       m_threadPool = NULL;
-               }
-       
-               if ( m_fileDesc != NULL )
-               {
-                       PR_Close( m_fileDesc );
-                       m_fileDesc = NULL;
-               }
-
-               if ( m_mainRef )
-               {
-                       DNSServiceRefDeallocate( m_mainRef );
-                       m_mainRef = NULL;
-               }
-       }
-       else
-       {
-               if ( m_subRef )
-               {
-                       DNSServiceRefDeallocate( m_subRef );
-                       m_subRef = NULL;
-               }
-       }
-}
-
-
-nsresult
-CDNSSDService::SetupNotifications()
-{
-       NS_PRECONDITION( m_threadPool != NULL, "m_threadPool is NULL" );
-       NS_PRECONDITION( m_fileDesc != NULL, "m_fileDesc is NULL" );
-       NS_PRECONDITION( m_job == NULL, "m_job is not NULL" );
-
-       m_iod.socket    = m_fileDesc;
-       m_iod.timeout   = PR_INTERVAL_MAX;
-       m_job                   = PR_QueueJob_Read( m_threadPool, &m_iod, Read, this, PR_FALSE );       
-       return ( m_job ) ? NS_OK : NS_ERROR_FAILURE;
-}
-
-
-/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
-NS_IMETHODIMP
-CDNSSDService::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
-       CDNSSDService   *       service = NULL;
-       DNSServiceErrorType dnsErr      = 0;
-       nsresult                        err             = 0;
-
-       *_retval = NULL;
-       
-       if ( !m_mainRef )
-       {
-               err = NS_ERROR_NOT_AVAILABLE;
-               goto exit;
-       }
-
-       try
-       {
-               service = new CDNSSDService( m_mainRef, listener );
-       }
-       catch ( ... )
-       {
-               service = NULL;
-       }
-       
-       if ( service == NULL )
-       {
-               err = NS_ERROR_FAILURE;
-               goto exit;
-       }
-       
-       dnsErr = DNSServiceBrowse( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceBrowseReply ) BrowseReply, service );
-       
-       if ( dnsErr != kDNSServiceErr_NoError )
-       {
-               err = NS_ERROR_FAILURE;
-               goto exit;
-       }
-       
-       listener->AddRef();
-       service->AddRef();
-       *_retval = service;
-       err = NS_OK;
-       
-exit:
-
-       if ( err && service )
-       {
-               delete service;
-               service = NULL;
-       }
-       
-       return err;
-}
-
-
-/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
-NS_IMETHODIMP
-CDNSSDService::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
-    CDNSSDService      *       service;
-       DNSServiceErrorType dnsErr;
-       nsresult                        err;
-
-       *_retval = NULL;
-       
-       if ( !m_mainRef )
-       {
-               err = NS_ERROR_NOT_AVAILABLE;
-               goto exit;
-       }
-
-       try
-       {
-               service = new CDNSSDService( m_mainRef, listener );
-       }
-       catch ( ... )
-       {
-               service = NULL;
-       }
-       
-       if ( service == NULL )
-       {
-               err = NS_ERROR_FAILURE;
-               goto exit;
-       }
-
-       dnsErr = DNSServiceResolve( &service->m_subRef, kDNSServiceFlagsShareConnection, interfaceIndex, NS_ConvertUTF16toUTF8( name ).get(), NS_ConvertUTF16toUTF8( regtype ).get(), NS_ConvertUTF16toUTF8( domain ).get(), ( DNSServiceResolveReply ) ResolveReply, service );
-       
-       if ( dnsErr != kDNSServiceErr_NoError )
-       {
-               err = NS_ERROR_FAILURE;
-               goto exit;
-       }
-       
-       listener->AddRef();
-       service->AddRef();
-       *_retval = service;
-       err = NS_OK;
-       
-exit:
-       
-       if ( err && service )
-       {
-               delete service;
-               service = NULL;
-       }
-       
-       return err;
-}
-
-
-/* void stop (); */
-NS_IMETHODIMP
-CDNSSDService::Stop()
-{
-    if ( m_subRef )
-       {
-               DNSServiceRefDeallocate( m_subRef );
-               m_subRef = NULL;
-       }
-       
-       return NS_OK;
-}
-
-
-void
-CDNSSDService::Read( void * arg )
-{
-       NS_PRECONDITION( arg != NULL, "arg is NULL" );
-       
-       NS_DispatchToMainThread( ( CDNSSDService* ) arg );
-}
-
-
-NS_IMETHODIMP
-CDNSSDService::Run()
-{
-       nsresult err = NS_OK;
-       
-       NS_PRECONDITION( m_mainRef != NULL, "m_mainRef is NULL" );
-
-       m_job = NULL;
-
-       if ( PR_Available( m_fileDesc ) > 0 )
-       {
-               if ( DNSServiceProcessResult( m_mainRef ) != kDNSServiceErr_NoError )
-               {
-                       err = NS_ERROR_FAILURE;
-               }
-       }
-
-       if ( !err )
-       {
-               err = SetupNotifications();
-       }
-       
-       return err;
-}
-
-
-void DNSSD_API
-CDNSSDService::BrowseReply
-               (
-               DNSServiceRef           sdRef,
-               DNSServiceFlags         flags,
-               uint32_t                        interfaceIndex,
-               DNSServiceErrorType     errorCode,
-               const char              *       serviceName,
-               const char              *       regtype,
-               const char              *       replyDomain,
-               void                    *       context
-               )
-{
-       CDNSSDService * self = ( CDNSSDService* ) context;
-
-       // This should never be NULL, but let's be defensive.
-       
-       if ( self != NULL )
-       {
-               IDNSSDBrowseListener * listener = ( IDNSSDBrowseListener* ) self->m_listener;
-
-               // Same for this
-
-               if ( listener != NULL )
-               {
-                       listener->OnBrowse( self, ( flags & kDNSServiceFlagsAdd ) ? PR_TRUE : PR_FALSE, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( serviceName ), NS_ConvertUTF8toUTF16( regtype ), NS_ConvertUTF8toUTF16( replyDomain ) );
-               }
-       }
-}
-
-
-void DNSSD_API
-CDNSSDService::ResolveReply
-               (
-               DNSServiceRef                   sdRef,
-               DNSServiceFlags                 flags,
-               uint32_t                                interfaceIndex,
-               DNSServiceErrorType             errorCode,
-               const char                      *       fullname,
-               const char                      *       hosttarget,
-               uint16_t                                port,
-               uint16_t                                txtLen,
-               const unsigned char     *       txtRecord,
-               void                            *       context
-               )
-{
-       CDNSSDService * self = ( CDNSSDService* ) context;
-       
-       // This should never be NULL, but let's be defensive.
-       
-       if ( self != NULL )
-       {
-               IDNSSDResolveListener * listener = ( IDNSSDResolveListener* ) self->m_listener;
-               
-               // Same for this
-
-               if ( listener != NULL )
-               {
-                       std::string             path = "";
-                       const void      *       value = NULL;
-                       uint8_t                 valueLen = 0;
-
-                       value = TXTRecordGetValuePtr( txtLen, txtRecord, "path", &valueLen );
-                       
-                       if ( value && valueLen )
-                       {
-                               char * temp;
-                               
-                               temp = new char[ valueLen + 2 ];
-                               
-                               if ( temp )
-                               {
-                                       char * dst = temp;
-
-                                       memset( temp, 0, valueLen + 2 );
-
-                                       if ( ( ( char* ) value )[ 0 ] != '/' )
-                                       {
-                                               *dst++ = '/';
-                                       }
-
-                                       memcpy( dst, value, valueLen );
-                                       path = temp;
-                                       delete [] temp;
-                               }
-                       }
-
-                       listener->OnResolve( self, interfaceIndex, errorCode, NS_ConvertUTF8toUTF16( fullname ), NS_ConvertUTF8toUTF16( hosttarget ) , ntohs( port ), NS_ConvertUTF8toUTF16( path.c_str() ) );
-               }
-       }
-}
-
diff --git a/Clients/FirefoxExtension/CDNSSDService.h b/Clients/FirefoxExtension/CDNSSDService.h
deleted file mode 100755 (executable)
index 33eaa71..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#ifndef _CDNSSDSERVICE_H
-#define _CDNSSDSERVICE_H
-
-#include "IDNSSDService.h"
-#include "nsCOMPtr.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIThread.h"
-#include "nsIRunnable.h"
-#include "prtpool.h"
-#include <dns_sd.h>
-#include <stdio.h>
-#include <string>
-
-
-#define CDNSSDSERVICE_CONTRACTID "@apple.com/DNSSDService;1"
-#define CDNSSDSERVICE_CLASSNAME "CDNSSDService"
-#define CDNSSDSERVICE_CID { 0x944ED267, 0x465A, 0x4989, { 0x82, 0x72, 0x7E, 0xE9, 0x28, 0x6C, 0x99, 0xA5 } }
-
-
-/* Header file */
-class CDNSSDService : public IDNSSDService, nsIRunnable
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDSERVICE
-NS_DECL_NSIRUNNABLE
-
-CDNSSDService();
-CDNSSDService( DNSServiceRef mainRef, nsISupports * listener );
-
-virtual ~CDNSSDService();
-
-private:
-
-static void DNSSD_API
-BrowseReply
-(
-    DNSServiceRef sdRef,
-    DNSServiceFlags flags,
-    uint32_t interfaceIndex,
-    DNSServiceErrorType errorCode,
-    const char      *   serviceName,
-    const char      *   regtype,
-    const char      *   replyDomain,
-    void            *   context
-);
-
-static void DNSSD_API
-ResolveReply
-(
-    DNSServiceRef sdRef,
-    DNSServiceFlags flags,
-    uint32_t interfaceIndex,
-    DNSServiceErrorType errorCode,
-    const char          *   fullname,
-    const char          *   hosttarget,
-    uint16_t port,
-    uint16_t txtLen,
-    const unsigned char *   txtRecord,
-    void                *   context
-);
-
-static void
-Read
-(
-    void * arg
-);
-
-nsresult
-SetupNotifications();
-
-void
-Cleanup();
-
-char m_master;
-PRThreadPool    *   m_threadPool;
-DNSServiceRef m_mainRef;
-DNSServiceRef m_subRef;
-nsISupports     *   m_listener;
-PRFileDesc      *   m_fileDesc;
-PRJobIoDesc m_iod;
-PRJob           *   m_job;
-};
-
-
-#endif
diff --git a/Clients/FirefoxExtension/CDNSSDServiceModule.cpp b/Clients/FirefoxExtension/CDNSSDServiceModule.cpp
deleted file mode 100755 (executable)
index 3833c5a..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "nsIGenericFactory.h"
-#include "CDNSSDService.h"
-
-NS_COM_GLUE nsresult
-NS_NewGenericModule2(nsModuleInfo const *info, nsIModule* *result);
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(CDNSSDService)
-
-static nsModuleComponentInfo components[] =
-{
-    {
-       CDNSSDSERVICE_CLASSNAME, 
-       CDNSSDSERVICE_CID,
-       CDNSSDSERVICE_CONTRACTID,
-       CDNSSDServiceConstructor,
-    }
-};
-
-NS_IMPL_NSGETMODULE("CDNSSDServiceModule", components) 
-
diff --git a/Clients/FirefoxExtension/DNSSDService.sln b/Clients/FirefoxExtension/DNSSDService.sln
deleted file mode 100755 (executable)
index 68534f4..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-\r
-Microsoft Visual Studio Solution File, Format Version 9.00\r
-# Visual Studio 2005\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DNSSDService", "DNSSDService.vcproj", "{7826EA27-D4CC-4FAA-AD23-DF813823227B}"\r
-EndProject\r
-Global\r
-       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
-               Debug|Win32 = Debug|Win32\r
-               Release|Win32 = Release|Win32\r
-       EndGlobalSection\r
-       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
-               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Debug|Win32.Build.0 = Debug|Win32\r
-               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.ActiveCfg = Release|Win32\r
-               {7826EA27-D4CC-4FAA-AD23-DF813823227B}.Release|Win32.Build.0 = Release|Win32\r
-       EndGlobalSection\r
-       GlobalSection(SolutionProperties) = preSolution\r
-               HideSolutionNode = FALSE\r
-       EndGlobalSection\r
-EndGlobal\r
diff --git a/Clients/FirefoxExtension/FirefoxExtension.rc b/Clients/FirefoxExtension/FirefoxExtension.rc
deleted file mode 100644 (file)
index 998e5e9..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "WinVersRes.h"
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "#include ""WinVersRes.h""\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", MASTER_COMPANY_NAME
-            VALUE "FileDescription", "Firefox Extension Library"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "DNSSDService.dll"
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
-            VALUE "OriginalFilename", "DNSSDService.dll"
-            VALUE "ProductName", MASTER_PROD_NAME
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/Clients/FirefoxExtension/FirefoxExtension.vcproj b/Clients/FirefoxExtension/FirefoxExtension.vcproj
deleted file mode 100755 (executable)
index 352fdd6..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="FirefoxExtension"\r
-       ProjectGUID="{7826EA27-D4CC-4FAA-AD23-DF813823227B}"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"\r
-                       UseOfMFC="0"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"\r
-                               HeaderFileName=""\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="1"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\nspr&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\string&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\pref&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\sdk\include&quot;"\r
-                               PreprocessorDefinitions="NDEBUG;WIN32;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"\r
-                               StringPooling="true"\r
-                               RuntimeLibrary="0"\r
-                               EnableFunctionLevelLinking="true"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="3"\r
-                               SuppressStartupBanner="true"\r
-                               ForcedIncludeFiles=""\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../../mDNSWindows"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
-                               OutputFile="$(OutDir)\DNSSDService.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               AdditionalLibraryDirectories=""\r
-                               ProgramDatabaseFile=".\$(OutDir)/DNSSDService.pdb"\r
-                               ImportLibrary=".\$(OutDir)/DNSSDService.lib"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                               SuppressStartupBanner="true"\r
-                               OutputFile=".\$(OutDir)\DNSSDService.bsc"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="xcopy /I/Y $(PlatformName)\$(ConfigurationName)\DNSSDService.dll extension\platform\WINNT\components&#x0D;&#x0A;if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension&quot;                      mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension&quot;&#x0D;&#x0A;xcopy /E/I/Y &quot;extension&quot;                                 &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\FirefoxExtension&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC60.vsprops"\r
-                       UseOfMFC="0"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName=".\$(OutDir)\DNSSDService.tlb"\r
-                               HeaderFileName=""\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\nspr&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\string&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\include\pref&quot;;&quot;$(SRCROOT)\AppleInternal\XULRunner\sdk\include&quot;"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32"\r
-                               MinimalRebuild="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="3"\r
-                               SuppressStartupBanner="true"\r
-                               DebugInformationFormat="3"\r
-                               ForcedIncludeFiles=""\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../../mDNSWindows"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib $(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
-                               OutputFile="$(OutDir)\DNSSDService.dll"\r
-                               LinkIncremental="2"\r
-                               SuppressStartupBanner="true"\r
-                               AdditionalLibraryDirectories=""\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile=".\$(OutDir)\DNSSDService.pdb"\r
-                               ImportLibrary=".\$(OutDir)/DNSSDService.lib"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                               SuppressStartupBanner="true"\r
-                               OutputFile=".\$(OutDir)\DNSSDService.bsc"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="xcopy /I/Y $(PlatformName)\$(ConfigurationName)\DNSSDService.dll extension\platform\WINNT\components"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\CDNSSDService.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\CDNSSDServiceModule.cpp"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\CDNSSDService.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\IDNSSDService.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="IDL"\r
-                       Filter="idl"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\IDNSSDService.idl"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCustomBuildTool"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCustomBuildTool"\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\FirefoxExtension.rc"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/Clients/FirefoxExtension/FirefoxExtension.vcxproj b/Clients/FirefoxExtension/FirefoxExtension.vcxproj
deleted file mode 100755 (executable)
index 1d02a4e..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{7826EA27-D4CC-4FAA-AD23-DF813823227B}</ProjectGuid>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>false</UseOfMfc>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>false</UseOfMfc>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC60.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">DNSSDService</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">DNSSDService</TargetName>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <TypeLibraryName>.\$(OutDir)DNSSDService.tlb</TypeLibraryName>\r
-      <HeaderFileName>\r
-      </HeaderFileName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom;$(SRCROOT)\AppleInternal\XULRunner\include\nspr;$(SRCROOT)\AppleInternal\XULRunner\include\string;$(SRCROOT)\AppleInternal\XULRunner\include\pref;$(SRCROOT)\AppleInternal\XULRunner\sdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>NDEBUG;WIN32;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <FunctionLevelLinking>true</FunctionLevelLinking>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ObjectFileName>$(IntDir)</ObjectFileName>\r
-      <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <ForcedIncludeFiles>%(ForcedIncludeFiles)</ForcedIncludeFiles>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>../../mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib;ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)DNSSDService.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
-      <ProgramDatabaseFile>.\$(OutDir)DNSSDService.pdb</ProgramDatabaseFile>\r
-      <ImportLibrary>.\$(OutDir)DNSSDService.lib</ImportLibrary>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-    <Bscmake>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <OutputFile>.\$(OutDir)DNSSDService.bsc</OutputFile>\r
-    </Bscmake>\r
-    <PostBuildEvent>\r
-      <Command>xcopy /I/Y $(Platform)\$(Configuration)\DNSSDService.dll extension\platform\WINNT\components\r
-if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\FirefoxExtension"                      mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\FirefoxExtension"\r
-xcopy /E/I/Y "extension"                                 "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\FirefoxExtension"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <TypeLibraryName>.\$(OutDir)DNSSDService.tlb</TypeLibraryName>\r
-      <HeaderFileName>\r
-      </HeaderFileName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;$(SRCROOT)\AppleInternal\XULRunner\include\xpcom;$(SRCROOT)\AppleInternal\XULRunner\include\nspr;$(SRCROOT)\AppleInternal\XULRunner\include\string;$(SRCROOT)\AppleInternal\XULRunner\include\pref;$(SRCROOT)\AppleInternal\XULRunner\sdk\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DNSSDSERVICE_EXPORTS;XP_WIN;XP_WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ObjectFileName>$(IntDir)</ObjectFileName>\r
-      <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <ForcedIncludeFiles>%(ForcedIncludeFiles)</ForcedIncludeFiles>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>../../mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>$(SRCROOT)\AppleInternal\XULRunner\lib\nspr4.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcom.lib;$(SRCROOT)\AppleInternal\XULRunner\lib\xpcomglue_s.lib;ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)DNSSDService.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>.\$(OutDir)DNSSDService.pdb</ProgramDatabaseFile>\r
-      <ImportLibrary>.\$(OutDir)DNSSDService.lib</ImportLibrary>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-    <Bscmake>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <OutputFile>.\$(OutDir)DNSSDService.bsc</OutputFile>\r
-    </Bscmake>\r
-    <PostBuildEvent>\r
-      <Command>xcopy /I/Y $(Platform)\$(Configuration)\DNSSDService.dll extension\platform\WINNT\components</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="CDNSSDService.cpp" />\r
-    <ClCompile Include="CDNSSDServiceModule.cpp" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="CDNSSDService.h" />\r
-    <ClInclude Include="IDNSSDService.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <CustomBuildStep Include="IDNSSDService.idl" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="FirefoxExtension.rc" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="..\..\mDNSWindows\DLLStub\DLLStub.vcxproj">\r
-      <Project>{3a2b6325-3053-4236-84bd-aa9be2e323e5}</Project>\r
-      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/Clients/FirefoxExtension/FirefoxExtension.vcxproj.filters b/Clients/FirefoxExtension/FirefoxExtension.vcxproj.filters
deleted file mode 100755 (executable)
index 02c1c55..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{89e57cc2-d6b1-4e68-ad57-71223df12d28}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{4d103fe8-9737-47c7-9190-6f7b5666ecf5}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl</Extensions>\r
-    </Filter>\r
-    <Filter Include="IDL">\r
-      <UniqueIdentifier>{4dae44a8-3da8-43c0-a749-2d1e0610c66f}</UniqueIdentifier>\r
-      <Extensions>idl</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{ac7dbdd1-2fe3-416d-9cab-2d663c05f252}</UniqueIdentifier>\r
-      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="CDNSSDService.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="CDNSSDServiceModule.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="CDNSSDService.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="IDNSSDService.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="FirefoxExtension.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <CustomBuildStep Include="IDNSSDService.idl">\r
-      <Filter>IDL</Filter>\r
-    </CustomBuildStep>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/Clients/FirefoxExtension/IDNSSDService.h b/Clients/FirefoxExtension/IDNSSDService.h
deleted file mode 100755 (executable)
index e4784d4..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * DO NOT EDIT.  THIS FILE IS GENERATED FROM IDNSSDService.idl
- */
-
-#ifndef __gen_IDNSSDService_h__
-#define __gen_IDNSSDService_h__
-
-
-#ifndef __gen_nsISupports_h__
-#include "nsISupports.h"
-#endif
-
-/* For IDL files that don't want to include root IDL files. */
-#ifndef NS_NO_VTABLE
-#define NS_NO_VTABLE
-#endif
-class IDNSSDService; /* forward declaration */
-
-
-/* starting interface:    IDNSSDBrowseListener */
-#define IDNSSDBROWSELISTENER_IID_STR "27346495-a1ed-458a-a5bc-587df9a26b4f"
-
-#define IDNSSDBROWSELISTENER_IID \
-    {0x27346495, 0xa1ed, 0x458a, \
-     { 0xa5, 0xbc, 0x58, 0x7d, 0xf9, 0xa2, 0x6b, 0x4f }}
-
-class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDBrowseListener : public nsISupports {
-public:
-
-NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDBROWSELISTENER_IID)
-
-/* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */
-NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain) = 0;
-
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDBrowseListener, IDNSSDBROWSELISTENER_IID)
-
-/* Use this macro when declaring classes that implement this interface. */
-#define NS_DECL_IDNSSDBROWSELISTENER \
-    NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString &serviceName, const nsAString &regtype, const nsAString &domain);
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object. */
-#define NS_FORWARD_IDNSSDBROWSELISTENER(_to) \
-    NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString &serviceName, const nsAString &regtype, const nsAString &domain) { return _to OnBrowse(service, add, interfaceIndex, error, serviceName, regtype, domain); }
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
-#define NS_FORWARD_SAFE_IDNSSDBROWSELISTENER(_to) \
-    NS_SCRIPTABLE NS_IMETHOD OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString &serviceName, const nsAString &regtype, const nsAString &domain) { return !_to ? NS_ERROR_NULL_POINTER : _to->OnBrowse(service, add, interfaceIndex, error, serviceName, regtype, domain); }
-
-#if 0
-/* Use the code below as a template for the implementation class for this interface. */
-
-/* Header file */
-class _MYCLASS_ : public IDNSSDBrowseListener
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDBROWSELISTENER
-
-_MYCLASS_();
-
-private:
-~_MYCLASS_();
-
-protected:
-/* additional members */
-};
-
-/* Implementation file */
-NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDBrowseListener)
-
-_MYCLASS_::_MYCLASS_()
-{
-    /* member initializers and constructor code */
-}
-
-_MYCLASS_::~_MYCLASS_()
-{
-    /* destructor code */
-}
-
-/* void onBrowse (in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain); */
-NS_IMETHODIMP _MYCLASS_::OnBrowse(IDNSSDService *service, PRBool add, PRInt32 interfaceIndex, PRInt32 error, const nsAString & serviceName, const nsAString & regtype, const nsAString & domain)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* End of implementation class template. */
-#endif
-
-
-/* starting interface:    IDNSSDResolveListener */
-#define IDNSSDRESOLVELISTENER_IID_STR "6620e18f-47f3-47c6-941f-126a5fd4fcf7"
-
-#define IDNSSDRESOLVELISTENER_IID \
-    {0x6620e18f, 0x47f3, 0x47c6, \
-     { 0x94, 0x1f, 0x12, 0x6a, 0x5f, 0xd4, 0xfc, 0xf7 }}
-
-class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDResolveListener : public nsISupports {
-public:
-
-NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDRESOLVELISTENER_IID)
-
-/* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */
-NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path) = 0;
-
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDResolveListener, IDNSSDRESOLVELISTENER_IID)
-
-/* Use this macro when declaring classes that implement this interface. */
-#define NS_DECL_IDNSSDRESOLVELISTENER \
-    NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString &fullname, const nsAString &host, PRInt16 port, const nsAString &path);
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object. */
-#define NS_FORWARD_IDNSSDRESOLVELISTENER(_to) \
-    NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString &fullname, const nsAString &host, PRInt16 port, const nsAString &path) { return _to OnResolve(service, interfaceIndex, error, fullname, host, port, path); }
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
-#define NS_FORWARD_SAFE_IDNSSDRESOLVELISTENER(_to) \
-    NS_SCRIPTABLE NS_IMETHOD OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString &fullname, const nsAString &host, PRInt16 port, const nsAString &path) { return !_to ? NS_ERROR_NULL_POINTER : _to->OnResolve(service, interfaceIndex, error, fullname, host, port, path); }
-
-#if 0
-/* Use the code below as a template for the implementation class for this interface. */
-
-/* Header file */
-class _MYCLASS_ : public IDNSSDResolveListener
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDRESOLVELISTENER
-
-_MYCLASS_();
-
-private:
-~_MYCLASS_();
-
-protected:
-/* additional members */
-};
-
-/* Implementation file */
-NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDResolveListener)
-
-_MYCLASS_::_MYCLASS_()
-{
-    /* member initializers and constructor code */
-}
-
-_MYCLASS_::~_MYCLASS_()
-{
-    /* destructor code */
-}
-
-/* void onResolve (in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path); */
-NS_IMETHODIMP _MYCLASS_::OnResolve(IDNSSDService *service, PRInt32 interfaceIndex, PRInt32 error, const nsAString & fullname, const nsAString & host, PRInt16 port, const nsAString & path)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* End of implementation class template. */
-#endif
-
-
-/* starting interface:    IDNSSDService */
-#define IDNSSDSERVICE_IID_STR "3a3539ff-f8d8-40b4-8d02-5ea73c51fa12"
-
-#define IDNSSDSERVICE_IID \
-    {0x3a3539ff, 0xf8d8, 0x40b4, \
-     { 0x8d, 0x02, 0x5e, 0xa7, 0x3c, 0x51, 0xfa, 0x12 }}
-
-class NS_NO_VTABLE NS_SCRIPTABLE IDNSSDService : public nsISupports {
-public:
-
-NS_DECLARE_STATIC_IID_ACCESSOR(IDNSSDSERVICE_IID)
-
-/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
-NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;
-
-/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
-NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) = 0;
-
-/* void stop (); */
-NS_SCRIPTABLE NS_IMETHOD Stop(void) = 0;
-
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(IDNSSDService, IDNSSDSERVICE_IID)
-
-/* Use this macro when declaring classes that implement this interface. */
-#define NS_DECL_IDNSSDSERVICE \
-    NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString &regtype, const nsAString &domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM); \
-    NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString &name, const nsAString &regtype, const nsAString &domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM); \
-    NS_SCRIPTABLE NS_IMETHOD Stop(void);
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object. */
-#define NS_FORWARD_IDNSSDSERVICE(_to) \
-    NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString &regtype, const nsAString &domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return _to Browse(interfaceIndex, regtype, domain, listener, _retval); } \
-    NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString &name, const nsAString &regtype, const nsAString &domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return _to Resolve(interfaceIndex, name, regtype, domain, listener, _retval); } \
-    NS_SCRIPTABLE NS_IMETHOD Stop(void) { return _to Stop(); }
-
-/* Use this macro to declare functions that forward the behavior of this interface to another object in a safe way. */
-#define NS_FORWARD_SAFE_IDNSSDSERVICE(_to) \
-    NS_SCRIPTABLE NS_IMETHOD Browse(PRInt32 interfaceIndex, const nsAString &regtype, const nsAString &domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to->Browse(interfaceIndex, regtype, domain, listener, _retval); } \
-    NS_SCRIPTABLE NS_IMETHOD Resolve(PRInt32 interfaceIndex, const nsAString &name, const nsAString &regtype, const nsAString &domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM) { return !_to ? NS_ERROR_NULL_POINTER : _to->Resolve(interfaceIndex, name, regtype, domain, listener, _retval); } \
-    NS_SCRIPTABLE NS_IMETHOD Stop(void) { return !_to ? NS_ERROR_NULL_POINTER : _to->Stop(); }
-
-#if 0
-/* Use the code below as a template for the implementation class for this interface. */
-
-/* Header file */
-class _MYCLASS_ : public IDNSSDService
-{
-public:
-NS_DECL_ISUPPORTS
-NS_DECL_IDNSSDSERVICE
-
-_MYCLASS_();
-
-private:
-~_MYCLASS_();
-
-protected:
-/* additional members */
-};
-
-/* Implementation file */
-NS_IMPL_ISUPPORTS1(_MYCLASS_, IDNSSDService)
-
-_MYCLASS_::_MYCLASS_()
-{
-    /* member initializers and constructor code */
-}
-
-_MYCLASS_::~_MYCLASS_()
-{
-    /* destructor code */
-}
-
-/* IDNSSDService browse (in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener); */
-NS_IMETHODIMP _MYCLASS_::Browse(PRInt32 interfaceIndex, const nsAString & regtype, const nsAString & domain, IDNSSDBrowseListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* IDNSSDService resolve (in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener); */
-NS_IMETHODIMP _MYCLASS_::Resolve(PRInt32 interfaceIndex, const nsAString & name, const nsAString & regtype, const nsAString & domain, IDNSSDResolveListener *listener, IDNSSDService **_retval NS_OUTPARAM)
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* void stop (); */
-NS_IMETHODIMP _MYCLASS_::Stop()
-{
-    return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-/* End of implementation class template. */
-#endif
-
-
-#endif /* __gen_IDNSSDService_h__ */
diff --git a/Clients/FirefoxExtension/IDNSSDService.idl b/Clients/FirefoxExtension/IDNSSDService.idl
deleted file mode 100755 (executable)
index d0f62c8..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-\r
- *\r
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- * \r
- *     http://www.apache.org/licenses/LICENSE-2.0\r
- * \r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-\r
-#include "nsISupports.idl"\r
-\r
-interface IDNSSDService;\r
-\r
-\r
-[scriptable, function, uuid(27346495-A1ED-458A-A5BC-587DF9A26B4F)]\r
-interface IDNSSDBrowseListener : nsISupports\r
-{\r
-       void\r
-       onBrowse( in IDNSSDService service, in boolean add, in long interfaceIndex, in long error, in AString serviceName, in AString regtype, in AString domain );\r
-};\r
-\r
-\r
-[scriptable, function, uuid(6620E18F-47F3-47C6-941F-126A5FD4FCF7)]\r
-interface IDNSSDResolveListener : nsISupports\r
-{\r
-       void\r
-       onResolve( in IDNSSDService service, in long interfaceIndex, in long error, in AString fullname, in AString host, in short port, in AString path );\r
-};\r
-\r
-\r
-[scriptable, uuid(3A3539FF-F8D8-40B4-8D02-5EA73C51FA12)]\r
-interface IDNSSDService : nsISupports\r
-{\r
-       IDNSSDService\r
-       browse( in long interfaceIndex, in AString regtype, in AString domain, in IDNSSDBrowseListener listener );\r
-\r
-       IDNSSDService\r
-       resolve( in long interfaceIndex, in AString name, in AString regtype, in AString domain, in IDNSSDResolveListener listener );\r
-\r
-       void\r
-       stop();\r
-};\r
diff --git a/Clients/FirefoxExtension/extension/chrome.manifest b/Clients/FirefoxExtension/extension/chrome.manifest
deleted file mode 100755 (executable)
index f1daf86..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-content        bonjour4firefox content/
-locale bonjour4firefox en-US   locale/en-US/
-skin   bonjour4firefox classic/1.0     skin/ 
-skin   bonjour4firefox classic/1.0 skin-darwin/ os=darwin
-overlay        chrome://browser/content/browser.xul    chrome://bonjour4firefox/content/browserOverlay.xul
-style  chrome://global/content/customizeToolbar.xul    chrome://bonjour4firefox/skin/overlay.css
diff --git a/Clients/FirefoxExtension/extension/components/IDNSSDService.xpt b/Clients/FirefoxExtension/extension/components/IDNSSDService.xpt
deleted file mode 100755 (executable)
index bfda3e5..0000000
Binary files a/Clients/FirefoxExtension/extension/components/IDNSSDService.xpt and /dev/null differ
diff --git a/Clients/FirefoxExtension/extension/content/_internal_bonjour4firefox.png b/Clients/FirefoxExtension/extension/content/_internal_bonjour4firefox.png
deleted file mode 100755 (executable)
index baf8b21..0000000
Binary files a/Clients/FirefoxExtension/extension/content/_internal_bonjour4firefox.png and /dev/null differ
diff --git a/Clients/FirefoxExtension/extension/content/_internal_listImage.png b/Clients/FirefoxExtension/extension/content/_internal_listImage.png
deleted file mode 100755 (executable)
index 278efe3..0000000
Binary files a/Clients/FirefoxExtension/extension/content/_internal_listImage.png and /dev/null differ
diff --git a/Clients/FirefoxExtension/extension/content/bonjour4firefox.css b/Clients/FirefoxExtension/extension/content/bonjour4firefox.css
deleted file mode 100755 (executable)
index 2e7eb2c..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-tree.sidebar-placesTree treechildren::-moz-tree-row(selected)
-{
-       background-color: #6f81a9;
-       background-image: url("chrome://browser/skin/places/selected-gradient.png");
-       background-repeat: repeat-x;
-       background-position: bottom left;
-       border-top: 1px solid #979797;
-}
-
-
-tree.sidebar-placesTree treechildren::-moz-tree-separator
-{
-       border-top: 1px solid #505d6d;
-       margin: 0 10px;
-}
-
diff --git a/Clients/FirefoxExtension/extension/content/bonjour4firefox.xul b/Clients/FirefoxExtension/extension/content/bonjour4firefox.xul
deleted file mode 100755 (executable)
index 2be0c69..0000000
+++ /dev/null
@@ -1,222 +0,0 @@
-<?xml version="1.0"?>
-<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
-<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
-<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
-<?xml-stylesheet href="browseList.css"?>
-<!DOCTYPE page SYSTEM "chrome://bonjour4firefox/locale/bonjour4firefox.dtd">
-       <page
-               orient="vertical"
-        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
-        style="background-color: transparent !important; -moz-appearance: none !important;"
-               onload="BonjourBrowser.init()"
-               onunload="BonjourBrowser.cleanup()">
-               
-
-       <menupopup id="targetmenu">
-        <menuitem label="&bonjour4firefoxSidebarOpenDefault.label;" value="current"/>
-        <menuitem label="&bonjour4firefoxSidebarOpenTab.label;" value="tab"/>
-        <menuitem label="&bonjour4firefoxSidebarOpenWindow.label;" value="window"/>
-       </menupopup>
-
-       <tree id="treeBrowseList" flex="1" class="sidebar-placesTree" hidecolumnpicker="true">
-               <treecols hide="true">
-                       <treecol id="title" flex="1" primary="true" hideheader="true"/>
-        </treecols>
-
-        <treechildren class="sidebar-placesTreechildren" context="targetmenu" flex="1" id="treeChildrenBrowseList">
-                       <treeitem>
-                               <treerow>
-                                       <treecell src="chrome://bonjour4firefox/content/_internal_bonjour4firefox.png" label="About Bonjour"/>
-                               </treerow>
-                       </treeitem>
-               </treechildren>
-       </tree>
-
-       <script><![CDATA[
-
-               var BonjourBrowser =
-               {
-                       Service: null,
-                       Browse: null,
-                       BrowseListener: null,
-                       Resolve: null,
-                       ResolveListener: null,
-
-                       init: function()
-                       {
-                               document.getElementById("treeChildrenBrowseList").addEventListener( "click", this.listListener, false );
-
-                               try
-                               {
-                               netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
-                                       const cid = "@apple.com/DNSSDService;1";
-                               Service = Components.classes[cid].createInstance();
-                                       Service = Service.QueryInterface(Components.interfaces.IDNSSDService);
-                               }
-                               catch (err)
-                               {
-                               alert(err);
-                               return;
-                       }
-
-                               BrowseListener = this.browseListener;
-                               ResolveListener = this.resolveListener;
-
-                               try
-                               {
-                                       Browse = Service.browse(0, "_http._tcp", "", BrowseListener );
-                               }
-                               catch ( err )
-                               {
-                                       alert( err );
-                                       return;
-                               }
-                       },
-
-                       cleanup: function()
-                       {
-                               if ( Browse != null )
-                               {
-                                       Browse.stop();
-                                       Browse = null;
-                               }
-                       },
-
-
-                       browseListener: function( service, add, interfaceIndex, error, serviceName, regtype, domain )
-                       {
-                               if ( error == 0 )
-                               {
-                                       // First see if we can look this guy up
-
-                                       var treeView = document.getElementById( 'treeChildrenBrowseList' );
-                                       var treeItem = null;
-
-                                       for ( i = 1; i < treeView.childNodes.length; i++ )
-                                       {
-                                               var ti = treeView.childNodes[ i ];
-                                               var tr = ti.childNodes[ 0 ];
-                                               var tc = tr.childNodes[ 0 ];
-
-                                               if ( tc.getAttribute( 'label' ) == serviceName )
-                                               {
-                                                       treeItem = ti;
-                                                       break;
-                                               }
-                                       }
-       
-                                       if ( add )
-                                       {
-                                               // If we've already seen this guy, then bump up his reference count
-
-                                               if ( treeItem )
-                                               {
-                                                       var refcnt = treeItem.getUserData( 'refcnt' );
-                                                       refcnt++;
-                                               }
-                                               else
-                                               {
-                                                       var newTreeItem = document.createElement('treeitem');
-                                                       var newTreeRow = document.createElement('treerow');
-                                                       newTreeRow.setAttribute( 'properties', 'bonjourRow' );
-                                                       var newTreeCell = document.createElement('treecell');
-                                       newTreeCell.setAttribute( 'label', serviceName );
-                                                       newTreeCell.setAttribute( 'src', 'chrome://bonjour4firefox/content/_internal_bonjour4firefox.png' );
-                               
-                                                       newTreeItem.appendChild( newTreeRow );
-                                                       newTreeRow.appendChild( newTreeCell );
-                                                       newTreeItem.setUserData( 'interfaceIndex', interfaceIndex, null );
-                                       newTreeItem.setUserData( 'serviceName', serviceName, null );
-                                                       newTreeItem.setUserData( 'regtype', regtype, null );
-                                                       newTreeItem.setUserData( 'domain', domain, null );
-                                                       newTreeItem.setUserData( 'refcnt', 1, null );
-
-                                                       // Insert in alphabetical order
-
-                                                       var insertBefore = null;
-
-                                                       for ( i = 1; i < treeView.childNodes.length; i++ )
-                                                       {
-                                                               var ti = treeView.childNodes[ i ];
-                                                               var tr = ti.childNodes[ 0 ];
-                                                               var tc = tr.childNodes[ 0 ];
-               
-                                                               if ( serviceName.toLowerCase() < tc.getAttribute( 'label' ).toLowerCase() )
-                                                               {
-                                                                       insertBefore = ti;
-                                                                       break;
-                                                               }
-                                               }
-       
-                                                       if ( insertBefore != null )
-                                                       {
-                                                               treeView.insertBefore( newTreeItem, insertBefore );
-                                                       }
-                                                       else
-                                                       {
-                                                               treeView.appendChild( newTreeItem );
-                                                       }
-                                               }
-                                       }
-                                       else if ( treeItem )
-                                       {
-                                               var refcnt = treeItem.getUserData( 'refcnt' );
-                                               
-                                               if ( --refcnt == 0 )
-                                               {
-                                                       treeView.removeChild( treeItem );
-                                               }
-                                       }
-                               }
-                               else
-                               {
-                                       alert( 'There was an error browsing for websites: ' + error );
-                               }
-                       },
-
-                       listListener: function( event )
-                       {
-                               var treeBrowseList = document.getElementById( 'treeBrowseList' );
-
-                               if ( treeBrowseList.currentIndex == 0 )
-                               {
-                                       window._content.location="http://www.apple.com/macosx/features/bonjour";
-                               }
-                               else
-                               {
-                                       var item = treeBrowseList.view.getItemAtIndex(treeBrowseList.currentIndex);
-
-                                       var interfaceIndex = item.getUserData("interfaceIndex");
-                                       var serviceName = item.getUserData("serviceName");
-                                       var regtype = item.getUserData("regtype");
-                                       var domain = item.getUserData("domain");
-
-                                       try
-                                       {
-                                               Resolve = Service.resolve( interfaceIndex, serviceName, regtype, domain, ResolveListener );
-                                       }
-                                       catch ( err )
-                                       {
-                                               alert( err );
-                                               return;
-                                       }
-                               }
-                       },
-
-                       resolveListener: function( service, interfaceIndex, error, fullname, host, port, path )
-                       {
-                               if ( error == 0 )
-                               {
-                                       window._content.location='http://' + host + ':' + port + path;
-                               }
-                               else
-                               {
-                                       alert( 'There was an error resolving ' + fullname );
-                               }
-
-                               Resolve.stop();
-                       },
-               };
-
-       ]]></script>
-</page>
diff --git a/Clients/FirefoxExtension/extension/content/browserOverlay.xul b/Clients/FirefoxExtension/extension/content/browserOverlay.xul
deleted file mode 100755 (executable)
index 3b4d668..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet href="chrome://bonjour4firefox/skin/overlay.css" type="text/css"?>
-<!DOCTYPE overlay SYSTEM "chrome://bonjour4firefox/locale/bonjour4firefox.dtd">
-<overlay id="bonjour4firefox-overlay"
-         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
-       <script src="overlay.js"/>
-       <stringbundleset id="stringbundleset">
-       <stringbundle id="bonjour4firefox-strings" src="chrome://bonjour4firefox/locale/bonjour4firefox.properties"/>
-       </stringbundleset>
-
-       <menupopup id="viewSidebarMenu">
-               <menuitem observes="viewBonjour4FirefoxSidebar"/>
-       </menupopup>
-
-       <toolbarpalette id="BrowserToolbarPalette">
-               <toolbarbutton id="bonjour4firefox-toolbar-button"
-               label="&bonjour4firefoxToolbar.label;"
-               tooltiptext="&bonjour4firefoxToolbar.tooltip;"
-               oncommand="toggleSidebar('viewBonjour4FirefoxSidebar');"
-               class="toolbarbutton-1 chromeclass-toolbar-additional"/>
-       </toolbarpalette>
-
-       <broadcasterset id="mainBroadcasterSet">
-               <broadcaster id="viewBonjour4FirefoxSidebar"
-                       autoCheck="false"
-                       label="Bonjour"
-                       type="checkbox" group="sidebar"
-                       sidebarurl="chrome://bonjour4firefox/content/bonjour4firefox.xul"
-                       sidebartitle="&bonjour4firefox.label;"
-                       oncommand="toggleSidebar('viewBonjour4FirefoxSidebar');"/>
-       </broadcasterset>
-</overlay>
diff --git a/Clients/FirefoxExtension/extension/content/overlay.js b/Clients/FirefoxExtension/extension/content/overlay.js
deleted file mode 100755 (executable)
index f989caa..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-var bonjour4firefox = 
-{
-       onLoad: function()
-       {
-       // initialization code
-       this.initialized = true;
-       this.strings = document.getElementById("bonjour4firefox-strings");
-       },
-       onMenuItemCommand: function(e)
-       {
-       var promptService = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].getService(Components.interfaces.nsIPromptService);
-               promptService.alert(window, this.strings.getString("helloMessageTitle"), this.strings.getString("helloMessage"));
-       },
-       onToolbarButtonCommand: function(e)
-       {
-       // just reuse the function above.  you can change this, obviously!
-       bonjour4firefox.onMenuItemCommand(e);
-       }
-};
-
-window.addEventListener("load", function(e) { bonjour4firefox.onLoad(e); }, false);
diff --git a/Clients/FirefoxExtension/extension/defaults/preferences/bonjour4firefox.js b/Clients/FirefoxExtension/extension/defaults/preferences/bonjour4firefox.js
deleted file mode 100755 (executable)
index 2965608..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-// See http://kb.mozillazine.org/Localize_extension_descriptions
-pref("extensions.bonjour4firefox@apple.com.description", "chrome://bonjour4firefox/locale/bonjour4firefox.properties");
diff --git a/Clients/FirefoxExtension/extension/install.rdf b/Clients/FirefoxExtension/extension/install.rdf
deleted file mode 100755 (executable)
index 37c0955..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 
- xmlns:em="http://www.mozilla.org/2004/em-rdf#">
-  <Description about="urn:mozilla:install-manifest">
-    <em:id>bonjour4firefox@apple.com</em:id>
-    <em:name>Bonjour Extension for Firefox</em:name>
-    <em:version>1.0</em:version>
-    <em:creator>Apple Inc.</em:creator>
-    <em:description>Bonjour Browsing Extension for Firefox</em:description>
-    <em:iconURL>chrome://bonjour4firefox/content/_internal_bonjour4firefox.png</em:iconURL>
-    <em:targetApplication>
-      <Description>
-        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!-- firefox -->
-        <em:minVersion>3.5</em:minVersion>
-        <em:maxVersion>3.6.*</em:maxVersion>
-      </Description>
-    </em:targetApplication>
-  </Description>
-</RDF>
diff --git a/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.dtd b/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.dtd
deleted file mode 100755 (executable)
index 2e133f9..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<!ENTITY bonjour4firefox.label "Bonjour">
-<!ENTITY bonjour4firefoxToolbar.label "Bonjour">
-<!ENTITY bonjour4firefoxToolbar.tooltip "Display Bonjour enabled websites">
-<!ENTITY bonjour4firefoxSidebarOpenDefault.label "Open in current window">
-<!ENTITY bonjour4firefoxSidebarOpenTab.label "Open in new tab">
-<!ENTITY bonjour4firefoxSidebarOpenWindow.label "Open in new window">
diff --git a/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.properties b/Clients/FirefoxExtension/extension/locale/en-US/bonjour4firefox.properties
deleted file mode 100755 (executable)
index afed1ab..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-helloMessage=Hello World!
-helloMessageTitle=Hello
-prefMessage=Int Pref Value: %d
-extensions.bonjour4firefox.description=Bonjour Browsing Extension for Firefox
diff --git a/Clients/FirefoxExtension/extension/readme.txt b/Clients/FirefoxExtension/extension/readme.txt
deleted file mode 100755 (executable)
index 71f1edc..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-This extension was generated by the Extension Wizard at
-http://ted.mielczarek.org/code/mozilla/extensionwiz/ .
-This extension is compatible only with Firefox 1.5 and
-above.  Most of the files in this package are based on
-the 'helloworld' extension from the Mozillazine Knowledge Base.
-
-You can build an XPI for installation by running the
-build.sh script located in this folder.  For development
-you should do the following:
-  1. Unzip the entire contents of this package to somewhere,
-              e.g, c:\dev or /home/user/dev
-  2. Put the full path to the folder (e.g. c:\dev\bonjour4firefox on
-     Windows, /home/user/dev/bonjour4firefox on Linux) in a file named
-     bonjour4firefox@apple.com and copy that file to
-     [your profile folder]\extensions\
-  3. Restart Firefox.
-
-For more information, see the Mozillazine Knowledge Base:
-http://kb.mozillazine.org/Getting_started_with_extension_development
-
--Ted Mielczarek <ted.mielczarek@gmail.com>
diff --git a/Clients/FirefoxExtension/extension/skin-darwin/_internal_toobar-button.png b/Clients/FirefoxExtension/extension/skin-darwin/_internal_toobar-button.png
deleted file mode 100644 (file)
index 2bd6c9d..0000000
Binary files a/Clients/FirefoxExtension/extension/skin-darwin/_internal_toobar-button.png and /dev/null differ
diff --git a/Clients/FirefoxExtension/extension/skin-darwin/overlay.css b/Clients/FirefoxExtension/extension/skin-darwin/overlay.css
deleted file mode 100644 (file)
index f5f4a28..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#bonjour4firefox-hello
-{
-  color: red ! important;
-}
-#bonjour4firefox-toolbar-button
-{
-  list-style-image: url("chrome://bonjour4firefox/skin/_internal_toolbar-button.png");
-  -moz-image-region: rect(0px 36px 23px 0px);
-}
-#bonjour4firefox-toolbar-button[disabled="true"]
-{
-  -moz-image-region: rect(23px 36px 46px 0px);
-}
-#bonjour4firefox-toolbar-button:hover:active
-{
-  -moz-image-region: rect(46px 36px 69px 0px);
-}
diff --git a/Clients/FirefoxExtension/extension/skin/_internal_toobar-button.png b/Clients/FirefoxExtension/extension/skin/_internal_toobar-button.png
deleted file mode 100755 (executable)
index d99a0c9..0000000
Binary files a/Clients/FirefoxExtension/extension/skin/_internal_toobar-button.png and /dev/null differ
diff --git a/Clients/FirefoxExtension/extension/skin/overlay.css b/Clients/FirefoxExtension/extension/skin/overlay.css
deleted file mode 100755 (executable)
index b286560..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#bonjour4firefox-hello
-{
-  color: black ! important;
-}
-#bonjour4firefox-toolbar-button
-{
-  list-style-image: url("chrome://bonjour4firefox/skin/_internal_toolbar-button.png");
-  -moz-image-region: rect(0px 24px 24px 0px);
-}
-#bonjour4firefox-toolbar-button:hover
-{
-  -moz-image-region: rect(24px 24px 48px  0px);
-}
-[iconsize="small"] #bonjour4firefox-toolbar-button
-{
-  -moz-image-region: rect( 0px 40px 16px 24px);
-}
-[iconsize="small"] #bonjour4firefox-toolbar-button:hover
-{
-  -moz-image-region: rect(24px 40px 40px 24px);
-}
diff --git a/Clients/FirefoxExtension/readme.txt b/Clients/FirefoxExtension/readme.txt
deleted file mode 100644 (file)
index f898f33..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Building the Bonjour Firefox Extension on Windows
-
-There is a Visual Studio 2005 project file that will build the extension correctly as long as the Visual Studio environment is setup correctly.  This code was built against the 1.9 version of the XULRunner SDK.  The Visual Studio environment should be modified to add the include and lib paths of the XULRunner SDK.  Specifically, the following include paths should be added to VC++ include directories:
-
-…\xulrunner-sdk\include\xpcom
-…\xulrunner-sdk\include\nspr
-…\xulrunner-sdk\include\string
-…\xulrunner-sdk\include\pref
-…\xulrunner-sdk\sdk\include
-
-The following path should be added to VC++ lib directories:
-
-…\xulrunner-sdk\lib
-
-After the code has been built, it can be installed like any other Firefox extension.  Please consult Firefox extension documentation for more information on how to package and install Firefox extensions.
-
diff --git a/Clients/FirefoxExtension/resource.h b/Clients/FirefoxExtension/resource.h
deleted file mode 100644 (file)
index 42710b8..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by FirefoxExtension.rc
-//
-#define IDS_PROJNAME                    100
-#define IDR_WMDMLOGGER                  101
-#define IDS_LOG_SEV_INFO                201
-#define IDS_LOG_SEV_WARN                202
-#define IDS_LOG_SEV_ERROR               203
-#define IDS_LOG_DATETIME                204
-#define IDS_LOG_SRCNAME                 205
-#define IDS_DEF_LOGFILE                 301
-#define IDS_DEF_MAXSIZE                 302
-#define IDS_DEF_SHRINKTOSIZE            303
-#define IDS_DEF_LOGENABLED              304
-#define IDS_MUTEX_TIMEOUT               401
-
-// Next default values for new objects
-//
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        201
-#define _APS_NEXT_COMMAND_VALUE         32768
-#define _APS_NEXT_CONTROL_VALUE         201
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
index 383af3135368cd29d1674e618f8fcd606c76cba8..9d62e99ff58f72deb281487788e1bd03c680d2d7 100755 (executable)
 
 # 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
+ifeq "$(DEBUG)" "1"
+DEBUGFLAGS = -g
+BUILDDIR = build/debug
+else
+DEBUGFLAGS = -Os
+BUILDDIR = build/prod
+endif
+
 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
+LIBS = -L../mDNSPosix/$(BUILDDIR)/ -ldns_sd
 endif
 
 all: $(TARGETS)
@@ -46,10 +54,10 @@ build:
        mkdir build
 
 build/dns-sd: build dns-sd.c ClientCommon.c
-       $(CC) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
+       $(CC) $(SUPMAKE_CFLAGS) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@
 
 build/dns-sd64: build dns-sd.c ClientCommon.c
-       $(CC) $(filter %.c %.o, $+) $(LIBS) -I../mDNSShared -Wall -o $@ -m64
+       $(CC) $(SUPMAKE_CFLAGS) $(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
index 5260b3f29b5ac873ca7effd526bf9aa886df2e8a..357a478f56208adadd4377b610beace44a3d9dae 100644 (file)
 #include <errno.h>          // For errno, EINTR
 #include <time.h>
 #include <sys/types.h>      // For u_char
+#ifdef APPLE_OSX_mDNSResponder
+#include <inttypes.h>       // For PRId64
+#endif // APPLE_OSX_mDNSResponder
+
+#if APPLE_OSX_mDNSResponder
+#include <xpc/xpc.h>
+#include "xpc_clients.h"
+#endif
 
 #ifdef _WIN32
     #include <winsock2.h>
@@ -168,6 +176,7 @@ static const char kFilePathSep = '/';
 #include "dns_sd_internal.h"
 #include "ClientCommon.h"
 
+
 #if TEST_NEW_CLIENTSTUB
 #include "../mDNSShared/dnssd_ipc.c"
 #include "../mDNSShared/dnssd_clientlib.c"
@@ -509,49 +518,52 @@ static void FormatTime(unsigned long te, unsigned char *buf, int bufsize)
 static void print_usage(const char *arg0, int print_all)
 {
     // Print the commonly used command line options.  These are listed in "the order they have been in historically".
-    fprintf(stderr, "%s -E                              (Enumerate recommended registration domains)\n", arg0);
-    fprintf(stderr, "%s -F                                  (Enumerate recommended browsing domains)\n", arg0);
-    fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...]             (Register a service)\n", arg0);
-    fprintf(stderr, "%s -B        <Type> <Domain>                     (Browse for service instances)\n", arg0);
-    fprintf(stderr, "%s -L <Name> <Type> <Domain>                       (Resolve a service instance)\n", arg0);
-    fprintf(stderr, "%s -Q <name> <rrtype> <rrclass>             (Generic query for any record type)\n", arg0);
-    fprintf(stderr, "%s -Z        <Type> <Domain>               (Output results in Zone File format)\n", arg0);
-    fprintf(stderr, "%s -G     v4/v6/v4v6 <name>              (Get address information for hostname)\n", arg0);
-    fprintf(stderr, "%s -H                                   (Print usage for complete command list)\n", arg0);
-    fprintf(stderr, "%s -V                (Get version of currently running daemon / system service)\n", arg0);
+    fprintf(stderr, "%s -E                          (Enumerate recommended registration domains)\n", arg0);
+    fprintf(stderr, "%s -F                          (Enumerate recommended browsing     domains)\n", arg0);
+    fprintf(stderr, "%s -R <Name> <Type> <Domain> <Port> [<TXT>...]         (Register a service)\n", arg0);
+    fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...] (Register Proxy)\n", arg0);
+    fprintf(stderr, "%s -B        <Type> <Domain>                 (Browse for service instances)\n", arg0);
+    fprintf(stderr, "%s -Z        <Type> <Domain>           (Output results in Zone File format)\n", arg0);
+    fprintf(stderr, "%s -L <Name> <Type> <Domain>        (Resolve (‘lookup’) a service instance)\n", arg0);
+    fprintf(stderr, "%s -Q <name> <rrtype> <rrclass>         (Generic query for any record type)\n", arg0);
+    fprintf(stderr, "%s -q <name> <rrtype> <rrclass>     (Generic query, using SuppressUnusable)\n", arg0);
+    fprintf(stderr, "%s -G v4/v6/v4v6 <hostname>          (Get address information for hostname)\n", arg0);
+    fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL>           (NAT Port Mapping)\n", arg0);
+    fprintf(stderr, "%s -H                               (Print usage for complete command list)\n", arg0);
+    fprintf(stderr, "%s -V            (Get version of currently running daemon / system service)\n", arg0);
+#ifdef APPLE_OSX_mDNSResponder
+    fprintf(stderr, "%s -O [-compress|-stdout](Dump the state of mDNSResponder to file / STDOUT)\n", arg0);
+#endif // APPLE_OSX_mDNSResponder
 
     if (print_all)  // Print all available options for dns-sd tool.  Keep these in alphabetical order for easier maintenance.
     {
         fprintf(stderr, "\n");
-        fprintf(stderr, "%s -A                                  (Test Adding/Updating/Deleting a record)\n", arg0);
-        fprintf(stderr, "%s -C <FQDN> <rrtype> <rrclass>               (Query; reconfirming each result)\n", arg0);
-        fprintf(stderr, "%s -D <name> <rrtype> <rrclass>(Validate query for any record type with DNSSEC)\n", arg0);
-        fprintf(stderr, "%s -I               (Test registering and then immediately updating TXT record)\n", arg0);
-        fprintf(stderr, "%s -N                                         (Test adding a large NULL record)\n", arg0);
-        fprintf(stderr, "%s -M                  (Test creating a registration with multiple TXT records)\n", arg0);
-        fprintf(stderr, "%s -P <Name> <Type> <Domain> <Port> <Host> <IP> [<TXT>...]              (Proxy)\n", arg0);
-        fprintf(stderr, "%s -S                             (Test multiple operations on a shared socket)\n", arg0);
-        fprintf(stderr, "%s -T                                        (Test creating a large TXT record)\n", arg0);
-        fprintf(stderr, "%s -U                                              (Test updating a TXT record)\n", arg0);
-        fprintf(stderr, "%s -X udp/tcp/udptcp <IntPort> <ExtPort> <TTL>               (NAT Port Mapping)\n", arg0);
-        fprintf(stderr, "%s -ble                                      (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
-        fprintf(stderr, "%s -g v4/v6/v4v6 <name>        (Validate address info for hostname with DNSSEC)\n", arg0);
-        fprintf(stderr, "%s -i <Interface>             (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
-        fprintf(stderr, "%s -includep2p                            (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
-        fprintf(stderr, "%s -includeAWDL                          (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
-        fprintf(stderr, "%s -intermediates                (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
-        fprintf(stderr, "%s -ku                                   (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
-        fprintf(stderr, "%s -lo                              (Run dns-sd cmd using local only interface)\n", arg0);
-        fprintf(stderr, "%s -optional                        (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
-        fprintf(stderr, "%s -p2p                                      (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
-        fprintf(stderr, "%s -q <name> <rrtype> <rrclass> (Equivalent to -Q with kDNSServiceFlagsSuppressUnusable set)\n", arg0);
-        fprintf(stderr, "%s -tc                        (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
-        fprintf(stderr, "%s -test                                      (Run basic API input range tests)\n", arg0);
-        fprintf(stderr, "%s -t1                                  (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
-        fprintf(stderr, "%s -tFinder                          (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
-        fprintf(stderr, "%s -timeout                                  (Set kDNSServiceFlagsTimeout flag)\n", arg0);
-        fprintf(stderr, "%s -unicastResponse                  (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
-        fprintf(stderr, "%s -autoTrigger                          (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
+        fprintf(stderr, "%s -A                              (Test Adding/Updating/Deleting a record)\n", arg0);
+        fprintf(stderr, "%s -C <name> <rrtype> <rrclass>           (Query; reconfirming each result)\n", arg0);
+        fprintf(stderr, "%s -D <name> <rrtype> <rrclass>                (Validate query with DNSSEC)\n", arg0);
+        fprintf(stderr, "%s -I           (Test registering and then immediately updating TXT record)\n", arg0);
+        fprintf(stderr, "%s -N                                     (Test adding a large NULL record)\n", arg0);
+        fprintf(stderr, "%s -M              (Test creating a registration with multiple TXT records)\n", arg0);
+        fprintf(stderr, "%s -S                         (Test multiple operations on a shared socket)\n", arg0);
+        fprintf(stderr, "%s -T                                    (Test creating a large TXT record)\n", arg0);
+        fprintf(stderr, "%s -U                                          (Test updating a TXT record)\n", arg0);
+        fprintf(stderr, "%s -ble                                  (Use kDNSServiceInterfaceIndexBLE)\n", arg0);
+        fprintf(stderr, "%s -g v4/v6/v4v6 <hostname>             (Validate address info with DNSSEC)\n", arg0);
+        fprintf(stderr, "%s -i <Interface>         (Run dns-sd cmd on a specific interface (en0/en1)\n", arg0);
+        fprintf(stderr, "%s -includep2p                        (Set kDNSServiceFlagsIncludeP2P flag)\n", arg0);
+        fprintf(stderr, "%s -includeAWDL                      (Set kDNSServiceFlagsIncludeAWDL flag)\n", arg0);
+        fprintf(stderr, "%s -intermediates            (Set kDNSServiceFlagsReturnIntermediates flag)\n", arg0);
+        fprintf(stderr, "%s -ku                               (Set kDNSServiceFlagsKnownUnique flag)\n", arg0);
+        fprintf(stderr, "%s -lo                          (Run dns-sd cmd using local only interface)\n", arg0);
+        fprintf(stderr, "%s -optional                    (Set kDNSServiceFlagsValidateOptional flag)\n", arg0);
+        fprintf(stderr, "%s -p2p                                  (Use kDNSServiceInterfaceIndexP2P)\n", arg0);
+        fprintf(stderr, "%s -tc                    (Set kDNSServiceFlagsBackgroundTrafficClass flag)\n", arg0);
+        fprintf(stderr, "%s -test                                  (Run basic API input range tests)\n", arg0);
+        fprintf(stderr, "%s -t1                              (Set kDNSServiceFlagsThresholdOne flag)\n", arg0);
+        fprintf(stderr, "%s -tFinder                      (Set kDNSServiceFlagsThresholdFinder flag)\n", arg0);
+        fprintf(stderr, "%s -timeout                              (Set kDNSServiceFlagsTimeout flag)\n", arg0);
+        fprintf(stderr, "%s -unicastResponse              (Set kDNSServiceFlagsUnicastResponse flag)\n", arg0);
+        fprintf(stderr, "%s -autoTrigger                      (Set kDNSServiceFlagsAutoTrigger flag)\n", arg0);
     }
 }
 
@@ -1035,7 +1047,7 @@ static void DNSSD_API qr_reply(DNSServiceRef sdref, const DNSServiceFlags flags,
     int unknowntype = 0;
     char dnssec_status[15] = "Unknown";
     char rr_type[RR_TYPE_SIZE];
-    char rr_class[3];
+    char rr_class[6];
     DNSServiceFlags check_flags = flags;//local flags for dnssec status checking
 
     (void)sdref;    // Unused
@@ -1215,7 +1227,7 @@ static void DNSSD_API addrinfo_reply(DNSServiceRef sdref, const DNSServiceFlags
         const unsigned char       *b  = (const unsigned char *      )&s6->sin6_addr;
         if (!if_indextoname(s6->sin6_scope_id, if_name))
             snprintf(if_name, sizeof(if_name), "<%d>", s6->sin6_scope_id);
-            snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
+        snprintf(addr, sizeof(addr), "%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X:%02X%02X%%%s",
             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_name);
     }
@@ -1401,12 +1413,14 @@ static DNSServiceErrorType RegisterProxyAddressRecord(DNSServiceRef sdref, const
 
 #define HexPair(P) ((HexVal((P)[0]) << 4) | HexVal((P)[1]))
 
+#define MAXTXTRecordSize 8900
 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)
 {
     uint16_t PortAsNumber = atoi(port);
     Opaque16 registerPort = { { PortAsNumber >> 8, PortAsNumber & 0xFF } };
-    unsigned char txt[2048] = "";
+    unsigned char txt[MAXTXTRecordSize];
+    txt[0] = '\0';
     unsigned char *ptr = txt;
     int i;
 
@@ -1422,9 +1436,13 @@ static DNSServiceErrorType RegisterService(DNSServiceRef *sdref,
         for (i = 0; i < argc; i++)
         {
             const char *p = argv[i];
+            if (ptr >= txt + sizeof(txt))
+                return kDNSServiceErr_BadParam;
             *ptr = 0;
-            while (*p && *ptr < 255 && ptr + 1 + *ptr < txt+sizeof(txt))
+            while (*p && *ptr < 255)
             {
+                if (ptr + 1 + *ptr >= txt + sizeof(txt))
+                    return kDNSServiceErr_BadParam;
                 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; }
@@ -1836,6 +1854,9 @@ static int API_input_range_test()
     return 0;
 }
 
+#ifdef APPLE_OSX_mDNSResponder
+static void handle_state_dump_request(uint8_t if_compress_state_dump, uint8_t if_dump_to_stdout);
+#endif // APPLE_OSX_mDNSResponder
 int main(int argc, char **argv)
 {
     DNSServiceErrorType err;
@@ -2245,11 +2266,43 @@ int main(int argc, char **argv)
         else printf("Currently running daemon (system service) is version %d.%d.%d\n",  v / 10000, v / 100 % 100, v % 100);
         exit(0);
     }
+#ifdef APPLE_OSX_mDNSResponder
+    case 'O': {
+        // check if the user specifies the flag "-compress"
+        uint8_t if_compress_state_dump = 0;
+        uint8_t if_dump_to_stdout = 0;
+
+        if (argc > opi+1) {
+            printf("dns-sd: illegal option count\n");
+            goto Fail;
+        }
+        
+        if (argc == opi+1) {
+            const char *param = argv[opi];
+            if (strcasecmp("-compress", param) == 0) {
+                if_compress_state_dump = 1;
+            } else if (strcasecmp("-stdout", param) == 0) {
+                if_dump_to_stdout = 1;
+            } else {
+                printf("dns-sd: illegal option %s \n", param);
+                goto Fail;
+            }
+        }
+        handle_state_dump_request(if_compress_state_dump, if_dump_to_stdout);
+        err = kDNSServiceErr_NoError;
+        break;
+    }
+#endif // APPLE_OSX_mDNSResponder
 
     case 'H': goto Fail;
 
     default: goto Fail;
     }
+#ifdef APPLE_OSX_mDNSResponder
+    // state dump does not need to create DNSServiceRef, so we can return directly here without cleaning up.
+    if (operation == 'O')
+        return 0;
+#endif // APPLE_OSX_mDNSResponder
 
     if (!client || err != kDNSServiceErr_NoError)
     {
@@ -2270,8 +2323,72 @@ Fail:
     if (operation == 'H') print_usage(a0,1);
     else print_usage(a0,0);
     return 0;
+}
+
+#ifdef APPLE_OSX_mDNSResponder
+/*
+ *  if_compress_state_dump and if_dump_to_stdout cannot be set at the same time.
+ */
+static void handle_state_dump_request(uint8_t if_compress_state_dump, uint8_t if_dump_to_stdout)
+{
+    // create xpc connection to the xpc server for log utility
+    xpc_connection_t log_utility_connection =  xpc_connection_create_mach_service(kDNSLogUtilityService, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+    xpc_connection_set_event_handler(log_utility_connection, ^(xpc_object_t event){
+        printf("Connecting to %s, status: %s\n", kDNSLogUtilityService, xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+    });
+    xpc_connection_resume(log_utility_connection);
+
+    // set option for the state dump
+    xpc_object_t xpc_dict = xpc_dictionary_create(NULL, NULL, 0);
+    uint64_t dump_option;
+    if (if_compress_state_dump) {
+        dump_option = full_state_with_compression;
+    }
+    else if (if_dump_to_stdout) {
+        // we pass the stdout directly to xpc server
+        dump_option = full_state_to_stdout;
+        xpc_dictionary_set_fd(xpc_dict, kDNSStateDumpFD, STDOUT_FILENO);
+    }
+    else {
+        dump_option = full_state;
+    }
+
+    xpc_dictionary_set_uint64(xpc_dict, kDNSStateDump, dump_option);
+
+    // send the request and handle the response from xpc server
+    xpc_connection_send_message_with_reply(log_utility_connection, xpc_dict, dispatch_get_main_queue(), ^(xpc_object_t recv_msg){
+        xpc_type_t msg_type = xpc_get_type(recv_msg);
 
+        if (msg_type != XPC_TYPE_DICTIONARY) {
+            printf("Received unexpected reply from daemon, error: \"%s\"\nUnexpected reply Contents:\n%s\n",
+                   xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION), xpc_copy_description(recv_msg));
+            exit(1);
+        }
+
+        // get the response dictionary
+        uint32_t return_code = (uint32_t)xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply);
+        if (return_code != kDNSMsg_NoError) {
+            const char *error_description = xpc_dictionary_get_string(recv_msg, kDNSErrorDescription);
+            printf("XPC service returns error, description: %s\n", error_description);
+            exit(1);
+        }
+
+        // print the state information returned from the XPC server
+        if (dump_option != full_state_to_stdout) {
+            const char *path = xpc_dictionary_get_string(recv_msg, kDNSDumpFilePath);
+            printf("State Dump Is Saved to: %s\n", path);
+        }
+
+        int64_t time_used = xpc_dictionary_get_int64(recv_msg, kDNSStateDumpTimeUsed);
+        printf("             Time Used: %" PRId64 " ms\n", time_used);
+
+        xpc_release(xpc_dict);
+        exit(0);
+    });
+
+    dispatch_main();
 }
+#endif // APPLE_OSX_mDNSResponder
 
 // 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"
diff --git a/Clients/dnsctl.c b/Clients/dnsctl.c
deleted file mode 100644 (file)
index e01c8fe..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*- 
- *
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
- *
- * dnsctl.c 
- * Command-line tool using libdns_services.dylib 
- *   
- * To build only this tool, copy and paste the following on the command line:
- * On Apple 64bit Platforms ONLY OSX/iOS:
- * clang -Wall dnsctl.c /usr/lib/libdns_services.dylib -o dnsctl
- * 
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <net/if.h> // if_nametoindex()
-
-#include "dns_services.h"
-#include <xpc/xpc.h>
-#include "dns_xpc.h"
-
-//*************************************************************************************************************
-// Globals:
-//*************************************************************************************************************
-
-static const char kFilePathSep   =  '/';
-
-static DNSXConnRef ClientRef     =  NULL;
-
-static xpc_connection_t dnsctl_conn = NULL;
-
-//*************************************************************************************************************
-// Utility Funcs:
-//*************************************************************************************************************
-
-static void printtimestamp(void)
-{
-    struct tm tm;
-    int ms;
-    static char date[16];
-    static char new_date[16];
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    localtime_r((time_t*)&tv.tv_sec, &tm);
-    ms = tv.tv_usec/1000;
-    strftime(new_date, sizeof(new_date), "%a %d %b %Y", &tm);
-    //display date only if it has changed
-    if (strncmp(date, new_date, sizeof(new_date)))
-    {
-        printf("DATE: ---%s---\n", new_date);
-        strlcpy(date, new_date, sizeof(date));
-    }
-    printf("%2d:%02d:%02d.%03d  ", tm.tm_hour, tm.tm_min, tm.tm_sec, ms);
-}
-
-static void print_usage(const char *arg0)
-{
-    fprintf(stderr, "%s USAGE:                                                                  \n", arg0);
-    fprintf(stderr, "%s -DP Enable DNS Proxy with Default Parameters                            \n", arg0);
-    fprintf(stderr, "%s -DP [-o <output interface>] [-i <input interface(s)>] Enable DNS Proxy  \n", arg0);
-    fprintf(stderr, "%s -L [1/2/3/4] Change mDNSResponder Logging Level                         \n", arg0);
-    fprintf(stderr, "%s -I Print mDNSResponder STATE INFO                                       \n", arg0);
-}
-
-
-static bool DebugEnabled()
-{
-    return true; // keep this true to debug the XPC msgs
-}
-
-static void DebugLog(const char *prefix, xpc_object_t o)
-{
-    if (!DebugEnabled())
-        return;
-    
-    char *desc = xpc_copy_description(o);
-    printf("%s: %s \n", prefix, desc);
-    free(desc);
-}
-
-//*************************************************************************************************************
-// CallBack Funcs:
-//*************************************************************************************************************
-
-
-// DNSXEnableProxy Callback from the Daemon
-static void dnsproxy_reply(DNSXConnRef connRef, DNSXErrorType errCode)
-{
-    (void) connRef;
-    printtimestamp();
-    switch (errCode)
-    {
-        case kDNSX_NoError          :  printf("  SUCCESS   \n");
-            break;
-        case kDNSX_DaemonNotRunning :  printf(" NO DAEMON  \n");
-            DNSXRefDeAlloc(ClientRef);    break;
-        case kDNSX_BadParam          :  printf(" BAD PARAMETER \n");
-            DNSXRefDeAlloc(ClientRef);    break;
-        case kDNSX_Busy             :  printf(" BUSY \n");
-            DNSXRefDeAlloc(ClientRef);    break;
-        case kDNSX_UnknownErr       :
-        default                     :  printf(" UNKNOWN ERR \n");
-            DNSXRefDeAlloc(ClientRef);    break;
-    }
-    fflush(NULL);
-    
-}
-
-//*************************************************************************************************************
-// XPC Funcs:
-//*************************************************************************************************************
-
-static void Init_Connection(const char *servname)
-{
-    dnsctl_conn = xpc_connection_create_mach_service(servname, dispatch_get_main_queue(), XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
-    
-    xpc_connection_set_event_handler(dnsctl_conn, ^(xpc_object_t event)
-    {
-         printf("InitConnection: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
-    });
-    
-    xpc_connection_resume(dnsctl_conn);
-}
-
-static void SendDictToServer(xpc_object_t msg)
-{
-    
-    DebugLog("SendDictToServer Sending msg to Daemon", msg);
-    
-    xpc_connection_send_message_with_reply(dnsctl_conn, msg, dispatch_get_main_queue(), ^(xpc_object_t recv_msg)
-    {
-        xpc_type_t type = xpc_get_type(recv_msg);
-                                               
-        if (type == XPC_TYPE_DICTIONARY)
-        {
-            DebugLog("SendDictToServer Received reply msg from Daemon", recv_msg);
-            /*
-            // If we ever want to do something based on the reply of the daemon
-            switch (daemon_status)
-            {
-                default:
-                    break;
-            }
-            */
-        }
-        else
-        {
-            printf("SendDictToServer Received unexpected reply from daemon [%s]",
-                                xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION));
-            DebugLog("SendDictToServer Unexpected Reply contents", recv_msg);
-        }
-        exit(1);
-    });
-}
-
-//*************************************************************************************************************
-
-int main(int argc, char **argv)
-{
-    // Extract program name from argv[0], which by convention contains the path to this executable
-    const char *a0 = strrchr(argv[0], kFilePathSep) + 1;
-    if (a0 == (const char *)1)
-        a0 = argv[0];
-    
-    // Must run as root
-    if (0 != geteuid())
-    {
-        fprintf(stderr, "%s MUST run as root!!\n", a0);
-        exit(-1);
-    }
-    if ((sizeof(argv) == 8))
-        printf("dnsctl running in 64-bit mode\n");
-    else if ((sizeof(argv) == 4))
-        printf("dnsctl running in 32-bit mode\n");
-    
-    // expects atleast one argument
-    if (argc < 2)
-        goto Usage;
-    
-    printtimestamp();
-    if (!strcasecmp(argv[1], "-DP"))
-    {
-        DNSXErrorType err;
-        // Default i/p intf is lo0 and o/p intf is primary interface
-        IfIndex Ipintfs[MaxInputIf] =  {1, 0, 0, 0, 0};
-        IfIndex Opintf = kDNSIfindexAny;
-        
-        if (argc == 2)
-        {
-            dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
-            err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
-            if (err)
-                fprintf(stderr, "DNSXEnableProxy returned %d\n", err);
-        }
-        else if (argc > 2)
-        {
-            argc--;
-            argv++;
-            if (!strcmp(argv[1], "-o"))
-            {
-                Opintf = if_nametoindex(argv[2]);
-                if (!Opintf)
-                    Opintf = atoi(argv[2]);
-                if (!Opintf)
-                {
-                    fprintf(stderr, "Could not parse o/p interface [%s]: Passing default primary \n", argv[2]);
-                    Opintf = kDNSIfindexAny;
-                }
-                argc -= 2;
-                argv += 2;
-            }
-            if (argc > 2 && !strcmp(argv[1], "-i"))
-            {
-                int i;
-                argc--;
-                argv++;
-                for (i = 0; i < MaxInputIf && argc > 1; i++)
-                {
-                    Ipintfs[i] = if_nametoindex(argv[1]);
-                    if (!Ipintfs[i])
-                        Ipintfs[i] = atoi(argv[1]);
-                    if (!Ipintfs[i])
-                    {
-                        fprintf(stderr, "Could not parse i/p interface [%s]: Passing default lo0 \n", argv[2]);
-                        Ipintfs[i] = 1;
-                    }
-                    argc--;
-                    argv++;
-                }
-            }
-            printf("Enabling DNSProxy on mDNSResponder \n");
-            dispatch_queue_t my_Q = dispatch_queue_create("com.apple.dnsctl.callback_queue", NULL);
-            err = DNSXEnableProxy(&ClientRef, kDNSProxyEnable, Ipintfs, Opintf, my_Q, dnsproxy_reply);
-            if (err)
-                fprintf(stderr, "DNSXEnableProxy returned %d\n", err);
-        }
-    }
-    else if (!strcasecmp(argv[1], "-l"))
-    {
-        printf("Changing loglevel of mDNSResponder \n");
-        Init_Connection(kDNSCTLService);
-
-        // Create Dictionary To Send
-        xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-
-        if (argc == 2)
-        {
-            xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1);
-            
-            SendDictToServer(dict);
-            xpc_release(dict);
-            dict = NULL;
-        }
-        else if (argc > 2)
-        {
-            argc--;
-            argv++;
-            switch (atoi(argv[1]))
-            {
-                case log_level1:
-                    xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1);
-                    break;
-                    
-                case log_level2:
-                    xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2);
-                    break;
-                
-                case log_level3:
-                    xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level3);
-                    break;
-                
-                case log_level4:
-                    xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level4);
-                    break;
-                    
-                default:
-                    xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level1);
-                    break;
-            }
-            SendDictToServer(dict);
-            xpc_release(dict);
-            dict = NULL;
-        }
-    }
-    else if(!strcasecmp(argv[1], "-i"))
-    {
-        printf("Get STATE INFO of mDNSResponder \n");
-        Init_Connection(kDNSCTLService);
-
-        // Create Dictionary To Send
-        xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-        xpc_dictionary_set_uint64(dict, kDNSStateInfo, full_state);
-        SendDictToServer(dict);
-        xpc_release(dict);
-        dict = NULL;
-    }
-    else if(!strcasecmp(argv[1], "-th"))
-    {
-        printf("Sending Test message to mDNSResponder to forward to mDNSResponderHelper\n");
-        Init_Connection(kDNSCTLService);
-        
-        // Create Dictionary To Send
-        xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-        xpc_dictionary_set_uint64(dict, kmDNSResponderTests, test_helper_ipc);
-        SendDictToServer(dict);
-        xpc_release(dict);
-        dict = NULL;
-    }
-    else if(!strcasecmp(argv[1], "-tl"))
-    {
-        printf("Testing mDNSResponder Logging\n");
-        Init_Connection(kDNSCTLService);
-        
-        // Create Dictionary To Send
-        xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-        xpc_dictionary_set_uint64(dict, kmDNSResponderTests, test_mDNS_log);
-        SendDictToServer(dict);
-        xpc_release(dict);
-        dict = NULL;
-    }
-    else
-    {
-        goto Usage;
-    }
-    
-    dispatch_main();
-    
-Usage:
-    print_usage(a0);
-    return 0;
-}
-
-/*
-#include <getopt.h>
-static int operation;
-
-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.
-    int o = getopt(argc, (char *const *)argv, optstr);
-    *pOptInd = optind;
-    return o;
-}
-int opindex;
-operation = getfirstoption(argc, argv, "lLDdPp", &opindex);
-if (operation == -1)
-    goto Usage;
-switch (operation)
-{
-    case 'L':
-    case 'l':
-    {
-        printtimestamp();
-        printf("Change Verbosity Level of mDNSResponder\n");
-        Init_Connection(kDNSCTLService);
-        // Create Dictionary To Send
-        xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-        if (dict == NULL)
-            printf("could not create the Msg Dict To Send! \n");
-        xpc_dictionary_set_uint64(dict, kDNSLogLevel, log_level2);
-        SendDictToServer(dict);
-        xpc_release(dict);
-        dict = NULL;
-        break;
-    }
- // exit(1);
-}
-
-*/
-
diff --git a/Clients/dnssdutil.c b/Clients/dnssdutil.c
deleted file mode 100644 (file)
index 16b4875..0000000
+++ /dev/null
@@ -1,21247 +0,0 @@
-/*
-       Copyright (c) 2016-2018 Apple Inc. All rights reserved.
-       
-       dnssdutil is a command-line utility for testing the DNS-SD API.
-*/
-
-#include <CoreUtils/CommonServices.h>  // Include early.
-#include <CoreUtils/AsyncConnection.h>
-#include <CoreUtils/AtomicUtils.h>
-#include <CoreUtils/CFUtils.h>
-#include <CoreUtils/CommandLineUtils.h>
-#include <CoreUtils/DataBufferUtils.h>
-#include <CoreUtils/DebugServices.h>
-#include <CoreUtils/HTTPUtils.h>
-#include <CoreUtils/JSONUtils.h>
-#include <CoreUtils/LogUtils.h>
-#include <CoreUtils/MiscUtils.h>
-#include <CoreUtils/NetUtils.h>
-#include <CoreUtils/PrintFUtils.h>
-#include <CoreUtils/RandomNumberUtils.h>
-#include <CoreUtils/SoftLinking.h>
-#include <CoreUtils/StringUtils.h>
-#include <CoreUtils/TickUtils.h>
-#include <CoreUtils/TimeUtils.h>
-#include <dns_sd.h>
-#include <dns_sd_private.h>
-
-#include CF_RUNTIME_HEADER
-
-#if( TARGET_OS_DARWIN )
-       #include <CFNetwork/CFHost.h>
-       #include <CoreFoundation/CoreFoundation.h>
-       #include <SystemConfiguration/SCPrivate.h>
-       #include <dnsinfo.h>
-       #include <libproc.h>
-       #include <netdb.h>
-       #include <pcap.h>
-       #include <spawn.h>
-       #include <sys/proc_info.h>
-#endif
-
-#if( TARGET_OS_POSIX )
-       #include <sys/resource.h>
-#endif
-
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-       #include "tweetnacl.h"  // TweetNaCl from <https://tweetnacl.cr.yp.to/software.html>.
-#endif
-
-//===========================================================================================================================
-//     Versioning
-//===========================================================================================================================
-
-#define kDNSSDUtilNumVersion   NumVersionBuild( 2, 0, 0, kVersionStageBeta, 0 )
-
-#if( !MDNSRESPONDER_PROJECT && !defined( DNSSDUTIL_SOURCE_VERSION ) )
-       #define DNSSDUTIL_SOURCE_VERSION        "0.0.0"
-#endif
-
-//===========================================================================================================================
-//     DNS-SD
-//===========================================================================================================================
-
-// DNS-SD API flag descriptors
-
-#define kDNSServiceFlagsDescriptors            \
-       "\x00" "AutoTrigger\0"                          \
-       "\x01" "Add\0"                                          \
-       "\x02" "Default\0"                                      \
-       "\x03" "NoAutoRename\0"                         \
-       "\x04" "Shared\0"                                       \
-       "\x05" "Unique\0"                                       \
-       "\x06" "BrowseDomains\0"                        \
-       "\x07" "RegistrationDomains\0"          \
-       "\x08" "LongLivedQuery\0"                       \
-       "\x09" "AllowRemoteQuery\0"                     \
-       "\x0A" "ForceMulticast\0"                       \
-       "\x0B" "KnownUnique\0"                          \
-       "\x0C" "ReturnIntermediates\0"          \
-       "\x0D" "NonBrowsable\0"                         \
-       "\x0E" "ShareConnection\0"                      \
-       "\x0F" "SuppressUnusable\0"                     \
-       "\x10" "Timeout\0"                                      \
-       "\x11" "IncludeP2P\0"                           \
-       "\x12" "WakeOnResolve\0"                        \
-       "\x13" "BackgroundTrafficClass\0"       \
-       "\x14" "IncludeAWDL\0"                          \
-       "\x15" "Validate\0"                                     \
-       "\x16" "UnicastResponse\0"                      \
-       "\x17" "ValidateOptional\0"                     \
-       "\x18" "WakeOnlyService\0"                      \
-       "\x19" "ThresholdOne\0"                         \
-       "\x1A" "ThresholdFinder\0"                      \
-       "\x1B" "DenyCellular\0"                         \
-       "\x1C" "ServiceIndex\0"                         \
-       "\x1D" "DenyExpensive\0"                        \
-       "\x1E" "PathEvaluationDone\0"           \
-       "\x1F" "AllowExpiredAnswers\0"          \
-       "\x00"
-
-#define kDNSServiceProtocolDescriptors \
-       "\x00" "IPv4\0"                                         \
-       "\x01" "IPv6\0"                                         \
-       "\x04" "UDP\0"                                          \
-       "\x05" "TCP\0"                                          \
-       "\x00"
-
-#define kBadDNSServiceRef              ( (DNSServiceRef)(intptr_t) -1 )
-
-//===========================================================================================================================
-//     DNS
-//===========================================================================================================================
-
-#define kDNSPort                                       53
-#define kDNSMaxUDPMessageSize          512
-#define kDNSMaxTCPMessageSize          UINT16_MAX
-
-#define kDomainLabelLengthMax          63
-#define kDomainNameLengthMax           256
-
-#define kDNSRecordDataLengthMax                UINT16_MAX
-
-typedef struct
-{
-       uint8_t         id[ 2 ];
-       uint8_t         flags[ 2 ];
-       uint8_t         questionCount[ 2 ];
-       uint8_t         answerCount[ 2 ];
-       uint8_t         authorityCount[ 2 ];
-       uint8_t         additionalCount[ 2 ];
-       
-}      DNSHeader;
-
-#define kDNSHeaderLength               12
-check_compile_time( sizeof( DNSHeader ) == kDNSHeaderLength );
-
-#define DNSHeaderGetID( HDR )                                  ReadBig16( ( HDR )->id )
-#define DNSHeaderGetFlags( HDR )                               ReadBig16( ( HDR )->flags )
-#define DNSHeaderGetQuestionCount( HDR )               ReadBig16( ( HDR )->questionCount )
-#define DNSHeaderGetAnswerCount( HDR )                 ReadBig16( ( HDR )->answerCount )
-#define DNSHeaderGetAuthorityCount( HDR )              ReadBig16( ( HDR )->authorityCount )
-#define DNSHeaderGetAdditionalCount( HDR )             ReadBig16( ( HDR )->additionalCount )
-
-#define DNSHeaderSetID( HDR, X )                                       WriteBig16( ( HDR )->id, (X) )
-#define DNSHeaderSetFlags( HDR, X )                                    WriteBig16( ( HDR )->flags, (X) )
-#define DNSHeaderSetQuestionCount( HDR, X )                    WriteBig16( ( HDR )->questionCount, (X) )
-#define DNSHeaderSetAnswerCount( HDR, X )                      WriteBig16( ( HDR )->answerCount, (X) )
-#define DNSHeaderSetAuthorityCount( HDR, X )           WriteBig16( ( HDR )->authorityCount, (X) )
-#define DNSHeaderSetAdditionalCount( HDR, X )          WriteBig16( ( HDR )->additionalCount, (X) )
-
-// Single-bit DNS header fields
-
-#define kDNSHeaderFlag_Response                                        ( 1 << 15 )     // QR (bit 15), Query (0)/Response (1)
-#define kDNSHeaderFlag_AuthAnswer                              ( 1 << 10 )     // AA (bit 10), Authoritative Answer
-#define kDNSHeaderFlag_Truncation                              ( 1 <<  9 )     // TC (bit  9), TrunCation
-#define kDNSHeaderFlag_RecursionDesired                        ( 1 <<  8 )     // RD (bit  8), Recursion Desired
-#define kDNSHeaderFlag_RecursionAvailable              ( 1 <<  7 )     // RA (bit  7), Recursion Available
-#define kDNSHeaderFlag_Z                                               ( 1 <<  6 )     //  Z (bit  6), Reserved (must be zero)
-#define kDNSHeaderFlag_AuthenticData                   ( 1 <<  5 )     // AD (bit  5), Authentic Data (RFC 2535, Section 6)
-#define kDNSHeaderFlag_CheckingDisabled                        ( 1 <<  4 )     // CD (bit  4), Checking Disabled (RFC 2535, Section 6)
-
-// OPCODE (bits 14-11), Operation Code
-
-#define DNSFlagsGetOpCode( FLAGS )             ( ( (FLAGS) >> 11 ) & 0x0FU )
-#define DNSFlagsSetOpCode( FLAGS, OPCODE ) \
-       do{ (FLAGS) = ( (FLAGS) & ~0x7800U ) | ( ( (OPCODE) & 0x0FU ) << 11 ); } while( 0 )
-
-#define kDNSOpCode_Query                       0       // QUERY (standard query)
-#define kDNSOpCode_InverseQuery                1       // IQUERY (inverse query)
-#define kDNSOpCode_Status                      2       // STATUS
-#define kDNSOpCode_Notify                      4       // NOTIFY
-#define kDNSOpCode_Update                      5       // UPDATE
-
-// RCODE (bits 3-0), Response Code
-
-#define DNSFlagsGetRCode( FLAGS )              ( (FLAGS) & 0x0FU )
-#define DNSFlagsSetRCode( FLAGS, RCODE ) \
-       do{ (FLAGS) = ( (FLAGS) & ~0x000FU ) | ( (RCODE) & 0x0FU ); } while( 0 )
-
-#define kDNSRCode_NoError                              0
-#define kDNSRCode_FormatError                  1
-#define kDNSRCode_ServerFailure                        2
-#define kDNSRCode_NXDomain                             3
-#define kDNSRCode_NotImplemented               4
-#define kDNSRCode_Refused                              5
-
-typedef struct
-{
-       uint8_t         type[ 2 ];
-       uint8_t         class[ 2 ];
-       
-}      DNSQuestionFixedFields;
-
-check_compile_time( sizeof( DNSQuestionFixedFields ) == 4 );
-
-#define DNSQuestionFixedFieldsInit( FIELDS, QTYPE, QCLASS ) \
-       do { WriteBig16( (FIELDS)->type, QTYPE ); WriteBig16( (FIELDS)->class, QCLASS ); } while( 0 )
-
-#define DNSQuestionFixedFieldsGetType( FIELDS )                        ReadBig16( (FIELDS)->type )
-#define DNSQuestionFixedFieldsGetClass( FIELDS )               ReadBig16( (FIELDS)->class )
-
-typedef struct
-{
-       uint8_t         type[ 2 ];
-       uint8_t         class[ 2 ];
-       uint8_t         ttl[ 4 ];
-       uint8_t         rdlength[ 2 ];
-       
-}      DNSRecordFixedFields;
-
-check_compile_time( sizeof( DNSRecordFixedFields ) == 10 );
-
-// SRV RDATA fixed-length fields. See <https://tools.ietf.org/html/rfc2782>.
-
-typedef struct
-{
-       uint8_t         priority[ 2 ];
-       uint8_t         weight[ 2 ];
-       uint8_t         port[ 2 ];
-       
-}      SRVRecordDataFixedFields;
-
-check_compile_time( sizeof( SRVRecordDataFixedFields ) == 6 );
-
-// SOA RDATA fixed-length fields. See <https://tools.ietf.org/html/rfc1035#section-3.3.13>.
-
-typedef struct
-{
-       uint8_t         serial[ 4 ];
-       uint8_t         refresh[ 4 ];
-       uint8_t         retry[ 4 ];
-       uint8_t         expire[ 4 ];
-       uint8_t         minimum[ 4 ];
-       
-}      SOARecordDataFixedFields;
-
-check_compile_time( sizeof( SOARecordDataFixedFields ) == 20 );
-
-// DNS message compression. See <https://tools.ietf.org/html/rfc1035#section-4.1.4>.
-
-#define kDNSCompressionOffsetMax               0x3FFF
-
-#define IsCompressionByte( X )         ( ( ( X ) & 0xC0 ) == 0xC0 )
-#define WriteDNSCompressionPtr( PTR, OFFSET )                                                                                  \
-       do                                                                                                                                                                      \
-       {                                                                                                                                                                       \
-               ( (uint8_t *)(PTR) )[ 0 ] = (uint8_t)( ( ( (OFFSET) >> 8 ) & 0x3F ) | 0xC0 );   \
-               ( (uint8_t *)(PTR) )[ 1 ] = (uint8_t)(     (OFFSET)        & 0xFF          );   \
-                                                                                                                                                                               \
-       }       while( 0 )
-
-#define NextLabel( LABEL )             ( ( (LABEL)[ 0 ] == 0 ) ? NULL : ( (LABEL) + 1 + (LABEL)[ 0 ] ) )
-
-//===========================================================================================================================
-//     mDNS
-//===========================================================================================================================
-
-#define kMDNSPort              5353
-
-#define kDefaultMDNSMessageID          0
-#define kDefaultMDNSQueryFlags         0
-
-#define kQClassUnicastResponseBit              ( 1U << 15 )
-#define kRRClassCacheFlushBit                  ( 1U << 15 )
-
-// Recommended Resource Record TTL values. See <https://tools.ietf.org/html/rfc6762#section-10>.
-
-#define kMDNSRecordTTL_Host                    120             // TTL for resource records related to a host name, e.g., A, AAAA, SRV, etc.
-#define kMDNSRecordTTL_Other           4500    // TTL for other resource records.
-
-// Maximum mDNS Message Size. See <https://tools.ietf.org/html/rfc6762#section-17>.
-
-#define kMDNSMessageSizeMax            8952    // 9000 B (Ethernet jumbo frame max size) - 40 B (IPv6 header) - 8 B (UDP header)
-
-#define kLocalStr                      "\x05" "local"
-#define kLocalName                     ( (const uint8_t *) kLocalStr )
-#define kLocalNameLen          sizeof( kLocalStr )
-
-//===========================================================================================================================
-//     Test Address Blocks
-//===========================================================================================================================
-
-// IPv4 address block 203.0.113.0/24 (TEST-NET-3) is reserved for documentation. See <https://tools.ietf.org/html/rfc5737>.
-
-#define kDNSServerBaseAddrV4           UINT32_C( 0xCB007100 )  // 203.0.113.0/24
-
-// IPv6 address block 2001:db8::/32 is reserved for documentation. See <https://tools.ietf.org/html/rfc3849>.
-
-static const uint8_t           kDNSServerBaseAddrV6[] =
-{
-       0x20, 0x01, 0x0D, 0xB8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // 2001:db8:1::/120
-};
-
-static const uint8_t           kMDNSReplierBaseAddrV6[] =
-{
-       0x20, 0x01, 0x0D, 0xB8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // 2001:db8:2::/96
-};
-
-check_compile_time( sizeof( kDNSServerBaseAddrV6 )   == 16 );
-check_compile_time( sizeof( kMDNSReplierBaseAddrV6 ) == 16 );
-
-// Bad IPv4 and IPv6 Address Blocks
-// Used by the DNS server when it needs to respond with intentionally "bad" A/AAAA record data, i.e., IP addresses neither
-// in 203.0.113.0/24 nor 2001:db8:1::/120.
-
-#define kDNSServerBadBaseAddrV4                UINT32_C( 0x00000000 )  // 0.0.0.0/24
-
-static const uint8_t           kDNSServerBadBaseAddrV6[] =
-{
-       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00  // ::ffff:0:0/120
-};
-
-check_compile_time( sizeof( kDNSServerBadBaseAddrV6 ) == 16 );
-
-//===========================================================================================================================
-//     Misc.
-//===========================================================================================================================
-
-#define kLowerAlphaNumericCharSet                      "abcdefghijklmnopqrstuvwxyz0123456789"
-#define kLowerAlphaNumericCharSetSize          sizeof_string( kLowerAlphaNumericCharSet )
-
-// Note: strcpy_literal() appears in CoreUtils code, but isn't currently defined in framework headers.
-
-#if( !defined( strcpy_literal ) )
-       #define strcpy_literal( DST, SRC )              memcpy( DST, SRC, sizeof( SRC ) )
-#endif
-
-#define _RandomStringExact( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, OUT_STRING ) \
-       RandomString( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, CHAR_COUNT, OUT_STRING )
-
-#define kNoSuchRecordStr                       "No Such Record"
-#define kNoSuchRecordAStr                      "No Such Record (A)"
-#define kNoSuchRecordAAAAStr           "No Such Record (AAAA)"
-
-#define kRootLabel             ( (const uint8_t *) "" )
-
-//===========================================================================================================================
-//     Gerneral Command Options
-//===========================================================================================================================
-
-// Command option macros
-
-#define Command( NAME, CALLBACK, SUB_OPTIONS, SHORT_HELP, IS_NOTCOMMON )                                                                                       \
-       CLI_COMMAND_EX( NAME, CALLBACK, SUB_OPTIONS, (IS_NOTCOMMON) ? kCLIOptionFlags_NotCommon : kCLIOptionFlags_None, \
-               (SHORT_HELP), NULL )
-
-#define kRequiredOptionSuffix          " [REQUIRED]"
-
-#define MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP )     \
-       CLI_OPTION_MULTI_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP,                                                                    \
-               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                                                                                          \
-               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
-
-#define MultiStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
-               MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
-
-#define IntegerOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED )     \
-       CLI_OPTION_INTEGER_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                                \
-               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                          \
-               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
-
-#define DoubleOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED )      \
-       CLI_OPTION_DOUBLE_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                                 \
-               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                          \
-               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
-
-#define BooleanOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP ) \
-       CLI_OPTION_BOOLEAN( (SHORT_CHAR), (LONG_NAME), (VAL_PTR), (SHORT_HELP), NULL )
-
-#define StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
-       CLI_OPTION_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                                                         \
-               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                                                  \
-               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
-
-#define StringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
-       StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
-
-#define CFStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED )    \
-       CLI_OPTION_CFSTRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                               \
-               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                          \
-               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
-
-// DNS-SD API flag options
-
-static int             gDNSSDFlags                                             = 0;
-static int             gDNSSDFlag_AllowExpiredAnswers  = false;
-static int             gDNSSDFlag_BrowseDomains                = false;
-static int             gDNSSDFlag_DenyCellular                 = false;
-static int             gDNSSDFlag_DenyExpensive                = false;
-static int             gDNSSDFlag_ForceMulticast               = false;
-static int             gDNSSDFlag_IncludeAWDL                  = false;
-static int             gDNSSDFlag_NoAutoRename                 = false;
-static int             gDNSSDFlag_PathEvaluationDone   = false;
-static int             gDNSSDFlag_RegistrationDomains  = false;
-static int             gDNSSDFlag_ReturnIntermediates  = false;
-static int             gDNSSDFlag_Shared                               = false;
-static int             gDNSSDFlag_SuppressUnusable             = false;
-static int             gDNSSDFlag_Timeout                              = false;
-static int             gDNSSDFlag_UnicastResponse              = false;
-static int             gDNSSDFlag_Unique                               = false;
-static int             gDNSSDFlag_WakeOnResolve                = false;
-
-#define DNSSDFlagsOption()                                                             \
-       IntegerOption( 'f', "flags", &gDNSSDFlags, "flags",     \
-               "DNSServiceFlags as an integer. This value is bitwise ORed with other single flag options.", false )
-
-#define DNSSDFlagOption( SHORT_CHAR, FLAG_NAME ) \
-       BooleanOption( SHORT_CHAR, # FLAG_NAME, &gDNSSDFlag_ ## FLAG_NAME, "Use kDNSServiceFlags" # FLAG_NAME "." )
-
-#define DNSSDFlagsOption_AllowExpiredAnswers()         DNSSDFlagOption( 'X', AllowExpiredAnswers )
-#define DNSSDFlagsOption_DenyCellular()                                DNSSDFlagOption( 'C', DenyCellular )
-#define DNSSDFlagsOption_DenyExpensive()                       DNSSDFlagOption( 'E', DenyExpensive )
-#define DNSSDFlagsOption_ForceMulticast()                      DNSSDFlagOption( 'M', ForceMulticast )
-#define DNSSDFlagsOption_IncludeAWDL()                         DNSSDFlagOption( 'A', IncludeAWDL )
-#define DNSSDFlagsOption_NoAutoRename()                                DNSSDFlagOption( 'N', NoAutoRename )
-#define DNSSDFlagsOption_PathEvalDone()                                DNSSDFlagOption( 'P', PathEvaluationDone )
-#define DNSSDFlagsOption_ReturnIntermediates()         DNSSDFlagOption( 'I', ReturnIntermediates )
-#define DNSSDFlagsOption_Shared()                                      DNSSDFlagOption( 'S', Shared )
-#define DNSSDFlagsOption_SuppressUnusable()                    DNSSDFlagOption( 'S', SuppressUnusable )
-#define DNSSDFlagsOption_Timeout()                                     DNSSDFlagOption( 'T', Timeout )
-#define DNSSDFlagsOption_UnicastResponse()                     DNSSDFlagOption( 'U', UnicastResponse )
-#define DNSSDFlagsOption_Unique()                                      DNSSDFlagOption( 'U', Unique )
-#define DNSSDFlagsOption_WakeOnResolve()                       DNSSDFlagOption( 'W', WakeOnResolve )
-
-// Interface option
-
-static const char *            gInterface = NULL;
-
-#define InterfaceOption()                                                                              \
-       StringOption( 'i', "interface", &gInterface, "interface",       \
-               "Network interface by name or index. Use index -1 for local-only.", false )
-
-// Connection options
-
-#define kConnectionArg_Normal                  ""
-#define kConnectionArgPrefix_PID               "pid:"
-#define kConnectionArgPrefix_UUID              "uuid:"
-
-static const char *            gConnectionOpt = kConnectionArg_Normal;
-
-#define ConnectionOptions()                                                                                                                                                                            \
-       { kCLIOptionType_String, 0, "connection", &gConnectionOpt, NULL, (intptr_t) kConnectionArg_Normal, "type",      \
-               kCLIOptionFlags_OptionalArgument, NULL, NULL, NULL, NULL,                                                                                               \
-               "Specifies the type of main connection to use. See " kConnectionSection_Name " below.", NULL }
-
-#define kConnectionSection_Name                "Connection Option"
-#define kConnectionSection_Text                                                                                                                                                                                        \
-       "The default behavior is to create a main connection with DNSServiceCreateConnection() and perform operations on\n"     \
-       "the main connection using the kDNSServiceFlagsShareConnection flag. This behavior can be explicitly invoked by\n"      \
-       "specifying the connection option without an argument, i.e.,\n"                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "    --connection\n"                                                                                                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "To instead use a delegate connection created with DNSServiceCreateDelegateConnection(), use\n"                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "    --connection=pid:<PID>\n"                                                                                                                                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "to specify the delegator by PID, or use\n"                                                                                                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "    --connection=uuid:<UUID>\n"                                                                                                                                                                        \
-       "\n"                                                                                                                                                                                                                            \
-       "to specify the delegator by UUID.\n"                                                                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "To not use a main connection at all, but instead perform operations on their own implicit connections, use\n"          \
-       "\n"                                                                                                                                                                                                                            \
-       "    --no-connection\n"
-
-#define ConnectionSection()            CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
-
-// Help text for record data options
-
-#define kRDataArgPrefix_Domain                 "domain:"
-#define kRDataArgPrefix_File                   "file:"
-#define kRDataArgPrefix_HexString              "hex:"
-#define kRDataArgPrefix_IPv4                   "ipv4:"
-#define kRDataArgPrefix_IPv6                   "ipv6:"
-#define kRDataArgPrefix_SRV                            "srv:"
-#define kRDataArgPrefix_String                 "string:"
-#define kRDataArgPrefix_TXT                            "txt:"
-
-#define kRecordDataSection_Name                "Record Data Arguments"
-#define kRecordDataSection_Text                                                                                                                                                                                        \
-       "A record data argument is specified in one of the following formats:\n"                                                                                        \
-       "\n"                                                                                                                                                                                                                            \
-       "Format                        Syntax                                   Example\n"                                                                      \
-       "Domain name                   domain:<domain name>                     domain:demo._test._tcp.local\n"                         \
-       "File containing record data   file:<file path>                         file:/path/to/rdata.bin\n"                                      \
-       "Hexadecimal string            hex:<hex string>                         hex:c0000201 or hex:'C0 00 02 01'\n"            \
-       "IPv4 address                  ipv4:<IPv4 address>                      ipv4:192.0.2.1\n"                                                       \
-       "IPv6 address                  ipv6:<IPv6 address>                      ipv6:2001:db8::1\n"                                                     \
-       "SRV record                    srv:<priority>,<weight>,<port>,<target>  srv:0,0,64206,example.local\n"                          \
-       "String (w/escaped hex bytes)  string:<string>                          string:'\\x09color=red'\n"                                      \
-       "TXT record keys and values    txt:<comma-delimited keys and values>    txt:'vers=1.0,lang=en\\,es\\,fr,passreq'\n"
-
-#define RecordDataSection()            CLI_SECTION( kRecordDataSection_Name, kRecordDataSection_Text )
-
-//===========================================================================================================================
-//     Output Formatting
-//===========================================================================================================================
-
-#define kOutputFormatStr_JSON          "json"
-#define kOutputFormatStr_XML           "xml"
-#define kOutputFormatStr_Binary                "binary"
-
-typedef enum
-{
-       kOutputFormatType_Invalid       = 0,
-       kOutputFormatType_JSON          = 1,
-       kOutputFormatType_XML           = 2,
-       kOutputFormatType_Binary        = 3
-       
-}      OutputFormatType;
-
-#define FormatOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP, IS_REQUIRED )                        \
-       StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, "format", SHORT_HELP, IS_REQUIRED,      \
-               "\n"                                                                                                                                                    \
-               "Use '" kOutputFormatStr_JSON   "' for JavaScript Object Notation (JSON).\n"    \
-               "Use '" kOutputFormatStr_XML    "' for property list XML version 1.0.\n"                \
-               "Use '" kOutputFormatStr_Binary "' for property list binary version 1.0.\n"             \
-               "\n"                                                                                                                                                    \
-       )
-
-//===========================================================================================================================
-//     Browse Command Options
-//===========================================================================================================================
-
-static char **                 gBrowse_ServiceTypes            = NULL;
-static size_t                  gBrowse_ServiceTypesCount       = 0;
-static const char *            gBrowse_Domain                          = NULL;
-static int                             gBrowse_DoResolve                       = false;
-static int                             gBrowse_QueryTXT                        = false;
-static int                             gBrowse_TimeLimitSecs           = 0;
-
-static CLIOption               kBrowseOpts[] =
-{
-       InterfaceOption(),
-       MultiStringOption(      't', "type",    &gBrowse_ServiceTypes, &gBrowse_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\".", true ),
-       StringOption(           'd', "domain",  &gBrowse_Domain, "domain", "Domain in which to browse for the service type(s).", false ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       DNSSDFlagsOption_IncludeAWDL(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       ConnectionOptions(),
-       BooleanOption(  0 , "resolve",          &gBrowse_DoResolve,             "Resolve service instances." ),
-       BooleanOption(  0 , "queryTXT",         &gBrowse_QueryTXT,              "Query TXT records of service instances." ),
-       IntegerOption( 'l', "timeLimit",        &gBrowse_TimeLimitSecs, "seconds", "Specifies the max duration of the browse operation. Use '0' for no time limit.", false ),
-       
-       ConnectionSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     GetAddrInfo Command Options
-//===========================================================================================================================
-
-static const char *            gGetAddrInfo_Name                       = NULL;
-static int                             gGetAddrInfo_ProtocolIPv4       = false;
-static int                             gGetAddrInfo_ProtocolIPv6       = false;
-static int                             gGetAddrInfo_OneShot            = false;
-static int                             gGetAddrInfo_TimeLimitSecs      = 0;
-
-static CLIOption               kGetAddrInfoOpts[] =
-{
-       InterfaceOption(),
-       StringOption(  'n', "name", &gGetAddrInfo_Name,                 "domain name", "Domain name to resolve.", true ),
-       BooleanOption(  0 , "ipv4", &gGetAddrInfo_ProtocolIPv4, "Use kDNSServiceProtocol_IPv4." ),
-       BooleanOption(  0 , "ipv6", &gGetAddrInfo_ProtocolIPv6, "Use kDNSServiceProtocol_IPv6." ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       DNSSDFlagsOption_AllowExpiredAnswers(),
-       DNSSDFlagsOption_DenyCellular(),
-       DNSSDFlagsOption_DenyExpensive(),
-       DNSSDFlagsOption_PathEvalDone(),
-       DNSSDFlagsOption_ReturnIntermediates(),
-       DNSSDFlagsOption_SuppressUnusable(),
-       DNSSDFlagsOption_Timeout(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       ConnectionOptions(),
-       BooleanOption( 'o', "oneshot",          &gGetAddrInfo_OneShot,                  "Finish after first set of results." ),
-       IntegerOption( 'l', "timeLimit",        &gGetAddrInfo_TimeLimitSecs,    "seconds", "Maximum duration of the GetAddrInfo operation. Use '0' for no time limit.", false ),
-       
-       ConnectionSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     QueryRecord Command Options
-//===========================================================================================================================
-
-static const char *            gQueryRecord_Name                       = NULL;
-static const char *            gQueryRecord_Type                       = NULL;
-static int                             gQueryRecord_OneShot            = false;
-static int                             gQueryRecord_TimeLimitSecs      = 0;
-static int                             gQueryRecord_RawRData           = false;
-
-static CLIOption               kQueryRecordOpts[] =
-{
-       InterfaceOption(),
-       StringOption( 'n', "name", &gQueryRecord_Name, "domain name", "Full domain name of record to query.", true ),
-       StringOption( 't', "type", &gQueryRecord_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       DNSSDFlagsOption_AllowExpiredAnswers(),
-       DNSSDFlagsOption_DenyCellular(),
-       DNSSDFlagsOption_DenyExpensive(),
-       DNSSDFlagsOption_ForceMulticast(),
-       DNSSDFlagsOption_IncludeAWDL(),
-       DNSSDFlagsOption_PathEvalDone(),
-       DNSSDFlagsOption_ReturnIntermediates(),
-       DNSSDFlagsOption_SuppressUnusable(),
-       DNSSDFlagsOption_Timeout(),
-       DNSSDFlagsOption_UnicastResponse(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       ConnectionOptions(),
-       BooleanOption( 'o', "oneshot",          &gQueryRecord_OneShot,                  "Finish after first set of results." ),
-       IntegerOption( 'l', "timeLimit",        &gQueryRecord_TimeLimitSecs,    "seconds", "Maximum duration of the query record operation. Use '0' for no time limit.", false ),
-       BooleanOption(  0 , "raw",                      &gQueryRecord_RawRData,                 "Show record data as a hexdump." ),
-       
-       ConnectionSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     Register Command Options
-//===========================================================================================================================
-
-static const char *                    gRegister_Name                  = NULL;
-static const char *                    gRegister_Type                  = NULL;
-static const char *                    gRegister_Domain                = NULL;
-static int                                     gRegister_Port                  = 0;
-static const char *                    gRegister_TXT                   = NULL;
-static int                                     gRegister_LifetimeMs    = -1;
-static const char **           gAddRecord_Types                = NULL;
-static size_t                          gAddRecord_TypesCount   = 0;
-static const char **           gAddRecord_Data                 = NULL;
-static size_t                          gAddRecord_DataCount    = 0;
-static const char **           gAddRecord_TTLs                 = NULL;
-static size_t                          gAddRecord_TTLsCount    = 0;
-static const char *                    gUpdateRecord_Data              = NULL;
-static int                                     gUpdateRecord_DelayMs   = 0;
-static int                                     gUpdateRecord_TTL               = 0;
-
-static CLIOption               kRegisterOpts[] =
-{
-       InterfaceOption(),
-       StringOption(  'n', "name",             &gRegister_Name,        "service name", "Name of service.", false ),
-       StringOption(  't', "type",             &gRegister_Type,        "service type", "Service type, e.g., \"_ssh._tcp\".", true ),
-       StringOption(  'd', "domain",   &gRegister_Domain,      "domain",               "Domain in which to advertise the service.", false ),
-       IntegerOption( 'p', "port",             &gRegister_Port,        "port number",  "Service's port number.", true ),
-       StringOption(   0 , "txt",              &gRegister_TXT,         "record data",  "The TXT record data. See " kRecordDataSection_Name " below.", false ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       DNSSDFlagsOption_IncludeAWDL(),
-       DNSSDFlagsOption_NoAutoRename(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       IntegerOption( 'l', "lifetime", &gRegister_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
-       
-       CLI_OPTION_GROUP( "Options for updating the registered service's primary TXT record with DNSServiceUpdateRecord()\n" ),
-       StringOption(  0 , "updateData",        &gUpdateRecord_Data,    "record data",  "Record data for the record update. See " kRecordDataSection_Name " below.", false ),
-       IntegerOption( 0 , "updateDelay",       &gUpdateRecord_DelayMs, "ms",                   "Number of milliseconds after registration to wait before record update.", false ),
-       IntegerOption( 0 , "updateTTL",         &gUpdateRecord_TTL,             "seconds",              "Time-to-live of the updated record.", false ),
-       
-       CLI_OPTION_GROUP( "Options for adding extra record(s) to the registered service with DNSServiceAddRecord()\n" ),
-       MultiStringOption(   0 , "addType",     &gAddRecord_Types,      &gAddRecord_TypesCount, "record type",  "Type of additional record by name (e.g., TXT, SRV, etc.) or number.", false ),
-       MultiStringOptionEx( 0 , "addData",     &gAddRecord_Data,       &gAddRecord_DataCount,  "record data",  "Additional record's data. See " kRecordDataSection_Name " below.", false, NULL ),
-       MultiStringOption(   0 , "addTTL",      &gAddRecord_TTLs,       &gAddRecord_TTLsCount,  "seconds",              "Time-to-live of additional record in seconds. Use '0' for default.", false ),
-       
-       RecordDataSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     RegisterRecord Command Options
-//===========================================================================================================================
-
-static const char *            gRegisterRecord_Name                    = NULL;
-static const char *            gRegisterRecord_Type                    = NULL;
-static const char *            gRegisterRecord_Data                    = NULL;
-static int                             gRegisterRecord_TTL                             = 0;
-static int                             gRegisterRecord_LifetimeMs              = -1;
-static const char *            gRegisterRecord_UpdateData              = NULL;
-static int                             gRegisterRecord_UpdateDelayMs   = 0;
-static int                             gRegisterRecord_UpdateTTL               = 0;
-
-static CLIOption               kRegisterRecordOpts[] =
-{
-       InterfaceOption(),
-       StringOption( 'n', "name",      &gRegisterRecord_Name,  "record name",  "Fully qualified domain name of record.", true ),
-       StringOption( 't', "type",      &gRegisterRecord_Type,  "record type",  "Record type by name (e.g., TXT, PTR, A) or number.", true ),
-       StringOption( 'd', "data",      &gRegisterRecord_Data,  "record data",  "The record data. See " kRecordDataSection_Name " below.", false ),
-       IntegerOption( 0 , "ttl",       &gRegisterRecord_TTL,   "seconds",              "Time-to-live in seconds. Use '0' for default.", false ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       DNSSDFlagsOption_IncludeAWDL(),
-       DNSSDFlagsOption_Shared(),
-       DNSSDFlagsOption_Unique(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       IntegerOption( 'l', "lifetime", &gRegisterRecord_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
-       
-       CLI_OPTION_GROUP( "Options for updating the registered record with DNSServiceUpdateRecord()\n" ),
-       StringOption(  0 , "updateData",        &gRegisterRecord_UpdateData,    "record data",  "Record data for the record update.", false ),
-       IntegerOption( 0 , "updateDelay",       &gRegisterRecord_UpdateDelayMs, "ms",                   "Number of milliseconds after registration to wait before record update.", false ),
-       IntegerOption( 0 , "updateTTL",         &gRegisterRecord_UpdateTTL,             "seconds",              "Time-to-live of the updated record.", false ),
-       
-       RecordDataSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     Resolve Command Options
-//===========================================================================================================================
-
-static char *          gResolve_Name                   = NULL;
-static char *          gResolve_Type                   = NULL;
-static char *          gResolve_Domain                 = NULL;
-static int                     gResolve_TimeLimitSecs  = 0;
-
-static CLIOption               kResolveOpts[] =
-{
-       InterfaceOption(),
-       StringOption( 'n', "name",              &gResolve_Name,         "service name", "Name of the service instance to resolve.", true ),
-       StringOption( 't', "type",              &gResolve_Type,         "service type", "Type of the service instance to resolve.", true ),
-       StringOption( 'd', "domain",    &gResolve_Domain,       "domain", "Domain of the service instance to resolve.", true ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       DNSSDFlagsOption_ForceMulticast(),
-       DNSSDFlagsOption_IncludeAWDL(),
-       DNSSDFlagsOption_ReturnIntermediates(),
-       DNSSDFlagsOption_WakeOnResolve(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       ConnectionOptions(),
-       IntegerOption( 'l', "timeLimit", &gResolve_TimeLimitSecs, "seconds", "Maximum duration of the resolve operation. Use '0' for no time limit.", false ),
-       
-       ConnectionSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     Reconfirm Command Options
-//===========================================================================================================================
-
-static const char *            gReconfirmRecord_Name   = NULL;
-static const char *            gReconfirmRecord_Type   = NULL;
-static const char *            gReconfirmRecord_Class  = NULL;
-static const char *            gReconfirmRecord_Data   = NULL;
-
-static CLIOption               kReconfirmOpts[] =
-{
-       InterfaceOption(),
-       StringOption( 'n', "name",      &gReconfirmRecord_Name,         "record name",  "Full name of the record to reconfirm.", true ),
-       StringOption( 't', "type",      &gReconfirmRecord_Type,         "record type",  "Type of the record to reconfirm.", true ),
-       StringOption( 'c', "class",     &gReconfirmRecord_Class,        "record class", "Class of the record to reconfirm. Default class is IN.", false ),
-       StringOption( 'd', "data",      &gReconfirmRecord_Data,         "record data",  "The record data. See " kRecordDataSection_Name " below.", false ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       
-       RecordDataSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     getaddrinfo-POSIX Command Options
-//===========================================================================================================================
-
-static const char *            gGAIPOSIX_HostName                      = NULL;
-static const char *            gGAIPOSIX_ServName                      = NULL;
-static const char *            gGAIPOSIX_Family                        = NULL;
-static int                             gGAIPOSIXFlag_AddrConfig        = false;
-static int                             gGAIPOSIXFlag_All                       = false;
-static int                             gGAIPOSIXFlag_CanonName         = false;
-static int                             gGAIPOSIXFlag_NumericHost       = false;
-static int                             gGAIPOSIXFlag_NumericServ       = false;
-static int                             gGAIPOSIXFlag_Passive           = false;
-static int                             gGAIPOSIXFlag_V4Mapped          = false;
-#if( defined( AI_V4MAPPED_CFG ) )
-static int                             gGAIPOSIXFlag_V4MappedCFG       = false;
-#endif
-#if( defined( AI_DEFAULT ) )
-static int                             gGAIPOSIXFlag_Default           = false;
-#endif
-#if( defined( AI_UNUSABLE ) )
-static int                             gGAIPOSIXFlag_Unusable          = false;
-#endif
-
-static CLIOption               kGetAddrInfoPOSIXOpts[] =
-{
-       StringOption(   'n', "hostname",                        &gGAIPOSIX_HostName,            "hostname", "Domain name to resolve or an IPv4 or IPv6 address.", true ),
-       StringOption(   's', "servname",                        &gGAIPOSIX_ServName,            "servname", "Port number in decimal or service name from services(5).", false ),
-       
-       CLI_OPTION_GROUP( "Hints" ),
-       StringOptionEx( 'f', "family",                          &gGAIPOSIX_Family,                      "address family", "Address family to use for hints ai_family field.", false,
-               "\n"
-               "Possible address family values are 'inet' for AF_INET, 'inet6' for AF_INET6, or 'unspec' for AF_UNSPEC. If no\n"
-               "address family is specified, then AF_UNSPEC is used.\n"
-               "\n" ),
-       BooleanOption(   0 , "flag-addrconfig",         &gGAIPOSIXFlag_AddrConfig,      "In hints ai_flags field, set AI_ADDRCONFIG." ),
-       BooleanOption(   0 , "flag-all",                        &gGAIPOSIXFlag_All,                     "In hints ai_flags field, set AI_ALL." ),
-       BooleanOption(   0 , "flag-canonname",          &gGAIPOSIXFlag_CanonName,       "In hints ai_flags field, set AI_CANONNAME." ),
-       BooleanOption(   0 , "flag-numerichost",        &gGAIPOSIXFlag_NumericHost,     "In hints ai_flags field, set AI_NUMERICHOST." ),
-       BooleanOption(   0 , "flag-numericserv",        &gGAIPOSIXFlag_NumericServ,     "In hints ai_flags field, set AI_NUMERICSERV." ),
-       BooleanOption(   0 , "flag-passive",            &gGAIPOSIXFlag_Passive,         "In hints ai_flags field, set AI_PASSIVE." ),
-       BooleanOption(   0 , "flag-v4mapped",           &gGAIPOSIXFlag_V4Mapped,        "In hints ai_flags field, set AI_V4MAPPED." ),
-#if( defined( AI_V4MAPPED_CFG ) )
-       BooleanOption(   0 , "flag-v4mappedcfg",        &gGAIPOSIXFlag_V4MappedCFG,     "In hints ai_flags field, set AI_V4MAPPED_CFG." ),
-#endif
-#if( defined( AI_DEFAULT ) )
-       BooleanOption(   0 , "flag-default",            &gGAIPOSIXFlag_Default,         "In hints ai_flags field, set AI_DEFAULT." ),
-#endif
-#if( defined( AI_UNUSABLE ) )
-       BooleanOption(   0 , "flag-unusable",           &gGAIPOSIXFlag_Unusable,        "In hints ai_flags field, set AI_UNUSABLE." ),
-#endif
-       
-       CLI_SECTION( "Notes", "See getaddrinfo(3) man page for more details.\n" ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     ReverseLookup Command Options
-//===========================================================================================================================
-
-static const char *            gReverseLookup_IPAddr                   = NULL;
-static int                             gReverseLookup_OneShot                  = false;
-static int                             gReverseLookup_TimeLimitSecs    = 0;
-
-static CLIOption               kReverseLookupOpts[] =
-{
-       InterfaceOption(),
-       StringOption( 'a', "address", &gReverseLookup_IPAddr, "IP address", "IPv4 or IPv6 address for which to perform a reverse IP lookup.", true ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       DNSSDFlagsOption_ForceMulticast(),
-       DNSSDFlagsOption_ReturnIntermediates(),
-       DNSSDFlagsOption_SuppressUnusable(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       ConnectionOptions(),
-       BooleanOption( 'o', "oneshot",          &gReverseLookup_OneShot,                "Finish after first set of results." ),
-       IntegerOption( 'l', "timeLimit",        &gReverseLookup_TimeLimitSecs,  "seconds", "Specifies the max duration of the query record operation. Use '0' for no time limit.", false ),
-       
-       ConnectionSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     PortMapping Command Options
-//===========================================================================================================================
-
-static int             gPortMapping_ProtocolTCP        = false;
-static int             gPortMapping_ProtocolUDP        = false;
-static int             gPortMapping_InternalPort       = 0;
-static int             gPortMapping_ExternalPort       = 0;
-static int             gPortMapping_TTL                        = 0;
-
-static CLIOption               kPortMappingOpts[] =
-{
-       InterfaceOption(),
-       BooleanOption( 0, "tcp",                        &gPortMapping_ProtocolTCP,      "Use kDNSServiceProtocol_TCP." ),
-       BooleanOption( 0, "udp",                        &gPortMapping_ProtocolUDP,      "Use kDNSServiceProtocol_UDP." ),
-       IntegerOption( 0, "internalPort",       &gPortMapping_InternalPort,     "port number", "Internal port.", false ),
-       IntegerOption( 0, "externalPort",       &gPortMapping_ExternalPort,     "port number", "Requested external port. Use '0' for any external port.", false ),
-       IntegerOption( 0, "ttl",                        &gPortMapping_TTL,                      "seconds", "Requested TTL (renewal period) in seconds. Use '0' for a default value.", false ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       ConnectionOptions(),
-       
-       ConnectionSection(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     BrowseAll Command Options
-//===========================================================================================================================
-
-static const char *            gBrowseAll_Domain                               = NULL;
-static const char **   gBrowseAll_ServiceTypes                 = NULL;
-static size_t                  gBrowseAll_ServiceTypesCount    = 0;
-static int                             gBrowseAll_BrowseTimeSecs               = 5;
-static int                             gBrowseAll_ConnectTimeout               = 0;
-
-static CLIOption               kBrowseAllOpts[] =
-{
-       InterfaceOption(),
-       StringOption(      'd', "domain", &gBrowseAll_Domain, "domain", "Domain in which to browse for the service.", false ),
-       MultiStringOption( 't', "type",   &gBrowseAll_ServiceTypes, &gBrowseAll_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\". All services are browsed for if none is specified.", false ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption_IncludeAWDL(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       IntegerOption( 'b', "browseTime",     &gBrowseAll_BrowseTimeSecs, "seconds", "Amount of time to spend browsing in seconds. (default: 5)", false ),
-       IntegerOption( 'c', "connectTimeout", &gBrowseAll_ConnectTimeout, "seconds", "Timeout for connection attempts. If <= 0, no connections are attempted. (default: 0)", false ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     GetNameInfo Command Options
-//===========================================================================================================================
-
-static void    GetNameInfoCmd( void );
-
-static char *          gGetNameInfo_IPAddress                  = NULL;
-static int                     gGetNameInfoFlag_DGram                  = false;
-static int                     gGetNameInfoFlag_NameReqd               = false;
-static int                     gGetNameInfoFlag_NoFQDN                 = false;
-static int                     gGetNameInfoFlag_NumericHost    = false;
-static int                     gGetNameInfoFlag_NumericScope   = false;
-static int                     gGetNameInfoFlag_NumericServ    = false;
-
-static CLIOption               kGetNameInfoOpts[] =
-{
-       StringOption( 'a', "address",           &gGetNameInfo_IPAddress,        "IP address", "IPv4 or IPv6 address to use in sockaddr structure.", true ),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       BooleanOption( 0 , "flag-dgram",        &gGetNameInfoFlag_DGram,        "Use NI_DGRAM flag." ),
-       BooleanOption( 0 , "flag-namereqd",     &gGetNameInfoFlag_NameReqd,     "Use NI_NAMEREQD flag." ),
-       BooleanOption( 0 , "flag-nofqdn",       &gGetNameInfoFlag_NoFQDN,       "Use NI_NOFQDN flag." ),
-       BooleanOption( 0 , "flag-numerichost",  &gGetNameInfoFlag_NumericHost,  "Use NI_NUMERICHOST flag." ),
-       BooleanOption( 0 , "flag-numericscope", &gGetNameInfoFlag_NumericScope, "Use NI_NUMERICSCOPE flag." ),
-       BooleanOption( 0 , "flag-numericserv",  &gGetNameInfoFlag_NumericServ,  "Use NI_NUMERICSERV flag." ),
-       
-       CLI_SECTION( "Notes", "See getnameinfo(3) man page for more details.\n" ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     GetAddrInfoStress Command Options
-//===========================================================================================================================
-
-static int             gGAIStress_TestDurationSecs     = 0;
-static int             gGAIStress_ConnectionCount      = 0;
-static int             gGAIStress_DurationMinMs        = 0;
-static int             gGAIStress_DurationMaxMs        = 0;
-static int             gGAIStress_RequestCountMax      = 0;
-
-static CLIOption               kGetAddrInfoStressOpts[] =
-{
-       InterfaceOption(),
-       
-       CLI_OPTION_GROUP( "Flags" ),
-       DNSSDFlagsOption_ReturnIntermediates(),
-       DNSSDFlagsOption_SuppressUnusable(),
-       
-       CLI_OPTION_GROUP( "Operation" ),
-       IntegerOption( 0, "testDuration",                       &gGAIStress_TestDurationSecs,   "seconds",      "Stress test duration in seconds. Use '0' for forever.", false ),
-       IntegerOption( 0, "connectionCount",            &gGAIStress_ConnectionCount,    "integer",      "Number of simultaneous DNS-SD connections.", true ),
-       IntegerOption( 0, "requestDurationMin",         &gGAIStress_DurationMinMs,              "ms",           "Minimum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
-       IntegerOption( 0, "requestDurationMax",         &gGAIStress_DurationMaxMs,              "ms",           "Maximum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
-       IntegerOption( 0, "consecutiveRequestMax",      &gGAIStress_RequestCountMax,    "integer",      "Maximum number of requests on a connection before restarting it.", true ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     DNSQuery Command Options
-//===========================================================================================================================
-
-static char *          gDNSQuery_Name                  = NULL;
-static char *          gDNSQuery_Type                  = "A";
-static char *          gDNSQuery_Server                = NULL;
-static int                     gDNSQuery_TimeLimitSecs = 5;
-static int                     gDNSQuery_UseTCP                = false;
-static int                     gDNSQuery_Flags                 = kDNSHeaderFlag_RecursionDesired;
-static int                     gDNSQuery_RawRData              = false;
-static int                     gDNSQuery_Verbose               = false;
-
-#if( TARGET_OS_DARWIN )
-       #define kDNSQueryServerOptionIsRequired         false
-#else
-       #define kDNSQueryServerOptionIsRequired         true
-#endif
-
-static CLIOption               kDNSQueryOpts[] =
-{
-       StringOption(  'n', "name",                     &gDNSQuery_Name,                        "name", "Question name (QNAME) to put in DNS query message.", true ),
-       StringOption(  't', "type",                     &gDNSQuery_Type,                        "type", "Question type (QTYPE) to put in DNS query message. Default value is 'A'.", false ),
-       StringOption(  's', "server",           &gDNSQuery_Server,                      "IP address", "DNS server's IPv4 or IPv6 address.", kDNSQueryServerOptionIsRequired ),
-       IntegerOption( 'l', "timeLimit",        &gDNSQuery_TimeLimitSecs,       "seconds", "Specifies query time limit. Use '-1' for no limit and '0' to exit immediately after sending.", false ),
-       BooleanOption(  0 , "tcp",                      &gDNSQuery_UseTCP,                      "Send the DNS query via TCP instead of UDP." ),
-       IntegerOption( 'f', "flags",            &gDNSQuery_Flags,                       "flags", "16-bit value for DNS header flags/codes field. Default value is 0x0100 (Recursion Desired).", false ),
-       BooleanOption(  0 , "raw",                      &gDNSQuery_RawRData,            "Present record data as a hexdump." ),
-       BooleanOption( 'v', "verbose",          &gDNSQuery_Verbose,                     "Prints the DNS message to be sent to the server." ),
-       CLI_OPTION_END()
-};
-
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-//===========================================================================================================================
-//     DNSCrypt Command Options
-//===========================================================================================================================
-
-static char *          gDNSCrypt_ProviderName  = NULL;
-static char *          gDNSCrypt_ProviderKey   = NULL;
-static char *          gDNSCrypt_Name                  = NULL;
-static char *          gDNSCrypt_Type                  = NULL;
-static char *          gDNSCrypt_Server                = NULL;
-static int                     gDNSCrypt_TimeLimitSecs = 5;
-static int                     gDNSCrypt_RawRData              = false;
-static int                     gDNSCrypt_Verbose               = false;
-
-static CLIOption               kDNSCryptOpts[] =
-{
-       StringOption(  'p', "providerName",     &gDNSCrypt_ProviderName,        "name", "The DNSCrypt provider name.", true ),
-       StringOption(  'k', "providerKey",      &gDNSCrypt_ProviderKey,         "hex string", "The DNSCrypt provider's public signing key.", true ),
-       StringOption(  'n', "name",                     &gDNSCrypt_Name,                        "name", "Question name (QNAME) to put in DNS query message.", true ),
-       StringOption(  't', "type",                     &gDNSCrypt_Type,                        "type", "Question type (QTYPE) to put in DNS query message.", true ),
-       StringOption(  's', "server",           &gDNSCrypt_Server,                      "IP address", "DNS server's IPv4 or IPv6 address.", true ),
-       IntegerOption( 'l', "timeLimit",        &gDNSCrypt_TimeLimitSecs,       "seconds", "Specifies query time limit. Use '-1' for no time limit and '0' to exit immediately after sending.", false ),
-       BooleanOption(  0 , "raw",                      &gDNSCrypt_RawRData,            "Present record data as a hexdump." ),
-       BooleanOption( 'v', "verbose",          &gDNSCrypt_Verbose,                     "Prints the DNS message to be sent to the server." ),
-       CLI_OPTION_END()
-};
-#endif
-
-//===========================================================================================================================
-//     MDNSQuery Command Options
-//===========================================================================================================================
-
-static char *          gMDNSQuery_Name                 = NULL;
-static char *          gMDNSQuery_Type                 = NULL;
-static int                     gMDNSQuery_SourcePort   = 0;
-static int                     gMDNSQuery_IsQU                 = false;
-static int                     gMDNSQuery_RawRData             = false;
-static int                     gMDNSQuery_UseIPv4              = false;
-static int                     gMDNSQuery_UseIPv6              = false;
-static int                     gMDNSQuery_AllResponses = false;
-static int                     gMDNSQuery_ReceiveSecs  = 1;
-
-static CLIOption               kMDNSQueryOpts[] =
-{
-       StringOption(  'i', "interface",        &gInterface,                            "name or index", "Network interface by name or index.", true ),
-       StringOption(  'n', "name",                     &gMDNSQuery_Name,                       "name", "Question name (QNAME) to put in mDNS message.", true ),
-       StringOption(  't', "type",                     &gMDNSQuery_Type,                       "type", "Question type (QTYPE) to put in mDNS message.", true ),
-       IntegerOption( 'p', "sourcePort",       &gMDNSQuery_SourcePort,         "port number", "UDP source port to use when sending mDNS messages. Default is 5353 for QM questions.", false ),
-       BooleanOption( 'u', "QU",                       &gMDNSQuery_IsQU,                       "Set the unicast-response bit, i.e., send a QU question." ),
-       BooleanOption(  0 , "raw",                      &gMDNSQuery_RawRData,           "Present record data as a hexdump." ),
-       BooleanOption(  0 , "ipv4",                     &gMDNSQuery_UseIPv4,            "Use IPv4." ),
-       BooleanOption(  0 , "ipv6",                     &gMDNSQuery_UseIPv6,            "Use IPv6." ),
-       BooleanOption( 'a', "allResponses",     &gMDNSQuery_AllResponses,       "Print all received mDNS messages, not just those containing answers." ),
-       IntegerOption( 'r', "receiveTime",      &gMDNSQuery_ReceiveSecs,        "seconds", "Amount of time to spend receiving messages after the query is sent. The default is one second. Use -1 for unlimited time.", false ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     MDNSCollider Command Options
-//===========================================================================================================================
-
-#define kMDNSColliderProgramSection_Intro                                                                                                                                                              \
-       "Programs dictate when the collider sends out unsolicited response messages for its record and how the collider\n"      \
-       "ought to react to probe queries that match its record's name, if at all.\n"                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "For example, suppose that the goal is to cause a specific unique record in the verified state to be renamed.\n"        \
-       "The collider should be invoked such that its record's name is equal to that of the record being targeted. Also,\n"     \
-       "the record's type and data should be such that no record with that name, type, and data combination currently\n"       \
-       "exists. If the mDNS responder that owns the record follows sections 8.1 and 9 of RFC 6762, then the goal can be\n"     \
-       "accomplished with the following program:\n"                                                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "    probes 3r; send; wait 5000\n"                                                                                                                                                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "The first command, 'probes 3r', tells the collider to respond to the next three probe queries that match its\n"        \
-       "record's name. The second command, makes the collider send an unsolicited response message that contains its\n"        \
-       "record in the answer section. The third command makes the collider wait for five seconds before exiting, which\n"      \
-       "is more than enough time for the collider to respond to probe queries.\n"                                                                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "The send command will cause the targeted record to go into the probing state per section 9 since the collider's\n"     \
-       "record conflicts with target record. Per the probes command, the subsequent probe query sent during the probing\n"     \
-       "state will be answered by the collider, which will cause the record to be renamed per section 8.1.\n"
-
-#define kMDNSColliderProgramSection_Probes                                                                                                                                                             \
-       "The probes command defines how the collider ought to react to probe queries that match its record's name.\n"           \
-       "\n"                                                                                                                                                                                                                            \
-       "Usage: probes [<action-string>]\n"                                                                                                                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "The syntax for an action-string is\n"                                                                                                                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "    <action-string> ::= <action> | <action-string> \"-\" <action>\n"                                                                                           \
-       "    <action>        ::= [<repeat-count>] <action-code>\n"                                                                                                                      \
-       "    <repeat-count>  ::= \"1\" | \"2\" | ... | \"10\"\n"                                                                                                                        \
-       "    <action-code>   ::= \"n\" | \"r\" | \"u\" | \"m\" | \"p\"\n"                                                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "An expanded action-string is defined as\n"                                                                                                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "    <expanded-action-string> ::= <action-code> | <expanded-action-string> \"-\" <action-code>\n"                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "The action-string argument is converted into an expanded-action-string by expanding each action with a\n"                      \
-       "repeat-count into an expanded-action-string consisting of exactly <repeat-count> <action-code>s. For example,\n"       \
-       "2n-r expands to n-n-r. Action-strings that expand to expanded-action-strings with more than 10 action-codes\n"         \
-       "are not allowed.\n"                                                                                                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "When the probes command is executed, it does two things. Firstly, it resets to zero the collider's count of\n"         \
-       "probe queries that match its record's name. Secondly, it defines how the collider ought to react to such probe\n"      \
-       "queries based on the action-string argument. Specifically, the nth action-code in the expanded version of the\n"       \
-       "action-string argument defines how the collider ought to react to the nth received probe query:\n"                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "    Code  Action\n"                                                                                                                                                                                            \
-       "    ----  ------\n"                                                                                                                                                                                            \
-       "    n     Do nothing.\n"                                                                                                                                                                                       \
-       "    r     Respond to the probe query.\n"                                                                                                                                                       \
-       "    u     Respond to the probe query via unicast.\n"                                                                                                                           \
-       "    m     Respond to the probe query via multicast.\n"                                                                                                                         \
-       "    p     Multicast own probe query. (Useful for causing simultaneous probe scenarios.)\n"                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "Note: If no action is defined for a received probe query, then the collider does nothing, i.e., it doesn't send\n"     \
-       "a response nor does it multicast its own probe query.\n"
-
-#define kMDNSColliderProgramSection_Send                                                                                                                                                               \
-       "The send command multicasts an unsolicited mDNS response containing the collider's record in the answer\n"                     \
-       "section, which can be used to force unique records with the same record name into the probing state.\n"                        \
-       "\n"                                                                                                                                                                                                                            \
-       "Usage: send\n"
-
-#define kMDNSColliderProgramSection_Wait                                                                                                                                                               \
-       "The wait command pauses program execution for the interval of time specified by its argument.\n"                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "Usage: wait <milliseconds>\n"
-
-#define kMDNSColliderProgramSection_Loop                                                                                                                                                               \
-       "The loop command starts a counting loop. The done statement marks the end of the loop body. The loop command's\n"      \
-       "argument specifies the number of loop iterations. Note: Loop nesting is supported up to a depth of 16.\n"                      \
-       "\n"                                                                                                                                                                                                                            \
-       "Usage: loop <non-zero count>; ... ; done\n"                                                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "For example, the following program sends three unsolicited responses at an approximate rate of one per second:\n"      \
-       "\n"                                                                                                                                                                                                                            \
-       "    loop 3; wait 1000; send; done"
-
-#define ConnectionSection()            CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
-
-static const char *            gMDNSCollider_Name                      = NULL;
-static const char *            gMDNSCollider_Type                      = NULL;
-static const char *            gMDNSCollider_RecordData        = NULL;
-static int                             gMDNSCollider_UseIPv4           = false;
-static int                             gMDNSCollider_UseIPv6           = false;
-static const char *            gMDNSCollider_Program           = NULL;
-
-static CLIOption               kMDNSColliderOpts[] =
-{
-       StringOption(  'i', "interface", &gInterface,               "name or index", "Network interface by name or index.", true ),
-       StringOption(  'n', "name",      &gMDNSCollider_Name,       "name", "Collider's record name.", true ),
-       StringOption(  't', "type",      &gMDNSCollider_Type,       "type", "Collider's record type.", true ),
-       StringOption(  'd', "data",      &gMDNSCollider_RecordData, "record data", "Collider's record data. See " kRecordDataSection_Name " below.", true ),
-       StringOption(  'p', "program",   &gMDNSCollider_Program,    "program", "Program to execute. See Program section below.", true ),
-       BooleanOption(  0 , "ipv4",      &gMDNSCollider_UseIPv4,    "Use IPv4." ),
-       BooleanOption(  0 , "ipv6",      &gMDNSCollider_UseIPv6,    "Use IPv6." ),
-       
-       RecordDataSection(),
-       CLI_SECTION( "Program",                                 kMDNSColliderProgramSection_Intro ),
-       CLI_SECTION( "Program Command: probes", kMDNSColliderProgramSection_Probes ),
-       CLI_SECTION( "Program Command: send",   kMDNSColliderProgramSection_Send ),
-       CLI_SECTION( "Program Command: wait",   kMDNSColliderProgramSection_Wait ),
-       CLI_SECTION( "Program Command: loop",   kMDNSColliderProgramSection_Loop ),
-       CLI_OPTION_END()
-};
-
-static void    MDNSColliderCmd( void );
-
-//===========================================================================================================================
-//     PIDToUUID Command Options
-//===========================================================================================================================
-
-static int             gPIDToUUID_PID = 0;
-
-static CLIOption               kPIDToUUIDOpts[] =
-{
-       IntegerOption( 'p', "pid", &gPIDToUUID_PID, "PID", "Process ID.", true ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     DNSServer Command Options
-//===========================================================================================================================
-
-#define kDNSServerInfoText_Intro                                                                                                                                                                               \
-       "The DNS server answers certain queries in the d.test. domain. Responses are dynamically generated based on the\n"      \
-       "presence of special labels in the query's QNAME. There are currently eight types of special labels that can be\n"      \
-       "used to generate specific responses: Alias labels, Alias-TTL labels, Count labels, Tag labels, TTL labels, the\n"      \
-       "IPv4 label, the IPv6 label, and SRV labels.\n"                                                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
-
-#define kDNSServerInfoText_NameExistence                                                                                                                                                               \
-       "A name is considered to exist if it's an Address name or an SRV name.\n"                                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "An Address name is defined as a name that ends with d.test., and the other labels, if any, and in no particular\n"     \
-       "order, unless otherwise noted, consist of\n"                                                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. at most one Alias or Alias-TTL label as the first label;\n"                                                                                                     \
-       "    2. at most one Count label;\n"                                                                                                                                                                     \
-       "    3. zero or more Tag labels;\n"                                                                                                                                                                     \
-       "    4. at most one TTL label; and\n"                                                                                                                                                           \
-       "    5. at most one IPv4 or IPv6 label.\n"                                                                                                                                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "An SRV name is defined as a name with the following form:\n"                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       " _<service>._<proto>[.<parent domain>][.<SRV label 1>[.<target 1>][.<SRV label 2>[.<target 2>][...]]].d.test.\n"       \
-       "\n"                                                                                                                                                                                                                            \
-       "See \"SRV Names\" for details.\n"
-
-#define kDNSServerInfoText_ResourceRecords                                                                                                                                                             \
-       "Currently, the server only supports CNAME, A, AAAA, and SRV records.\n"                                                                                        \
-       "\n"                                                                                                                                                                                                                            \
-       "Address names that begin with an Alias or Alias-TTL label are aliases of canonical names, i.e., they're the\n"         \
-       "names of CNAME records. See \"Alias Labels\" and \"Alias-TTL Labels\" for details.\n"                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "A canonical Address name can exclusively be the name of one or more A records, can exclusively be the name or\n"       \
-       "one or more AAAA records, or can be the name of both A and AAAA records. Address names that contain an IPv4\n"         \
-       "label have at least one A record, but no AAAA records. Address names that contain an IPv6 label, have at least\n"      \
-       "one AAAA record, but no A records. All other Address names have at least one A record and at least one AAAA\n"         \
-       "record. See \"Count Labels\" for how the number of address records for a given Address name is determined.\n"          \
-       "\n"                                                                                                                                                                                                                            \
-       "A records contain IPv4 addresses in the 203.0.113.0/24 block, while AAAA records contain IPv6 addresses in the\n"      \
-       "2001:db8:1::/120 block. Both of these address blocks are reserved for documentation. See\n"                                                    \
-       "<https://tools.ietf.org/html/rfc5737> and <https://tools.ietf.org/html/rfc3849>.\n"                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "SRV names are names of SRV records.\n"                                                                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "Unless otherwise specified, all resource records will use a default TTL. The default TTL can be set with the\n"        \
-       "--defaultTTL option. See \"Alias-TTL Labels\" and \"TTL Labels\" for details on how to query for CNAME, A, and\n"      \
-       "AAAA records with specific TTL values.\n"
-
-#define kDNSServerInfoText_AliasLabel                                                                                                                                                                  \
-       "Alias labels are of the form \"alias\" or \"alias-N\", where N is an integer in [2, 2^31 - 1].\n"                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an Address name and its first label is Alias label \"alias-N\", then the response will contain\n"          \
-       "exactly N CNAME records:\n"                                                                                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. For each i in [3, N], the response will contain a CNAME record whose name is identical to QNAME, except\n"      \
-       "       that the first label is \"alias-i\" instead, and whose RDATA is the name of the other CNAME record whose\n"     \
-       "       name has \"alias-(i - 1)\" as its first label.\n"                                                                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n"       \
-       "       is \"alias-2\" instead, and whose RDATA is the name identical to QNAME, except that the first label is\n"       \
-       "       \"alias\" instead.\n"                                                                                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "    3. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n"       \
-       "       is \"alias\" instead, and whose RDATA is the name identical to QNAME minus its first label.\n"                          \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an Address name and its first label is Alias label \"alias\", then the response will contain a\n"          \
-       "single CNAME record. The CNAME record's name will be equal to QNAME and its RDATA will be the name identical to\n"     \
-       "QNAME minus its first label.\n"                                                                                                                                                                        \
-       "\n"                                                                                                                                                                                                                            \
-       "Example. A response to a query with a QNAME of alias-3.count-5.d.test will contain the following CNAME\n"                      \
-       "records:\n"                                                                                                                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "    alias-4.count-5.d.test.                        60    IN CNAME alias-3.count-5.d.test.\n"                                           \
-       "    alias-3.count-5.d.test.                        60    IN CNAME alias-2.count-5.d.test.\n"                                           \
-       "    alias-2.count-5.d.test.                        60    IN CNAME alias.count-5.d.test.\n"                                                     \
-       "    alias.count-5.d.test.                          60    IN CNAME count-5.d.test.\n"
-
-#define kDNSServerInfoText_AliasTTLLabel                                                                                                                                                               \
-       "Alias-TTL labels are of the form \"alias-ttl-T_1[-T_2[...-T_N]]\", where each T_i is an integer in\n"                          \
-       "[0, 2^31 - 1] and N is a positive integer bounded by the size of the maximum legal label length (63 octets).\n"        \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an Address name and its first label is Alias-TTL label \"alias-ttl-T_1...-T_N\", then the response\n"      \
-       "will contain exactly N CNAME records:\n"                                                                                                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. For each i in [1, N - 1], the response will contain a CNAME record whose name is identical to QNAME,\n"         \
-       "       except that the first label is \"alias-ttl-T_i...-T_N\" instead, whose TTL value is T_i, and whose RDATA\n"     \
-       "       is the name of the other CNAME record whose name has \"alias-ttl-T_(i+1)...-T_N\" as its first label.\n"        \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n"       \
-       "       is \"alias-ttl-T_N\", whose TTL is T_N, and whose RDATA is identical to QNAME stripped of its first\n"          \
-       "       label.\n"                                                                                                                                                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "Example. A response to a query with a QNAME of alias-ttl-20-40-80.count-5.d.test will contain the following\n"         \
-       "CNAME records:\n"                                                                                                                                                                                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "    alias-ttl-20-40-80.count-5.d.test.             20    IN CNAME alias-ttl-40-80.count-5.d.test.\n"                           \
-       "    alias-ttl-40-80.count-5.d.test.                40    IN CNAME alias-ttl-80.count-5.d.test.\n"                                      \
-       "    alias-ttl-80.count-5.d.test.                   80    IN CNAME count-5.d.test.\n"
-
-#define kDNSServerInfoText_CountLabel                                                                                                                                                                  \
-       "Count labels are of the form \"count-N_1\" or \"count-N_1-N_2\", where N_1 is an integer in [1, 255] and N_2 is\n"     \
-       "an integer in [N_1, 255].\n"                                                                                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an Address name, contains Count label \"count-N\", and has the type of address records specified by\n"     \
-       "QTYPE, then the response will contain exactly N address records:\n"                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. For i in [1, N], the response will contain an address record of type QTYPE whose name is equal to QNAME\n"      \
-       "       and whose RDATA is an address equal to a constant base address + i.\n"                                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. The address records will be ordered by the address contained in RDATA in ascending order.\n"                            \
-       "\n"                                                                                                                                                                                                                            \
-       "Example. A response to an A record query with a QNAME of alias.count-3.d.test will contain the following A\n"          \
-       "records:\n"                                                                                                                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "    count-3.d.test.                                60    IN A     203.0.113.1\n"                                                                       \
-       "    count-3.d.test.                                60    IN A     203.0.113.2\n"                                                                       \
-       "    count-3.d.test.                                60    IN A     203.0.113.3\n"                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an Address name, contains Count label \"count-N_1-N_2\", and has the type of address records\n"            \
-       "specified by QTYPE, then the response will contain exactly N_1 address records:\n"                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. Each of the address records will be of type QTYPE, have name equal to QNAME, and have as its RDATA a\n"         \
-       "       unique address equal to a constant base address + i, where i is a randomly chosen integer in [1, N_2].\n"       \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. The order of the address records will be random.\n"                                                                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "Example. A response to a AAAA record query with a QNAME of count-3-100.ttl-20.d.test could contain the\n"                      \
-       "following AAAA records:\n"                                                                                                                                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "    count-3-100.ttl-20.d.test.                     20    IN AAAA  2001:db8:1::c\n"                                                                     \
-       "    count-3-100.ttl-20.d.test.                     20    IN AAAA  2001:db8:1::3a\n"                                                            \
-       "    count-3-100.ttl-20.d.test.                     20    IN AAAA  2001:db8:1::4f\n"                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an Address name, but doesn't have the type of address records specified by QTYPE, then the response\n"     \
-       "will contain no address records, regardless of whether it contains a Count label.\n"                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "Address names that don't have a Count label are treated as though they contain a count label equal to\n"                       \
-       "count-1\".\n"
-
-#define kDNSServerInfoText_TagLabel                                                                                                                                                                            \
-       "Tag labels are labels prefixed with \"tag-\" and contain zero or more arbitrary octets after the prefix.\n"            \
-       "\n"                                                                                                                                                                                                                            \
-       "This type of label exists to allow testers to \"uniquify\" domain names. Tag labels can also serve as padding\n"       \
-       "to increase the sizes of domain names.\n"
-
-#define kDNSServerInfoText_TTLLabel                                                                                                                                                                            \
-       "TTL labels are of the form \"ttl-T\", where T is an integer in [0, 2^31 - 1].\n"                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an Address name and contains TTL label \"ttl-T\", then all non-CNAME records contained in the\n"           \
-       "response will have a TTL value equal to T.\n"
-
-#define kDNSServerInfoText_IPv4Label \
-       "The IPv4 label is \"ipv4\". See \"Resource Records\" for the affect of this label.\n"
-
-#define kDNSServerInfoText_IPv6Label \
-       "The IPv6 label is \"ipv6\". See \"Resource Records\" for the affect of this label.\n"
-
-#define kDNSServerInfoText_SRVNames                                                                                                                                                                            \
-       "SRV labels are of the form \"srv-R-W-P\", where R, W, and P are integers in [0, 2^16 - 1].\n"                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "After the first two labels, i.e., the service and protocol labels, the sequence of labels, which may be empty,\n"      \
-       "leading up to the the first SRV label, if one exists, or the d.test. labels will be used as a parent domain for\n"     \
-       "the target hostname of each of the SRV name's SRV records.\n"                                                                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "If QNAME is an SRV name and QTYPE is SRV, then for each SRV label, the response will contain an SRV record with\n"     \
-       "priority R, weight W, port P, and target hostname <target>[.<parent domain>]., where <target> is the sequence\n"       \
-       "of labels, which may be empty, that follows the SRV label leading up to either the next SRV label or the\n"            \
-       "d.test. labels, whichever comes first.\n"                                                                                                                                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "Example. A response to an SRV record query with a QNAME of\n"                                                                                                          \
-       "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. will contain the following SRV records:\n"                      \
-       "\n"                                                                                                                                                                                                                            \
-       "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test.     60    IN SRV   0 0 80 www.example.com.\n"           \
-       "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test.     60    IN SRV   1 0 8080 www.example.com.\n"
-
-#define kDNSServerInfoText_BadUDPMode \
-       "The purpose of Bad UDP mode is to test mDNSResponder's TCP fallback mechanism by which mDNSResponder reissues a\n"     \
-       "UDP query as a TCP query if the UDP response contains the expected QNAME, QTYPE, and QCLASS, but a message ID\n"       \
-       "that's not equal to the query's message ID.\n"                                                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "This mode is identical to the normal mode except that all responses sent via UDP have a message ID equal to the\n"     \
-       "query's message ID plus one. Also, in this mode, to aid in debugging, A records in responses sent via UDP have\n"      \
-       "IPv4 addresses in the 0.0.0.0/24 block instead of the 203.0.113.0/24 block, i.e., 0.0.0.0 is used as the IPv4\n"       \
-       "base address, and AAAA records in responses sent via UDP have IPv6 addresses in the ::ffff:0:0/120 block\n"            \
-       "instead of the 2001:db8:1::/120 block, i.e., ::ffff:0:0 is used as the IPv6 base address.\n"
-
-static int                             gDNSServer_LoopbackOnly         = false;
-static int                             gDNSServer_Foreground           = false;
-static int                             gDNSServer_ResponseDelayMs      = 0;
-static int                             gDNSServer_DefaultTTL           = 60;
-static int                             gDNSServer_Port                         = kDNSPort;
-static const char *            gDNSServer_DomainOverride       = NULL;
-#if( TARGET_OS_DARWIN )
-static const char *            gDNSServer_FollowPID            = NULL;
-#endif
-static int                             gDNSServer_BadUDPMode           = false;
-
-static CLIOption               kDNSServerOpts[] =
-{
-       BooleanOption( 'l', "loopback",      &gDNSServer_LoopbackOnly,    "Bind to to the loopback interface." ),
-       BooleanOption( 'f', "foreground",    &gDNSServer_Foreground,      "Direct log output to stdout instead of system logging." ),
-       IntegerOption( 'd', "responseDelay", &gDNSServer_ResponseDelayMs, "ms", "The amount of additional delay in milliseconds to apply to responses. (default: 0)", false ),
-       IntegerOption(  0 , "defaultTTL",    &gDNSServer_DefaultTTL,      "seconds", "Resource record TTL value to use when unspecified. (default: 60)", false ),
-       IntegerOption( 'p', "port",          &gDNSServer_Port,            "port number", "UDP/TCP port number to use. Use 0 for any port. (default: 53)", false ),
-       StringOption(   0 , "domain",        &gDNSServer_DomainOverride,  "domain", "Used to override 'd.test.' as the server's domain.", false ),
-#if( TARGET_OS_DARWIN )
-       StringOption(   0 , "follow",        &gDNSServer_FollowPID,       "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
-#endif
-       BooleanOption(  0 , "badUDPMode",    &gDNSServer_BadUDPMode,      "Run in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
-       
-       CLI_SECTION( "Intro",                           kDNSServerInfoText_Intro ),
-       CLI_SECTION( "Name Existence",          kDNSServerInfoText_NameExistence ),
-       CLI_SECTION( "Resource Records",        kDNSServerInfoText_ResourceRecords ),
-       CLI_SECTION( "Alias Labels",            kDNSServerInfoText_AliasLabel ),
-       CLI_SECTION( "Alias-TTL Labels",        kDNSServerInfoText_AliasTTLLabel ),
-       CLI_SECTION( "Count Labels",            kDNSServerInfoText_CountLabel ),
-       CLI_SECTION( "Tag Labels",                      kDNSServerInfoText_TagLabel ),
-       CLI_SECTION( "TTL Labels",                      kDNSServerInfoText_TTLLabel ),
-       CLI_SECTION( "IPv4 Label",                      kDNSServerInfoText_IPv4Label ),
-       CLI_SECTION( "IPv6 Label",                      kDNSServerInfoText_IPv6Label ),
-       CLI_SECTION( "SRV Names",                       kDNSServerInfoText_SRVNames ),
-       CLI_SECTION( "Bad UDP Mode",            kDNSServerInfoText_BadUDPMode ),
-       CLI_OPTION_END()
-};
-
-static void    DNSServerCmd( void );
-
-//===========================================================================================================================
-//     MDNSReplier Command Options
-//===========================================================================================================================
-
-#define kMDNSReplierPortBase           50000
-
-#define kMDNSReplierInfoText_Intro                                                                                                                                                                             \
-       "The mDNS replier answers mDNS queries for its authoritative records. These records are of class IN and of types\n"     \
-       "PTR, SRV, TXT, A, and AAAA as described below.\n"                                                                                                                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
-
-#define kMDNSReplierInfoText_Parameters                                                                                                                                                                        \
-       "There are five parameters that control the replier's set of authoritative records.\n"                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. <hostname> is the base name used for service instance names and the names of A and AAAA records. This\n"        \
-       "       parameter is specified with the --hostname option.\n"                                                                                                           \
-       "    2. <tag> is an arbitrary string used to uniquify service types. This parameter is specified with the --tag\n"      \
-       "       option.\n"                                                                                                                                                                                                      \
-       "    3. N_max in an integer in [1, 65535] and limits service types to those that have no more than N_max\n"                     \
-       "       instances. It also limits the number of hostnames to N_max, i.e., <hostname>.local.,\n"                                         \
-       "       <hostname>-1.local., ..., <hostname>-N_max.local. This parameter is specified with the\n"                                       \
-       "       --maxInstanceCount option.\n"                                                                                                                                                           \
-       "    4. N_a is an integer in [1, 255] and the number of A records per hostname. This parameter is specified\n"          \
-       "       with the --countA option.\n"                                                                                                                                                            \
-       "    5. N_aaaa is an integer in [1, 255] and the number of AAAA records per hostname. This parameter is\n"                      \
-       "       specified with the --countAAAA option.\n"
-
-#define kMDNSReplierInfoText_PTR                                                                                                                                                                               \
-       "The replier's authoritative PTR records have names of the form _t-<tag>-<L>-<N>._tcp.local., where L is an\n"          \
-       "integer in [1, 65535], and N is an integer in [1, N_max].\n"                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "For a given L and N, the replier has exactly N authoritative PTR records:\n"                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. The first PTR record is defined as\n"                                                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:  _t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                                         \
-       "        TYPE:  PTR\n"                                                                                                                                                                                          \
-       "        CLASS: IN\n"                                                                                                                                                                                           \
-       "        TTL:   4500\n"                                                                                                                                                                                         \
-       "        RDATA: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                      \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. For each i in [2, N], there is one PTR record defined as\n"                                                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:  _t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                                         \
-       "        TYPE:  PTR\n"                                                                                                                                                                                          \
-       "        CLASS: IN\n"                                                                                                                                                                                           \
-       "        TTL:   4500\n"                                                                                                                                                                                         \
-       "        RDATA: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"
-
-#define kMDNSReplierInfoText_SRV                                                                                                                                                                               \
-       "The replier's authoritative SRV records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n"        \
-       "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n"            \
-       "\"<hostname> (<i>)\", where i is in [2, N].\n"                                                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "For a given L and N, the replier has exactly N authoritative SRV records:\n"                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. The first SRV record is defined as\n"                                                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:  <hostname>._t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                      \
-       "        TYPE:  SRV\n"                                                                                                                                                                                          \
-       "        CLASS: IN\n"                                                                                                                                                                                           \
-       "        TTL:   120\n"                                                                                                                                                                                          \
-       "        RDATA:\n"                                                                                                                                                                                                      \
-       "            Priority: 0\n"                                                                                                                                                                                     \
-       "            Weight:   0\n"                                                                                                                                                                                     \
-       "            Port:     (50000 + L) mod 2^16\n"                                                                                                                                          \
-       "            Target:   <hostname>.local.\n"                                                                                                                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. For each i in [2, N], there is one SRV record defined as:\n"                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:  \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"                                                                                            \
-       "        TYPE:  SRV\n"                                                                                                                                                                                          \
-       "        CLASS: IN\n"                                                                                                                                                                                           \
-       "        TTL:   120\n"                                                                                                                                                                                          \
-       "        RDATA:\n"                                                                                                                                                                                                      \
-       "            Priority: 0\n"                                                                                                                                                                                     \
-       "            Weight:   0\n"                                                                                                                                                                                     \
-       "            Port:     (50000 + L) mod 2^16\n"                                                                                                                                          \
-       "            Target:   <hostname>-<i>.local.\n"
-
-#define kMDNSReplierInfoText_TXT                                                                                                                                                                               \
-       "The replier's authoritative TXT records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n"        \
-       "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n"            \
-       "\"<hostname> (<i>)\", where i is in [2, N].\n"                                                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "For a given L and N, the replier has exactly N authoritative TXT records:\n"                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. The first TXT record is defined as\n"                                                                                                                                           \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:     <hostname>._t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                           \
-       "        TYPE:     TXT\n"                                                                                                                                                                                       \
-       "        CLASS:    IN\n"                                                                                                                                                                                        \
-       "        TTL:      4500\n"                                                                                                                                                                                      \
-       "        RDLENGTH: L\n"                                                                                                                                                                                         \
-       "        RDATA:    <one or more strings with an aggregate length of L octets>\n"                                                                        \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. For each i in [2, N], there is one TXT record:\n"                                                                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:     \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"                                                                                         \
-       "        TYPE:     TXT\n"                                                                                                                                                                                       \
-       "        CLASS:    IN\n"                                                                                                                                                                                        \
-       "        TTL:      4500\n"                                                                                                                                                                                      \
-       "        RDLENGTH: L\n"                                                                                                                                                                                         \
-       "        RDATA:    <one or more strings with an aggregate length of L octets>\n"                                                                        \
-       "\n"                                                                                                                                                                                                                            \
-       "The RDATA of each TXT record is exactly L octets and consists of a repeating series of the 15-byte string\n"           \
-       "\"hash=0x<32-bit FNV-1 hash of the record name as an 8-character hexadecimal string>\". The last instance of\n"        \
-       "the string may be truncated to satisfy the TXT record data's size requirement.\n"
-
-#define kMDNSReplierInfoText_A                                                                                                                                                                                 \
-       "The replier has exactly N_max x N_a authoritative A records:\n"                                                                                                        \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. For each j in [1, N_a], an A record is defined as\n"                                                                                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:     <hostname>.local.\n"                                                                                                                                                         \
-       "        TYPE:     A\n"                                                                                                                                                                                         \
-       "        CLASS:    IN\n"                                                                                                                                                                                        \
-       "        TTL:      120\n"                                                                                                                                                                                       \
-       "        RDLENGTH: 4\n"                                                                                                                                                                                         \
-       "        RDATA:    0.0.1.<j>\n"                                                                                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. For each i in [2, N_max], for each j in [1, N_a], an A record is defined as\n"                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:     <hostname>-<i>.local.\n"                                                                                                                                                     \
-       "        TYPE:     A\n"                                                                                                                                                                                         \
-       "        CLASS:    IN\n"                                                                                                                                                                                        \
-       "        TTL:      120\n"                                                                                                                                                                                       \
-       "        RDLENGTH: 4\n"                                                                                                                                                                                         \
-       "        RDATA:    0.<ceil(i / 256)>.<i mod 256>.<j>\n"
-
-#define kMDNSReplierInfoText_AAAA                                                                                                                                                                              \
-       "The replier has exactly N_max x N_aaaa authoritative AAAA records:\n"                                                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "    1. For each j in [1, N_aaaa], a AAAA record is defined as\n"                                                                                                       \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:     <hostname>.local.\n"                                                                                                                                                         \
-       "        TYPE:     AAAA\n"                                                                                                                                                                                      \
-       "        CLASS:    IN\n"                                                                                                                                                                                        \
-       "        TTL:      120\n"                                                                                                                                                                                       \
-       "        RDLENGTH: 16\n"                                                                                                                                                                                        \
-       "        RDATA:    2001:db8:2::1:<j>\n"                                                                                                                                                         \
-       "\n"                                                                                                                                                                                                                            \
-       "    2. For each i in [2, N_max], for each j in [1, N_aaaa], a AAAA record is defined as\n"                                                     \
-       "\n"                                                                                                                                                                                                                            \
-       "        NAME:     <hostname>-<i>.local.\n"                                                                                                                                                     \
-       "        TYPE:     AAAA\n"                                                                                                                                                                                      \
-       "        CLASS:    IN\n"                                                                                                                                                                                        \
-       "        TTL:      120\n"                                                                                                                                                                                       \
-       "        RDLENGTH: 16\n"                                                                                                                                                                                        \
-       "        RDATA:    2001:db8:2::<i>:<j>\n"
-
-#define kMDNSReplierInfoText_Responses                                                                                                                                                                 \
-       "When generating answers for a query message, any two records pertaining to the same hostname will be grouped\n"        \
-       "together in the same response message, and any two records pertaining to different hostnames will be in\n"                     \
-       "separate response messages.\n"
-
-static const char *            gMDNSReplier_Hostname                   = NULL;
-static const char *            gMDNSReplier_ServiceTypeTag             = NULL;
-static int                             gMDNSReplier_MaxInstanceCount   = 1000;
-static int                             gMDNSReplier_NoAdditionals              = false;
-static int                             gMDNSReplier_RecordCountA               = 1;
-static int                             gMDNSReplier_RecordCountAAAA    = 1;
-static double                  gMDNSReplier_UnicastDropRate    = 0.0;
-static double                  gMDNSReplier_MulticastDropRate  = 0.0;
-static int                             gMDNSReplier_MaxDropCount               = 0;
-static int                             gMDNSReplier_UseIPv4                    = false;
-static int                             gMDNSReplier_UseIPv6                    = false;
-static int                             gMDNSReplier_Foreground                 = false;
-static const char *            gMDNSReplier_FollowPID              = NULL;
-
-static CLIOption               kMDNSReplierOpts[] =
-{
-       StringOption(  'i', "interface",        &gInterface,                     "name or index", "Network interface by name or index.", true ),
-       StringOption(  'n', "hostname",         &gMDNSReplier_Hostname,          "string", "Base name to use for hostnames and service instance names.", true ),
-       StringOption(  't', "tag",              &gMDNSReplier_ServiceTypeTag,    "string", "Tag to use for service types, e.g., _t-<tag>-<TXT size>-<count>._tcp.", true ),
-       IntegerOption( 'c', "maxInstanceCount", &gMDNSReplier_MaxInstanceCount,  "count", "Maximum number of service instances. (default: 1000)", false ),
-       BooleanOption(  0 , "noAdditionals",    &gMDNSReplier_NoAdditionals,     "When answering queries, don't include any additional records." ),
-       IntegerOption(  0 , "countA",           &gMDNSReplier_RecordCountA,      "count", "Number of A records per hostname. (default: 1)", false ),
-       IntegerOption(  0 , "countAAAA",        &gMDNSReplier_RecordCountAAAA,   "count", "Number of AAAA records per hostname. (default: 1)", false ),
-       DoubleOption(   0 , "udrop",            &gMDNSReplier_UnicastDropRate,   "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
-       DoubleOption(   0 , "mdrop",            &gMDNSReplier_MulticastDropRate, "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
-       IntegerOption(  0 , "maxDropCount",     &gMDNSReplier_MaxDropCount,      "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
-       BooleanOption(  0 , "ipv4",             &gMDNSReplier_UseIPv4,           "Use IPv4." ),
-       BooleanOption(  0 , "ipv6",             &gMDNSReplier_UseIPv6,           "Use IPv6." ),
-       BooleanOption( 'f', "foreground",       &gMDNSReplier_Foreground,        "Direct log output to stdout instead of system logging." ),
-#if( TARGET_OS_DARWIN )
-       StringOption(   0 , "follow",           &gMDNSReplier_FollowPID,         "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
-#endif
-       
-       CLI_SECTION( "Intro",                                                   kMDNSReplierInfoText_Intro ),
-       CLI_SECTION( "Authoritative Record Parameters", kMDNSReplierInfoText_Parameters ),
-       CLI_SECTION( "Authoritative PTR Records",               kMDNSReplierInfoText_PTR ),
-       CLI_SECTION( "Authoritative SRV Records",               kMDNSReplierInfoText_SRV ),
-       CLI_SECTION( "Authoritative TXT Records",               kMDNSReplierInfoText_TXT ),
-       CLI_SECTION( "Authoritative A Records",                 kMDNSReplierInfoText_A ),
-       CLI_SECTION( "Authoritative AAAA Records",              kMDNSReplierInfoText_AAAA ),
-       CLI_SECTION( "Responses",                                               kMDNSReplierInfoText_Responses ),
-       CLI_OPTION_END()
-};
-
-static void    MDNSReplierCmd( void );
-
-//===========================================================================================================================
-//     Test Command Options
-//===========================================================================================================================
-
-#define kTestExitStatusSection_Name            "Exit Status"
-#define kTestExitStatusSection_Text                                                                                                                                                                            \
-       "This test command can exit with one of three status codes:\n"                                                                                                          \
-       "\n"                                                                                                                                                                                                                            \
-       "0 - The test ran to completion and passed.\n"                                                                                                                                          \
-       "1 - A fatal error prevented the test from completing.\n"                                                                                                                       \
-       "2 - The test ran to completion, but it or a subtest failed. See test output for details.\n"                                            \
-       "\n"                                                                                                                                                                                                                            \
-       "Note: The pass/fail status applies to the correctness or results. It does not necessarily imply anything about\n"      \
-       "performance.\n"
-
-#define TestExitStatusSection()                CLI_SECTION( kTestExitStatusSection_Name, kTestExitStatusSection_Text )
-
-#define kGAIPerfTestSuiteName_Basic                    "basic"
-#define kGAIPerfTestSuiteName_Advanced         "advanced"
-
-static const char *            gGAIPerf_TestSuite                              = NULL;
-static int                             gGAIPerf_CallDelayMs                    = 10;
-static int                             gGAIPerf_ServerDelayMs                  = 10;
-static int                             gGAIPerf_SkipPathEvalulation    = false;
-static int                             gGAIPerf_BadUDPMode                             = false;
-static int                             gGAIPerf_IterationCount                 = 100;
-static const char *            gGAIPerf_OutputFilePath                 = NULL;
-static const char *            gGAIPerf_OutputFormat                   = kOutputFormatStr_JSON;
-static int                             gGAIPerf_OutputAppendNewline    = false;
-
-static void    GAIPerfCmd( void );
-
-#define kGAIPerfSectionText_TestSuiteBasic                                                                                                                                                                     \
-       "This test suite consists of the following three test cases:\n"                                                                                                                 \
-       "\n"                                                                                                                                                                                                                                    \
-       "Test Case #1: Resolve a domain name with\n"                                                                                                                                                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "    2 CNAME records, 4 A records, and 4 AAAA records\n"                                                                                                                                \
-       "\n"                                                                                                                                                                                                                                    \
-       "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n"             \
-       "server queries.\n"                                                                                                                                                                                                             \
-       "\n"                                                                                                                                                                                                                                    \
-       "Test Case #2: Resolve a domain name with\n"                                                                                                                                                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "    2 CNAME records, 4 A records, and 4 AAAA records\n"                                                                                                                                \
-       "\n"                                                                                                                                                                                                                                    \
-       "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n"             \
-       "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n"              \
-       "which should ideally require no additional server queries, i.e., the results should come from the cache.\n"                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n"               \
-       "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n"             \
-       "domain name in the preliminary iteration isn't counted in the performance stats.\n"                                                                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "Test Case #3: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
-
-#define kGAIPerfSectionText_TestSuiteAdvanced                                                                                                                                                          \
-       "This test suite consists of 33 test cases. Test cases 1 through 32 can be described in the following way\n"                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "Test Case #N (where N is in [1, 32] and odd): Resolve a domain name with\n"                                                                                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "    N_c CNAME records, N_a A records, and N_a AAAA records\n"                                                                                                                  \
-       "\n"                                                                                                                                                                                                                                    \
-       "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n"             \
-       "server queries.\n"                                                                                                                                                                                                             \
-       "\n"                                                                                                                                                                                                                                    \
-       "Test Case #N (where N is in [1, 32] and even): Resolve a domain name with\n"                                                                                   \
-       "\n"                                                                                                                                                                                                                                    \
-       "    N_c CNAME records, N_a A records, and N_a AAAA records\n"                                                                                                                  \
-       "\n"                                                                                                                                                                                                                                    \
-       "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n"             \
-       "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n"              \
-       "which should ideally require no additional server queries, i.e., the results should come from the cache.\n"                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n"               \
-       "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n"             \
-       "domain name in the preliminary iteration isn't counted in the performance stats.\n"                                                                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "N_c and N_a take on the following values, depending on the value of N:\n"                                                                                              \
-       "\n"                                                                                                                                                                                                                                    \
-       "    N_c is 0 if N is in [1, 8].\n"                                                                                                                                                                             \
-       "    N_c is 1 if N is in [9, 16].\n"                                                                                                                                                                    \
-       "    N_c is 2 if N is in [17, 24].\n"                                                                                                                                                                   \
-       "    N_c is 4 if N is in [25, 32].\n"                                                                                                                                                                   \
-       "\n"                                                                                                                                                                                                                                    \
-       "    N_a is 1 if N mod 8 is 1 or 2.\n"                                                                                                                                                                  \
-       "    N_a is 2 if N mod 8 is 3 or 4.\n"                                                                                                                                                                  \
-       "    N_a is 4 if N mod 8 is 5 or 6.\n"                                                                                                                                                                  \
-       "    N_a is 8 if N mod 8 is 7 or 0.\n"                                                                                                                                                                  \
-       "\n"                                                                                                                                                                                                                                    \
-       "Finally,\n"                                                                                                                                                                                                                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "Test Case #33: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
-
-static CLIOption               kGAIPerfOpts[] =
-{
-       StringOptionEx( 's', "suite",         &gGAIPerf_TestSuite,           "name", "Name of the predefined test suite to run.", true,
-               "\n"
-               "There are currently two predefined test suites, '" kGAIPerfTestSuiteName_Basic "' and '" kGAIPerfTestSuiteName_Advanced "', which are described below.\n"
-               "\n"
-       ),
-       StringOption(   'o', "output",        &gGAIPerf_OutputFilePath,      "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
-       FormatOption(   'f', "format",        &gGAIPerf_OutputFormat,        "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
-       BooleanOption(  'n', "appendNewline", &gGAIPerf_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
-       IntegerOption(   0 , "callDelay",     &gGAIPerf_CallDelayMs,         "ms", "Time to wait before calling DNSServiceGetAddrInfo() in milliseconds. (default: 10)", false ),
-       BooleanOption(   0 , "skipPathEval",  &gGAIPerf_SkipPathEvalulation, "Use kDNSServiceFlagsPathEvaluationDone when calling DNSServiceGetAddrInfo()." ),
-       IntegerOption(  'i', "iterations",    &gGAIPerf_IterationCount,      "count", "The number of iterations per test case. (default: 100)", false ),
-       
-       CLI_OPTION_GROUP( "DNS Server Options" ),
-       IntegerOption(   0 , "responseDelay", &gGAIPerf_ServerDelayMs,       "ms", "Additional delay in milliseconds to have the server apply to responses. (default: 10)", false ),
-       BooleanOption(   0 , "badUDPMode",    &gGAIPerf_BadUDPMode,          "Run server in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
-       
-       CLI_SECTION( "Test Suite \"Basic\"",    kGAIPerfSectionText_TestSuiteBasic ),
-       CLI_SECTION( "Test Suite \"Advanced\"", kGAIPerfSectionText_TestSuiteAdvanced ),
-       TestExitStatusSection(),
-       CLI_OPTION_END()
-};
-
-static void    MDNSDiscoveryTestCmd( void );
-
-static int                             gMDNSDiscoveryTest_InstanceCount                = 100;
-static int                             gMDNSDiscoveryTest_TXTSize                              = 100;
-static int                             gMDNSDiscoveryTest_BrowseTimeSecs               = 2;
-static int                             gMDNSDiscoveryTest_FlushCache                   = false;
-static char *                  gMDNSDiscoveryTest_Interface                    = NULL;
-static int                             gMDNSDiscoveryTest_NoAdditionals                = false;
-static int                             gMDNSDiscoveryTest_RecordCountA                 = 1;
-static int                             gMDNSDiscoveryTest_RecordCountAAAA              = 1;
-static double                  gMDNSDiscoveryTest_UnicastDropRate              = 0.0;
-static double                  gMDNSDiscoveryTest_MulticastDropRate    = 0.0;
-static int                             gMDNSDiscoveryTest_MaxDropCount                 = 0;
-static int                             gMDNSDiscoveryTest_UseIPv4                              = false;
-static int                             gMDNSDiscoveryTest_UseIPv6                              = false;
-static const char *            gMDNSDiscoveryTest_OutputFormat                 = kOutputFormatStr_JSON;
-static int                             gMDNSDiscoveryTest_OutputAppendNewline  = false;
-static const char *            gMDNSDiscoveryTest_OutputFilePath               = NULL;
-
-static CLIOption               kMDNSDiscoveryTestOpts[] =
-{
-       IntegerOption( 'c', "instanceCount",  &gMDNSDiscoveryTest_InstanceCount,       "count", "Number of service instances to discover. (default: 100)", false ),
-       IntegerOption( 's', "txtSize",        &gMDNSDiscoveryTest_TXTSize,             "bytes", "Desired size of each service instance's TXT record data. (default: 100)", false ),
-       IntegerOption( 'b', "browseTime",     &gMDNSDiscoveryTest_BrowseTimeSecs,      "seconds", "Amount of time to spend browsing in seconds. (default: 2)", false ),
-       BooleanOption(  0 , "flushCache",     &gMDNSDiscoveryTest_FlushCache,          "Flush mDNSResponder's record cache before browsing. Requires root privileges." ),
-       
-       CLI_OPTION_GROUP( "mDNS Replier Parameters" ),
-       StringOption(  'i', "interface",      &gMDNSDiscoveryTest_Interface,           "name or index", "Network interface. If unspecified, any available mDNS-capable interface will be used.", false ),
-       BooleanOption(  0 , "noAdditionals",  &gMDNSDiscoveryTest_NoAdditionals,       "When answering queries, don't include any additional records." ),
-       IntegerOption(  0 , "countA",         &gMDNSDiscoveryTest_RecordCountA,        "count", "Number of A records per hostname. (default: 1)", false ),
-       IntegerOption(  0 , "countAAAA",      &gMDNSDiscoveryTest_RecordCountAAAA,     "count", "Number of AAAA records per hostname. (default: 1)", false ),
-       DoubleOption(   0 , "udrop",          &gMDNSDiscoveryTest_UnicastDropRate,     "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
-       DoubleOption(   0 , "mdrop",          &gMDNSDiscoveryTest_MulticastDropRate,   "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
-       IntegerOption(  0 , "maxDropCount",   &gMDNSDiscoveryTest_MaxDropCount,        "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
-       BooleanOption(  0 , "ipv4",           &gMDNSDiscoveryTest_UseIPv4,             "Use IPv4." ),
-       BooleanOption(  0 , "ipv6",           &gMDNSDiscoveryTest_UseIPv6,             "Use IPv6." ),
-       
-       CLI_OPTION_GROUP( "Results" ),
-       FormatOption(   'f', "format",        &gMDNSDiscoveryTest_OutputFormat,        "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
-       StringOption(   'o', "output",        &gMDNSDiscoveryTest_OutputFilePath,      "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
-       BooleanOption(  'n', "appendNewline", &gMDNSDiscoveryTest_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
-       
-       TestExitStatusSection(),
-       CLI_OPTION_END()
-};
-
-static void    DotLocalTestCmd( void );
-
-static const char *            gDotLocalTest_Interface                         = NULL;
-static const char *            gDotLocalTest_OutputFormat                      = kOutputFormatStr_JSON;
-static int                             gDotLocalTest_OutputAppendNewline       = false;
-static const char *            gDotLocalTest_OutputFilePath            = NULL;
-
-#define kDotLocalTestSubtestDesc_GAIMDNSOnly   "GAI for a dotlocal name that has only MDNS A and AAAA records."
-#define kDotLocalTestSubtestDesc_GAIDNSOnly            "GAI for a dotlocal name that has only DNS A and AAAA records."
-#define kDotLocalTestSubtestDesc_GAIBoth               "GAI for a dotlocal name that has both mDNS and DNS A and AAAA records."
-#define kDotLocalTestSubtestDesc_GAINeither            "GAI for a dotlocal name that has no A or AAAA records."
-#define kDotLocalTestSubtestDesc_GAINoSuchRecord \
-       "GAI for a dotlocal name that has no A or AAAA records, but is a subdomain name of a search domain."
-#define kDotLocalTestSubtestDesc_QuerySRV              "SRV query for a dotlocal name that has only a DNS SRV record."
-
-#define kDotLocalTestSectionText_Description                                                                                                                                                           \
-       "The goal of the dotlocal test is to verify that mDNSResponder properly handles queries for domain names in the\n"              \
-       "local domain when a local SOA record exists. As part of the test setup, a test DNS server and an mdnsreplier are\n"    \
-       "spawned, and a dummy local SOA record is registered with DNSServiceRegisterRecord(). The server is invoked such\n"             \
-       "that its domain is a second-level subdomain of the local domain, i.e., <some label>.local, while the mdnsreplier is\n" \
-       "invoked such that its base hostname is equal to the server's domain, e.g., if the server's domain is test.local.,\n"   \
-       "then the mdnsreplier's base hostname is test.local.\n"                                                                                                                                 \
-       "\n"                                                                                                                                                                                                                                    \
-       "The dotlocal test consists of six subtests that perform either a DNSServiceGetAddrInfo (GAI) operation for a\n"                \
-       "hostname in the local domain or a DNSServiceQueryRecord operation to query for an SRV record in the local domain:\n"   \
-       "\n"                                                                                                                                                                                                                                    \
-       "1. " kDotLocalTestSubtestDesc_GAIMDNSOnly              "\n"                                                                                                                                    \
-       "2. " kDotLocalTestSubtestDesc_GAIDNSOnly               "\n"                                                                                                                                    \
-       "3. " kDotLocalTestSubtestDesc_GAIBoth                  "\n"                                                                                                                                    \
-       "4. " kDotLocalTestSubtestDesc_GAINeither               "\n"                                                                                                                                    \
-       "5. " kDotLocalTestSubtestDesc_GAINoSuchRecord  "\n"                                                                                                                                    \
-       "6. " kDotLocalTestSubtestDesc_QuerySRV                 "\n"                                                                                                                                    \
-       "\n"                                                                                                                                                                                                                                    \
-       "Each subtest runs for five seconds.\n"
-
-static CLIOption               kDotLocalTestOpts[] =
-{
-       StringOption(  'i', "interface",     &gDotLocalTest_Interface,           "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
-       
-       CLI_OPTION_GROUP( "Results" ),
-       FormatOption(  'f', "format",        &gDotLocalTest_OutputFormat,        "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
-       StringOption(  'o', "output",        &gDotLocalTest_OutputFilePath,      "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
-       BooleanOption( 'n', "appendNewline", &gDotLocalTest_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
-       
-       CLI_SECTION( "Description", kDotLocalTestSectionText_Description ),
-       TestExitStatusSection(),
-       CLI_OPTION_END()
-};
-
-static void    ProbeConflictTestCmd( void );
-
-static const char *            gProbeConflictTest_Interface                    = NULL;
-static int                             gProbeConflictTest_UseComputerName              = false;
-static const char *            gProbeConflictTest_OutputFormat                 = kOutputFormatStr_JSON;
-static int                             gProbeConflictTest_OutputAppendNewline  = false;
-static const char *            gProbeConflictTest_OutputFilePath               = NULL;
-
-static CLIOption               kProbeConflictTestOpts[] =
-{
-       StringOption(  'i', "interface",       &gProbeConflictTest_Interface,           "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
-       BooleanOption( 'c', "useComputerName", &gProbeConflictTest_UseComputerName,     "Use the device's \"computer name\" for the test service's name." ),
-       
-       CLI_OPTION_GROUP( "Results" ),
-       FormatOption(  'f', "format",          &gProbeConflictTest_OutputFormat,        "Specifies the test report output format. (default: " kOutputFormatStr_JSON ")", false ),
-       StringOption(  'o', "output",          &gProbeConflictTest_OutputFilePath,      "path", "Path of the file to write test report to instead of standard output (stdout).", false ),
-       BooleanOption( 'n', "appendNewline",   &gProbeConflictTest_OutputAppendNewline, "If the output format is JSON, output a trailing newline character." ),
-       
-       TestExitStatusSection(),
-       CLI_OPTION_END()
-};
-
-static CLIOption               kTestOpts[] =
-{
-       Command( "gaiperf",        GAIPerfCmd,           kGAIPerfOpts,            "Runs DNSServiceGetAddrInfo() performance tests.", false ),
-       Command( "mdnsdiscovery",  MDNSDiscoveryTestCmd, kMDNSDiscoveryTestOpts,  "Tests mDNS service discovery for correctness.", false ),
-       Command( "dotlocal",       DotLocalTestCmd,      kDotLocalTestOpts,       "Tests DNS and mDNS queries for domain names in the local domain.", false ),
-       Command( "probeconflicts", ProbeConflictTestCmd, kProbeConflictTestOpts,  "Tests various probing conflict scenarios.", false ),
-       
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     SSDP Command Options
-//===========================================================================================================================
-
-static int                             gSSDPDiscover_MX                        = 1;
-static const char *            gSSDPDiscover_ST                        = "ssdp:all";
-static int                             gSSDPDiscover_ReceiveSecs       = 1;
-static int                             gSSDPDiscover_UseIPv4           = false;
-static int                             gSSDPDiscover_UseIPv6           = false;
-static int                             gSSDPDiscover_Verbose           = false;
-
-static CLIOption               kSSDPDiscoverOpts[] =
-{
-       StringOption(  'i', "interface",        &gInterface,                            "name or index", "Network interface by name or index.", true ),
-       IntegerOption( 'm', "mx",                       &gSSDPDiscover_MX,                      "seconds", "MX value in search request, i.e., max response delay in seconds. (Default: 1 second)", false ),
-       StringOption(  's', "st",                       &gSSDPDiscover_ST,                      "string", "ST value in search request, i.e., the search target. (Default: \"ssdp:all\")", false ),
-       IntegerOption( 'r', "receiveTime",      &gSSDPDiscover_ReceiveSecs,     "seconds", "Amount of time to spend receiving responses. -1 means unlimited. (Default: 1 second)", false ),
-       BooleanOption(  0 , "ipv4",                     &gSSDPDiscover_UseIPv4,         "Use IPv4, i.e., multicast to 239.255.255.250:1900." ),
-       BooleanOption(  0 , "ipv6",                     &gSSDPDiscover_UseIPv6,         "Use IPv6, i.e., multicast to [ff02::c]:1900" ),
-       BooleanOption( 'v', "verbose",          &gSSDPDiscover_Verbose,         "Prints the search request(s) that were sent." ),
-       CLI_OPTION_END()
-};
-
-static void    SSDPDiscoverCmd( void );
-
-static CLIOption               kSSDPOpts[] =
-{
-       Command( "discover", SSDPDiscoverCmd, kSSDPDiscoverOpts, "Crafts and multicasts an SSDP search message.", false ),
-       CLI_OPTION_END()
-};
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-//     res_query Command Options
-//===========================================================================================================================
-
-static void    ResQueryCmd( void );
-
-static const char *            gResQuery_Name                  = NULL;
-static const char *            gResQuery_Type                  = NULL;
-static const char *            gResQuery_Class                 = NULL;
-static int                             gResQuery_UseLibInfo    = false;
-
-static CLIOption               kResQueryOpts[] =
-{
-       StringOption( 'n', "name",              &gResQuery_Name,                "domain name",  "Full domain name of record to query.", true ),
-       StringOption( 't', "type",              &gResQuery_Type,                "record type",  "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
-       StringOption( 'c', "class",             &gResQuery_Class,               "record class", "Record class by name or number. Default class is IN.", false ),
-       BooleanOption( 0 , "libinfo",   &gResQuery_UseLibInfo,  "Use res_query from libinfo instead of libresolv." ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     dns_query Command Options
-//===========================================================================================================================
-
-static void ResolvDNSQueryCmd( void );
-
-static const char *            gResolvDNSQuery_Name    = NULL;
-static const char *            gResolvDNSQuery_Type    = NULL;
-static const char *            gResolvDNSQuery_Class   = NULL;
-static const char *            gResolvDNSQuery_Path    = NULL;
-
-static CLIOption               kResolvDNSQueryOpts[] =
-{
-       StringOption( 'n', "name",      &gResolvDNSQuery_Name,  "domain name",  "Full domain name of record to query.", true ),
-       StringOption( 't', "type",      &gResolvDNSQuery_Type,  "record type",  "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
-       StringOption( 'c', "class",     &gResolvDNSQuery_Class, "record class", "Record class by name or number. Default class is IN.", false ),
-       StringOption( 'p', "path",      &gResolvDNSQuery_Path,  "file path",    "The path argument to pass to dns_open() before calling dns_query(). Default value is NULL.", false ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     CFHost Command Options
-//===========================================================================================================================
-
-static void    CFHostCmd( void );
-
-static const char *            gCFHost_Name            = NULL;
-static int                             gCFHost_WaitSecs        = 0;
-
-static CLIOption               kCFHostOpts[] =
-{
-       StringOption(  'n', "name", &gCFHost_Name,     "hostname", "Hostname to resolve.", true ),
-       IntegerOption( 'w', "wait", &gCFHost_WaitSecs, "seconds",  "Time in seconds to wait before a normal exit. (default: 0)", false ),
-       CLI_OPTION_END()
-};
-
-static CLIOption               kLegacyOpts[] =
-{
-       Command( "res_query", ResQueryCmd,       kResQueryOpts,       "Uses res_query() from either libresolv or libinfo to query for a record.", true ),
-       Command( "dns_query", ResolvDNSQueryCmd, kResolvDNSQueryOpts, "Uses dns_query() from libresolv to query for a record.", true ),
-       Command( "cfhost",    CFHostCmd,         kCFHostOpts,         "Uses CFHost to resolve a hostname.", true ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     DNSConfigAdd Command Options
-//===========================================================================================================================
-
-static void    DNSConfigAddCmd( void );
-
-static CFStringRef             gDNSConfigAdd_ID                        = NULL;
-static char **                 gDNSConfigAdd_IPAddrArray       = NULL;
-static size_t                  gDNSConfigAdd_IPAddrCount       = 0;
-static char **                 gDNSConfigAdd_DomainArray       = NULL;
-static size_t                  gDNSConfigAdd_DomainCount       = 0;
-static const char *            gDNSConfigAdd_Interface         = NULL;
-
-static CLIOption               kDNSConfigAddOpts[] =
-{
-       CFStringOption(     0 , "id",        &gDNSConfigAdd_ID,                                      "ID", "Arbitrary ID to use for resolver entry.", true ),
-       MultiStringOption( 'a', "address",   &gDNSConfigAdd_IPAddrArray, &gDNSConfigAdd_IPAddrCount, "IP address", "DNS server IP address(es). Can be specified more than once.", true ),
-       MultiStringOption( 'd', "domain",    &gDNSConfigAdd_DomainArray, &gDNSConfigAdd_DomainCount, "domain", "Specific domain(s) for the resolver entry. Can be specified more than once.", false ),
-       StringOption(      'i', "interface", &gDNSConfigAdd_Interface,                               "interface name", "Specific interface for the resolver entry.", false ),
-       
-       CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     DNSConfigRemove Command Options
-//===========================================================================================================================
-
-static void    DNSConfigRemoveCmd( void );
-
-static CFStringRef             gDNSConfigRemove_ID = NULL;
-
-static CLIOption               kDNSConfigRemoveOpts[] =
-{
-       CFStringOption( 0, "id", &gDNSConfigRemove_ID, "ID", "ID of resolver entry to remove.", true ),
-       
-       CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
-       CLI_OPTION_END()
-};
-
-static CLIOption               kDNSConfigOpts[] =
-{
-       Command( "add",    DNSConfigAddCmd,    kDNSConfigAddOpts,    "Add a supplemental resolver entry to the system's DNS configuration.", true ),
-       Command( "remove", DNSConfigRemoveCmd, kDNSConfigRemoveOpts, "Remove a supplemental resolver entry from the system's DNS configuration.", true ),
-       CLI_OPTION_END()
-};
-#endif // TARGET_OS_DARWIN
-
-//===========================================================================================================================
-//     Command Table
-//===========================================================================================================================
-
-static OSStatus        VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset );
-
-static void    BrowseCmd( void );
-static void    GetAddrInfoCmd( void );
-static void    QueryRecordCmd( void );
-static void    RegisterCmd( void );
-static void    RegisterRecordCmd( void );
-static void    ResolveCmd( void );
-static void    ReconfirmCmd( void );
-static void    GetAddrInfoPOSIXCmd( void );
-static void    ReverseLookupCmd( void );
-static void    PortMappingCmd( void );
-static void    BrowseAllCmd( void );
-static void    GetAddrInfoStressCmd( void );
-static void    DNSQueryCmd( void );
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-static void    DNSCryptCmd( void );
-#endif
-static void    MDNSQueryCmd( void );
-static void    PIDToUUIDCmd( void );
-static void    DaemonVersionCmd( void );
-
-static CLIOption               kGlobalOpts[] =
-{
-       CLI_OPTION_CALLBACK_EX( 'V', "version", VersionOptionCallback, NULL, NULL,
-               kCLIOptionFlags_NoArgument | kCLIOptionFlags_GlobalOnly, "Displays the version of this tool.", NULL ),
-       CLI_OPTION_HELP(),
-       
-       // Common commands.
-       
-       Command( "browse",                              BrowseCmd,                              kBrowseOpts,                    "Uses DNSServiceBrowse() to browse for one or more service types.", false ),
-       Command( "getAddrInfo",                 GetAddrInfoCmd,                 kGetAddrInfoOpts,               "Uses DNSServiceGetAddrInfo() to resolve a hostname to IP addresses.", false ),
-       Command( "queryRecord",                 QueryRecordCmd,                 kQueryRecordOpts,               "Uses DNSServiceQueryRecord() to query for an arbitrary DNS record.", false ),
-       Command( "register",                    RegisterCmd,                    kRegisterOpts,                  "Uses DNSServiceRegister() to register a service.", false ),
-       Command( "registerRecord",              RegisterRecordCmd,              kRegisterRecordOpts,    "Uses DNSServiceRegisterRecord() to register a record.", false ),
-       Command( "resolve",                             ResolveCmd,                             kResolveOpts,                   "Uses DNSServiceResolve() to resolve a service.", false ),
-       Command( "reconfirm",                   ReconfirmCmd,                   kReconfirmOpts,                 "Uses DNSServiceReconfirmRecord() to reconfirm a record.", false ),
-       Command( "getaddrinfo-posix",   GetAddrInfoPOSIXCmd,    kGetAddrInfoPOSIXOpts,  "Uses getaddrinfo() to resolve a hostname to IP addresses.", false ),
-       Command( "reverseLookup",               ReverseLookupCmd,               kReverseLookupOpts,             "Uses DNSServiceQueryRecord() to perform a reverse IP address lookup.", false ),
-       Command( "portMapping",                 PortMappingCmd,                 kPortMappingOpts,               "Uses DNSServiceNATPortMappingCreate() to create a port mapping.", false ),
-       Command( "browseAll",                   BrowseAllCmd,                   kBrowseAllOpts,                 "Browse and resolve all (or specific) services and, optionally, attempt connections.", false ),
-       
-       // Uncommon commands.
-       
-       Command( "getnameinfo",                 GetNameInfoCmd,                 kGetNameInfoOpts,               "Calls getnameinfo() and prints results.", true ),
-       Command( "getAddrInfoStress",   GetAddrInfoStressCmd,   kGetAddrInfoStressOpts, "Runs DNSServiceGetAddrInfo() stress testing.", true ),
-       Command( "DNSQuery",                    DNSQueryCmd,                    kDNSQueryOpts,                  "Crafts and sends a DNS query.", true ),
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-       Command( "DNSCrypt",                    DNSCryptCmd,                    kDNSCryptOpts,                  "Crafts and sends a DNSCrypt query.", true ),
-#endif
-       Command( "mdnsquery",                   MDNSQueryCmd,                   kMDNSQueryOpts,                 "Crafts and sends an mDNS query over the specified interface.", true ),
-       Command( "mdnscollider",                MDNSColliderCmd,                kMDNSColliderOpts,              "Creates record name collision scenarios.", true ),
-       Command( "pid2uuid",                    PIDToUUIDCmd,                   kPIDToUUIDOpts,                 "Prints the UUID of a process.", true ),
-       Command( "server",                              DNSServerCmd,                   kDNSServerOpts,                 "DNS server for testing.", true ),
-       Command( "mdnsreplier",                 MDNSReplierCmd,                 kMDNSReplierOpts,               "Responds to mDNS queries for a set of authoritative resource records.", true ),
-       Command( "test",                                NULL,                                   kTestOpts,                              "Commands for testing DNS-SD.", true ),
-       Command( "ssdp",                                NULL,                                   kSSDPOpts,                              "Commands for testing Simple Service Discovery Protocol (SSDP).", true ),
-#if( TARGET_OS_DARWIN )
-       Command( "legacy",                              NULL,                                   kLegacyOpts,                    "Commands for legacy non-DNS-SD API.", true ),
-       Command( "dnsconfig",                   NULL,                                   kDNSConfigOpts,                 "Add/remove a supplemental resolver entry to/from the system's DNS configuration.", true ),
-#endif
-       Command( "daemonVersion",               DaemonVersionCmd,               NULL,                                   "Prints the version of the DNS-SD daemon.", true ),
-       
-       CLI_COMMAND_HELP(),
-       CLI_OPTION_END()
-};
-
-//===========================================================================================================================
-//     Helper Prototypes
-//===========================================================================================================================
-
-#define kExitReason_OneShotDone                                "one-shot done"
-#define kExitReason_ReceivedResponse           "received response"
-#define kExitReason_SIGINT                                     "interrupt signal"
-#define kExitReason_Timeout                                    "timeout"
-#define kExitReason_TimeLimit                          "time limit"
-
-static void    Exit( void *inContext ) ATTRIBUTE_NORETURN;
-
-static int
-       PrintFTimestampHandler(
-               PrintFContext * inContext,
-               PrintFFormat *  inFormat,
-               PrintFVAList *  inArgs,
-               void *                  inUserContext );
-static int
-       PrintFDNSMessageHandler(
-               PrintFContext * inContext,
-               PrintFFormat *  inFormat,
-               PrintFVAList *  inArgs,
-               void *                  inUserContext );
-static int
-       PrintFAddRmvFlagsHandler(
-               PrintFContext * inContext,
-               PrintFFormat *  inFormat,
-               PrintFVAList *  inArgs,
-               void *                  inUserContext );
-
-static DNSServiceFlags GetDNSSDFlagsFromOpts( void );
-
-typedef enum
-{
-       kConnectionType_None                    = 0,
-       kConnectionType_Normal                  = 1,
-       kConnectionType_DelegatePID             = 2,
-       kConnectionType_DelegateUUID    = 3
-       
-}      ConnectionType;
-
-typedef struct
-{
-       ConnectionType          type;
-       union
-       {
-               int32_t                 pid;
-               uint8_t                 uuid[ 16 ];
-               
-       }       delegate;
-       
-}      ConnectionDesc;
-
-static OSStatus
-       CreateConnectionFromArgString(
-               const char *                    inString,
-               dispatch_queue_t                inQueue,
-               DNSServiceRef *                 outSDRef,
-               ConnectionDesc *                outDesc );
-static OSStatus                        InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex );
-static OSStatus                        RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen );
-static OSStatus                        RecordTypeFromArgString( const char *inString, uint16_t *outValue );
-static OSStatus                        RecordClassFromArgString( const char *inString, uint16_t *outValue );
-
-#define kInterfaceNameBufLen           ( Max( IF_NAMESIZE, 16 ) + 1 )
-
-static char *                  InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] );
-static const char *            RecordTypeToString( unsigned int inValue );
-
-static OSStatus
-       DNSMessageExtractDomainName(
-               const uint8_t *         inMsgPtr,
-               size_t                          inMsgLen,
-               const uint8_t *         inNamePtr,
-               uint8_t                         inBuf[ kDomainNameLengthMax ],
-               const uint8_t **        outNextPtr );
-static OSStatus
-       DNSMessageExtractDomainNameString(
-               const void *            inMsgPtr,
-               size_t                          inMsgLen,
-               const void *            inNamePtr,
-               char                            inBuf[ kDNSServiceMaxDomainName ],
-               const uint8_t **        outNextPtr );
-static OSStatus
-       DNSMessageExtractQuestion(
-               const uint8_t *         inMsgPtr,
-               size_t                          inMsgLen,
-               const uint8_t *         inPtr,
-               uint8_t                         inNameBuf[ kDomainNameLengthMax ],
-               uint16_t *                      outType,
-               uint16_t *                      outClass,
-               const uint8_t **        outPtr );
-static OSStatus
-       DNSMessageExtractRecord(
-               const uint8_t *         inMsgPtr,
-               size_t                          inMsgLen,
-               const uint8_t *         inPtr,
-               uint8_t                         inNameBuf[ kDomainNameLengthMax ],
-               uint16_t *                      outType,
-               uint16_t *                      outClass,
-               uint32_t *                      outTTL,
-               const uint8_t **        outRDataPtr,
-               size_t *                        outRDataLen,
-               const uint8_t **        outPtr );
-static OSStatus        DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr );
-static OSStatus
-       DNSRecordDataToString(
-               const void *    inRDataPtr,
-               size_t                  inRDataLen,
-               unsigned int    inRDataType,
-               const void *    inMsgPtr,
-               size_t                  inMsgLen,
-               char **                 outString );
-static OSStatus
-       DomainNameAppendString(
-               uint8_t                 inDomainName[ kDomainNameLengthMax ],
-               const char *    inString,
-               uint8_t **              outEndPtr );
-static Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 );
-static size_t  DomainNameLength( const uint8_t *inName );
-static OSStatus        DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen );
-#define DomainNameDup( IN_NAME, OUT_NAME, OUT_LEN )                            DomainNameDupEx( IN_NAME, false, OUT_NAME, OUT_LEN )
-#define DomainNameDupLower( IN_NAME, OUT_NAME, OUT_LEN )               DomainNameDupEx( IN_NAME, true, OUT_NAME, OUT_LEN )
-
-static OSStatus
-       DomainNameFromString(
-               uint8_t                 inDomainName[ kDomainNameLengthMax ],
-               const char *    inString,
-               uint8_t **              outEndPtr );
-static OSStatus
-       DomainNameToString(
-               const uint8_t *         inDomainName,
-               const uint8_t *         inEnd,
-               char                            inBuf[ kDNSServiceMaxDomainName ],
-               const uint8_t **        outNextPtr );
-
-static OSStatus
-       DNSMessageToText(
-               const uint8_t * inMsgPtr,
-               size_t                  inMsgLen,
-               Boolean                 inIsMDNS,
-               Boolean                 inPrintRaw,
-               char **                 outText );
-
-#define kDNSQueryMessageMaxLen         ( kDNSHeaderLength + kDomainNameLengthMax + 4 )
-
-static OSStatus
-       WriteDNSQueryMessage(
-               uint8_t                 inMsg[ kDNSQueryMessageMaxLen ],
-               uint16_t                inMsgID,
-               uint16_t                inFlags,
-               const char *    inQName,
-               uint16_t                inQType,
-               uint16_t                inQClass,
-               size_t *                outMsgLen );
-
-// Dispatch helpers
-
-typedef void ( *DispatchHandler )( void *inContext );
-
-static OSStatus
-       DispatchSignalSourceCreate(
-               int                                     inSignal,
-               DispatchHandler         inEventHandler,
-               void *                          inContext,
-               dispatch_source_t *     outSource );
-static OSStatus
-       DispatchSocketSourceCreate(
-               SocketRef                               inSock,
-               dispatch_source_type_t  inType,
-               dispatch_queue_t                inQueue,
-               DispatchHandler                 inEventHandler,
-               DispatchHandler                 inCancelHandler,
-               void *                                  inContext,
-               dispatch_source_t *             outSource );
-
-#define DispatchReadSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
-       DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_READ, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
-
-#define DispatchWriteSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
-       DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_WRITE, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
-
-static OSStatus
-       DispatchTimerCreate(
-               dispatch_time_t         inStart,
-               uint64_t                        inIntervalNs,
-               uint64_t                        inLeewayNs,
-               dispatch_queue_t        inQueue,
-               DispatchHandler         inEventHandler,
-               DispatchHandler         inCancelHandler,
-               void *                          inContext,
-               dispatch_source_t *     outTimer );
-
-#define DispatchTimerOneShotCreate( IN_START, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, IN_CONTEXT, OUT_TIMER )   \
-       DispatchTimerCreate( IN_START, DISPATCH_TIME_FOREVER, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, NULL, IN_CONTEXT, OUT_TIMER )
-
-static OSStatus
-       DispatchProcessMonitorCreate(
-               pid_t                           inPID,
-               unsigned long           inFlags,
-               dispatch_queue_t        inQueue,
-               DispatchHandler         inEventHandler,
-               DispatchHandler         inCancelHandler,
-               void *                          inContext,
-               dispatch_source_t *     outMonitor );
-
-static const char *    ServiceTypeDescription( const char *inName );
-
-typedef struct
-{
-       SocketRef               sock;                   // Socket.
-       void *                  userContext;    // User context.
-       int32_t                 refCount;               // Reference count.
-       
-}      SocketContext;
-
-static OSStatus                        SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext );
-static SocketContext * SocketContextRetain( SocketContext *inContext );
-static void                            SocketContextRelease( SocketContext *inContext );
-static void                            SocketContextCancelHandler( void *inContext );
-
-#define ForgetSocketContext( X )       ForgetCustom( X, SocketContextRelease )
-
-static OSStatus                StringToInt32( const char *inString, int32_t *outValue );
-static OSStatus                StringToUInt32( const char *inString, uint32_t *outValue );
-#if( TARGET_OS_DARWIN )
-static OSStatus                StringToPID( const char *inString, pid_t *outPID );
-#endif
-static OSStatus                StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
-static OSStatus                StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
-static OSStatus                StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen );
-#if( TARGET_OS_DARWIN )
-static OSStatus                GetDefaultDNSServer( sockaddr_ip *outAddr );
-#endif
-static OSStatus
-       _ServerSocketOpenEx2( 
-               int                             inFamily, 
-               int                             inType, 
-               int                             inProtocol, 
-               const void *    inAddr, 
-               int                             inPort, 
-               int *                   outPort, 
-               int                             inRcvBufSize, 
-               Boolean                 inNoPortReuse,
-               SocketRef *             outSock );
-
-static const struct sockaddr * GetMDNSMulticastAddrV4( void );
-static const struct sockaddr * GetMDNSMulticastAddrV6( void );
-static OSStatus                                        GetAnyMDNSInterface( char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex );
-
-static OSStatus
-       CreateMulticastSocket(
-               const struct sockaddr * inAddr,
-               int                                             inPort,
-               const char *                    inIfName,
-               uint32_t                                inIfIndex,
-               Boolean                                 inJoin,
-               int *                                   outPort,
-               SocketRef *                             outSock );
-
-static OSStatus        DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr );
-static OSStatus        CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax );
-static OSStatus        CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax );
-static OSStatus        CheckRootUser( void );
-static OSStatus        SpawnCommand( pid_t *outPID, const char *inFormat, ... );
-static OSStatus
-       OutputPropertyList(
-               CFPropertyListRef       inPList,
-               OutputFormatType        inType,
-               Boolean                         inAppendNewline,
-               const char *            inOutputFilePath );
-static void
-       DNSRecordFixedFieldsSet(
-               DNSRecordFixedFields *  inFields,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint32_t                                inTTL,
-               uint16_t                                inRDLength );
-static void
-       SRVRecordDataFixedFieldsGet(
-               const SRVRecordDataFixedFields *        inFields,
-               unsigned int *                                          outPriority,
-               unsigned int *                                          outWeight,
-               unsigned int *                                          outPort );
-static void
-       SRVRecordDataFixedFieldsSet(
-               SRVRecordDataFixedFields *      inFields,
-               uint16_t                                        inPriority,
-               uint16_t                                        inWeight,
-               uint16_t                                        inPort );
-static void
-       SOARecordDataFixedFieldsGet(
-               const SOARecordDataFixedFields *        inFields,
-               uint32_t *                                                      outSerial,
-               uint32_t *                                                      outRefresh,
-               uint32_t *                                                      outRetry,
-               uint32_t *                                                      outExpire,
-               uint32_t *                                                      outMinimum );
-static void
-       SOARecordDataFixedFieldsSet(
-               SOARecordDataFixedFields *      inFields,
-               uint32_t                                        inSerial,
-               uint32_t                                        inRefresh,
-               uint32_t                                        inRetry,
-               uint32_t                                        inExpire,
-               uint32_t                                        inMinimum );
-static OSStatus        CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen );
-static OSStatus        CreateTXTRecordDataFromString( const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen );
-static OSStatus
-       CreateNSECRecordData(
-               const uint8_t * inNextDomainName,
-               uint8_t **              outPtr,
-               size_t *                outLen,
-               unsigned int    inTypeCount,
-               ... );
-static OSStatus
-       AppendSOARecord(
-               DataBuffer *    inDB,
-               const uint8_t * inNamePtr,
-               size_t                  inNameLen,
-               uint16_t                inType,
-               uint16_t                inClass,
-               uint32_t                inTTL,
-               const uint8_t * inMName,
-               const uint8_t * inRName,
-               uint32_t                inSerial,
-               uint32_t                inRefresh,
-               uint32_t                inRetry,
-               uint32_t                inExpire,
-               uint32_t                inMinimumTTL,
-               size_t *                outLen );
-static OSStatus
-       CreateSOARecordData(
-               const uint8_t * inMName,
-               const uint8_t * inRName,
-               uint32_t                inSerial,
-               uint32_t                inRefresh,
-               uint32_t                inRetry,
-               uint32_t                inExpire,
-               uint32_t                inMinimumTTL,
-               uint8_t **              outPtr,
-               size_t *                outLen );
-static OSStatus
-       _DataBuffer_AppendDNSQuestion(
-               DataBuffer *    inDB,
-               const uint8_t * inNamePtr,
-               size_t                  inNameLen,
-               uint16_t                inType,
-               uint16_t                inClass );
-static OSStatus
-       _DataBuffer_AppendDNSRecord(
-               DataBuffer *    inDB,
-               const uint8_t * inNamePtr,
-               size_t                  inNameLen,
-               uint16_t                inType,
-               uint16_t                inClass,
-               uint32_t                inTTL,
-               const uint8_t * inRDataPtr,
-               size_t                  inRDataLen );
-static char *  _NanoTime64ToDateString( NanoTime64 inTime, char *inBuf, size_t inMaxLen );
-
-#define Unused( X )            (void)(X)
-
-//===========================================================================================================================
-//     MDNSCollider
-//===========================================================================================================================
-
-typedef struct MDNSColliderPrivate *           MDNSColliderRef;
-
-typedef uint32_t               MDNSColliderProtocols;
-#define kMDNSColliderProtocol_None             0
-#define kMDNSColliderProtocol_IPv4             ( 1 << 0 )
-#define kMDNSColliderProtocol_IPv6             ( 1 << 1 )
-
-typedef void ( *MDNSColliderStopHandler_f )( void *inContext, OSStatus inError );
-
-static OSStatus        MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider );
-static OSStatus        MDNSColliderStart( MDNSColliderRef inCollider );
-static void            MDNSColliderStop( MDNSColliderRef inCollider );
-static void            MDNSColliderSetProtocols( MDNSColliderRef inCollider, MDNSColliderProtocols inProtocols );
-static void            MDNSColliderSetInterfaceIndex( MDNSColliderRef inCollider, uint32_t inInterfaceIndex );
-static OSStatus        MDNSColliderSetProgram( MDNSColliderRef inCollider, const char *inProgramStr );
-static void
-       MDNSColliderSetStopHandler(
-               MDNSColliderRef                         inCollider,
-               MDNSColliderStopHandler_f       inStopHandler,
-               void *                                          inStopContext );
-static OSStatus
-       MDNSColliderSetRecord(
-               MDNSColliderRef inCollider,
-               const uint8_t * inName,
-               uint16_t                inType,
-               const void *    inRDataPtr,
-               size_t                  inRDataLen );
-static CFTypeID        MDNSColliderGetTypeID( void );
-
-//===========================================================================================================================
-//     ServiceBrowser
-//===========================================================================================================================
-
-typedef struct ServiceBrowserPrivate *         ServiceBrowserRef;
-typedef struct ServiceBrowserResults           ServiceBrowserResults;
-typedef struct SBRDomain                                       SBRDomain;
-typedef struct SBRServiceType                          SBRServiceType;
-typedef struct SBRServiceInstance                      SBRServiceInstance;
-typedef struct SBRIPAddress                                    SBRIPAddress;
-
-typedef void ( *ServiceBrowserCallback_f )( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
-
-struct ServiceBrowserResults
-{
-       SBRDomain *             domainList;     // List of domains in which services were found.
-};
-
-struct SBRDomain
-{
-       SBRDomain *                             next;           // Next domain in list.
-       char *                                  name;           // Name of domain represented by this object.
-       SBRServiceType *                typeList;       // List of service types in this domain.
-};
-
-struct SBRServiceType
-{
-       SBRServiceType *                        next;                   // Next service type in list.
-       char *                                          name;                   // Name of service type represented by this object.
-       SBRServiceInstance *            instanceList;   // List of service instances of this service type.
-};
-
-struct SBRServiceInstance
-{
-       SBRServiceInstance *            next;                   // Next service instance in list.
-       char *                                          name;                   // Name of service instance represented by this object.
-       char *                                          hostname;               // Target from service instance's SRV record.
-       uint32_t                                        ifIndex;                // Index of interface over which this service instance was discovered.
-       uint16_t                                        port;                   // Port from service instance's SRV record.
-       uint8_t *                                       txtPtr;                 // Service instance's TXT record data.
-       size_t                                          txtLen;                 // Service instance's TXT record data length.
-       SBRIPAddress *                          ipaddrList;             // List of IP addresses that the hostname resolved to.
-       uint64_t                                        discoverTimeUs; // Time it took to discover this service instance in microseconds.
-       uint64_t                                        resolveTimeUs;  // Time it took to resolve this service instance in microseconds.
-};
-
-struct SBRIPAddress
-{
-       SBRIPAddress *          next;                   // Next IP address in list.
-       sockaddr_ip                     sip;                    // IPv4 or IPv6 address.
-       uint64_t                        resolveTimeUs;  // Time it took to resolve this IP address in microseconds.
-};
-
-static CFTypeID        ServiceBrowserGetTypeID( void );
-static OSStatus
-       ServiceBrowserCreate(
-               dispatch_queue_t        inQueue,
-               uint32_t                        inInterfaceIndex,
-               const char *            inDomain,
-               unsigned int            inBrowseTimeSecs,
-               Boolean                         inIncludeAWDL,
-               ServiceBrowserRef *     outBrowser );
-static void            ServiceBrowserStart( ServiceBrowserRef inBrowser );
-static OSStatus        ServiceBrowserAddServiceType( ServiceBrowserRef inBrowser, const char *inServiceType );
-static void
-       ServiceBrowserSetCallback(
-               ServiceBrowserRef                       inBrowser,
-               ServiceBrowserCallback_f        inCallback,
-               void *                                          inContext );
-static void            ServiceBrowserResultsRetain( ServiceBrowserResults *inResults );
-static void            ServiceBrowserResultsRelease( ServiceBrowserResults *inResults );
-
-#define ForgetServiceBrowserResults( X )               ForgetCustom( X, ServiceBrowserResultsRelease )
-
-//===========================================================================================================================
-//     main
-//===========================================================================================================================
-
-int    main( int argc, const char **argv )
-{
-       OSStatus                err;
-       
-       // Route DebugServices logging output to stderr.
-       
-       dlog_control( "DebugServices:output=file;stderr" );
-       
-       PrintFRegisterExtension( "du:time",    PrintFTimestampHandler,   NULL );
-       PrintFRegisterExtension( "du:dnsmsg",  PrintFDNSMessageHandler,  NULL );
-       PrintFRegisterExtension( "du:arflags", PrintFAddRmvFlagsHandler, NULL );
-       CLIInit( argc, argv );
-       err = CLIParse( kGlobalOpts, kCLIFlags_None );
-       if( err ) exit( 1 );
-       
-       return( gExitCode );
-}
-
-//===========================================================================================================================
-//     VersionOptionCallback
-//===========================================================================================================================
-
-static OSStatus        VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset )
-{
-       const char *            srcVers;
-#if( MDNSRESPONDER_PROJECT )
-       char                            srcStr[ 16 ];
-#endif
-       
-       Unused( inOption );
-       Unused( inArg );
-       Unused( inUnset );
-       
-#if( MDNSRESPONDER_PROJECT )
-       srcVers = SourceVersionToCString( _DNS_SD_H, srcStr );
-#else
-       srcVers = DNSSDUTIL_SOURCE_VERSION;
-#endif
-       FPrintF( stdout, "%s version %v (%s)\n", gProgramName, kDNSSDUtilNumVersion, srcVers );
-       
-       return( kEndingErr );
-}
-
-//===========================================================================================================================
-//     BrowseCmd
-//===========================================================================================================================
-
-typedef struct BrowseResolveOp         BrowseResolveOp;
-
-struct BrowseResolveOp
-{
-       BrowseResolveOp *               next;                   // Next resolve operation in list.
-       DNSServiceRef                   sdRef;                  // sdRef of the DNSServiceResolve or DNSServiceQueryRecord operation.
-       char *                                  fullName;               // Full name of the service to resolve.
-       uint32_t                                interfaceIndex; // Interface index of the DNSServiceResolve or DNSServiceQueryRecord operation.
-};
-
-typedef struct
-{
-       DNSServiceRef                   mainRef;                        // Main sdRef for shared connection.
-       DNSServiceRef *                 opRefs;                         // Array of sdRefs for individual Browse operarions.
-       size_t                                  opRefsCount;            // Count of array of sdRefs for non-shared connections.
-       const char *                    domain;                         // Domain for DNSServiceBrowse operation(s).
-       DNSServiceFlags                 flags;                          // Flags for DNSServiceBrowse operation(s).
-       char **                                 serviceTypes;           // Array of service types to browse for.
-       size_t                                  serviceTypesCount;      // Count of array of service types to browse for.
-       int                                             timeLimitSecs;          // Time limit of DNSServiceBrowse operation in seconds.
-       BrowseResolveOp *               resolveList;            // List of resolve and/or TXT record query operations.
-       uint32_t                                ifIndex;                        // Interface index of DNSServiceBrowse operation(s).
-       Boolean                                 printedHeader;          // True if results header has been printed.
-       Boolean                                 doResolve;                      // True if service instances are to be resolved.
-       Boolean                                 doResolveTXTOnly;       // True if TXT records of service instances are to be queried.
-       
-}      BrowseContext;
-
-static void            BrowsePrintPrologue( const BrowseContext *inContext );
-static void            BrowseContextFree( BrowseContext *inContext );
-static OSStatus        BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp );
-static void            BrowseResolveOpFree( BrowseResolveOp *inOp );
-static void DNSSD_API
-       BrowseCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inRegType,
-               const char *            inDomain,
-               void *                          inContext );
-static void DNSSD_API
-       BrowseResolveCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               uint16_t                                inTXTLen,
-               const unsigned char *   inTXTPtr,
-               void *                                  inContext );
-static void DNSSD_API
-       BrowseQueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-
-static void    BrowseCmd( void )
-{
-       OSStatus                                err;
-       size_t                                  i;
-       BrowseContext *                 context                 = NULL;
-       dispatch_source_t               signalSource    = NULL;
-       int                                             useMainConnection;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Create context.
-       
-       context = (BrowseContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->opRefs = (DNSServiceRef *) calloc( gBrowse_ServiceTypesCount, sizeof( DNSServiceRef ) );
-       require_action( context->opRefs, exit, err = kNoMemoryErr );
-       context->opRefsCount = gBrowse_ServiceTypesCount;
-       
-       // Check command parameters.
-       
-       if( gBrowse_TimeLimitSecs < 0 )
-       {
-               FPrintF( stderr, "Invalid time limit: %d seconds.\n", gBrowse_TimeLimitSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create main connection.
-       
-       if( gConnectionOpt )
-       {
-               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
-               require_noerr_quiet( err, exit );
-               useMainConnection = true;
-       }
-       else
-       {
-               useMainConnection = false;
-       }
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-       
-       // Get interface.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Set remaining parameters.
-       
-       context->serviceTypes           = gBrowse_ServiceTypes;
-       context->serviceTypesCount      = gBrowse_ServiceTypesCount;
-       context->domain                         = gBrowse_Domain;
-       context->doResolve                      = gBrowse_DoResolve     ? true : false;
-       context->timeLimitSecs          = gBrowse_TimeLimitSecs;
-       context->doResolveTXTOnly       = gBrowse_QueryTXT      ? true : false;
-       
-       // Print prologue.
-       
-       BrowsePrintPrologue( context );
-       
-       // Start operation(s).
-       
-       for( i = 0; i < context->serviceTypesCount; ++i )
-       {
-               DNSServiceRef           sdRef;
-               
-               sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
-               err = DNSServiceBrowse( &sdRef, context->flags, context->ifIndex, context->serviceTypes[ i ], context->domain,
-                       BrowseCallback, context );
-               require_noerr( err, exit );
-               
-               context->opRefs[ i ] = sdRef;
-               if( !useMainConnection )
-               {
-                       err = DNSServiceSetDispatchQueue( context->opRefs[ i ], dispatch_get_main_queue() );
-                       require_noerr( err, exit );
-               }
-       }
-       
-       // Set time limit.
-       
-       if( context->timeLimitSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
-                       kExitReason_TimeLimit, Exit );
-       }
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) BrowseContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     BrowsePrintPrologue
-//===========================================================================================================================
-
-static void    BrowsePrintPrologue( const BrowseContext *inContext )
-{
-       const int                                               timeLimitSecs   = inContext->timeLimitSecs;
-       const char * const *                    ptr                             = (const char **) inContext->serviceTypes;
-       const char * const * const              end                             = (const char **) inContext->serviceTypes + inContext->serviceTypesCount;
-       char                                                    ifName[ kInterfaceNameBufLen ];
-       
-       InterfaceIndexToName( inContext->ifIndex, ifName );
-       
-       FPrintF( stdout, "Flags:         %#{flags}\n",  inContext->flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:     %d (%s)\n",    (int32_t) inContext->ifIndex, ifName );
-       FPrintF( stdout, "Service types: %s",                   *ptr++ );
-       while( ptr < end ) FPrintF( stdout, ", %s",             *ptr++ );
-       FPrintF( stdout, "\n" );
-       FPrintF( stdout, "Domain:        %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
-       FPrintF( stdout, "Time limit:    " );
-       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
-       else                                    FPrintF( stdout, "∞\n" );
-       FPrintF( stdout, "Start time:    %{du:time}\n", NULL );
-       FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-//     BrowseContextFree
-//===========================================================================================================================
-
-static void    BrowseContextFree( BrowseContext *inContext )
-{
-       size_t          i;
-       
-       for( i = 0; i < inContext->opRefsCount; ++i )
-       {
-               DNSServiceForget( &inContext->opRefs[ i ] );
-       }
-       if( inContext->serviceTypes )
-       {
-               StringArray_Free( inContext->serviceTypes, inContext->serviceTypesCount );
-               inContext->serviceTypes                 = NULL;
-               inContext->serviceTypesCount    = 0;
-       }
-       DNSServiceForget( &inContext->mainRef );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     BrowseResolveOpCreate
-//===========================================================================================================================
-
-static OSStatus        BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp )
-{
-       OSStatus                                err;
-       BrowseResolveOp *               resolveOp;
-       
-       resolveOp = (BrowseResolveOp *) calloc( 1, sizeof( *resolveOp ) );
-       require_action( resolveOp, exit, err = kNoMemoryErr );
-       
-       resolveOp->fullName = strdup( inFullName );
-       require_action( resolveOp->fullName, exit, err = kNoMemoryErr );
-       
-       resolveOp->interfaceIndex = inInterfaceIndex;
-       
-       *outOp = resolveOp;
-       resolveOp = NULL;
-       err = kNoErr;
-       
-exit:
-       if( resolveOp ) BrowseResolveOpFree( resolveOp );
-       return( err );
-}
-
-//===========================================================================================================================
-//     BrowseResolveOpFree
-//===========================================================================================================================
-
-static void    BrowseResolveOpFree( BrowseResolveOp *inOp )
-{
-       DNSServiceForget( &inOp->sdRef );
-       ForgetMem( &inOp->fullName );
-       free( inOp );
-}
-
-//===========================================================================================================================
-//     BrowseCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       BrowseCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inRegType,
-               const char *            inDomain,
-               void *                          inContext )
-{
-       BrowseContext * const           context = (BrowseContext *) inContext;
-       OSStatus                                        err;
-       BrowseResolveOp *                       newOp = NULL;
-       BrowseResolveOp **                      p;
-       char                                            fullName[ kDNSServiceMaxDomainName ];
-       struct timeval                          now;
-       
-       Unused( inSDRef );
-       
-       gettimeofday( &now, NULL );
-       
-       err = inError;
-       require_noerr( err, exit );
-       
-       if( !context->printedHeader )
-       {
-               FPrintF( stdout, "%-26s  %-14s IF %-20s %-20s Instance Name\n", "Timestamp", "Flags", "Domain", "Service Type" );
-               context->printedHeader = true;
-       }
-       FPrintF( stdout, "%{du:time}  %{du:arflags} %2d %-20s %-20s %s\n",
-               &now, inFlags, (int32_t) inInterfaceIndex, inDomain, inRegType, inName );
-       
-       if( !context->doResolve && !context->doResolveTXTOnly ) goto exit;
-       
-       err = DNSServiceConstructFullName( fullName, inName, inRegType, inDomain );
-       require_noerr( err, exit );
-       
-       if( inFlags & kDNSServiceFlagsAdd )
-       {
-               DNSServiceRef           sdRef;
-               DNSServiceFlags         flags;
-               
-               err = BrowseResolveOpCreate( fullName, inInterfaceIndex, &newOp );
-               require_noerr( err, exit );
-               
-               if( context->mainRef )
-               {
-                       sdRef = context->mainRef;
-                       flags = kDNSServiceFlagsShareConnection;
-               }
-               else
-               {
-                       flags = 0;
-               }
-               if( context->doResolve )
-               {
-                       err = DNSServiceResolve( &sdRef, flags, inInterfaceIndex, inName, inRegType, inDomain, BrowseResolveCallback,
-                               NULL );
-                       require_noerr( err, exit );
-               }
-               else
-               {
-                       err = DNSServiceQueryRecord( &sdRef, flags, inInterfaceIndex, fullName, kDNSServiceType_TXT, kDNSServiceClass_IN,
-                               BrowseQueryRecordCallback, NULL );
-                       require_noerr( err, exit );
-               }
-               
-               newOp->sdRef = sdRef;
-               if( !context->mainRef )
-               {
-                       err = DNSServiceSetDispatchQueue( newOp->sdRef, dispatch_get_main_queue() );
-                       require_noerr( err, exit );
-               }
-               for( p = &context->resolveList; *p; p = &( *p )->next ) {}
-               *p = newOp;
-               newOp = NULL;
-       }
-       else
-       {
-               BrowseResolveOp *               resolveOp;
-               
-               for( p = &context->resolveList; ( resolveOp = *p ) != NULL; p = &resolveOp->next )
-               {
-                       if( ( resolveOp->interfaceIndex == inInterfaceIndex ) && ( strcasecmp( resolveOp->fullName, fullName ) == 0 ) )
-                       {
-                               break;
-                       }
-               }
-               if( resolveOp )
-               {
-                       *p = resolveOp->next;
-                       BrowseResolveOpFree( resolveOp );
-               }
-       }
-       
-exit:
-       if( newOp ) BrowseResolveOpFree( newOp );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     BrowseQueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       BrowseQueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       OSStatus                        err;
-       struct timeval          now;
-       
-       Unused( inSDRef );
-       Unused( inClass );
-       Unused( inTTL );
-       Unused( inContext );
-       
-       gettimeofday( &now, NULL );
-       
-       err = inError;
-       require_noerr( err, exit );
-       require_action( inType == kDNSServiceType_TXT, exit, err = kTypeErr );
-       
-       FPrintF( stdout, "%{du:time}  %s %s TXT on interface %d\n    TXT: %#{txt}\n",
-               &now, ( inFlags & kDNSServiceFlagsAdd ) ? "Add" : "Rmv", inFullName, (int32_t) inInterfaceIndex,
-               inRDataPtr, (size_t) inRDataLen );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     BrowseResolveCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       BrowseResolveCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               uint16_t                                inTXTLen,
-               const unsigned char *   inTXTPtr,
-               void *                                  inContext )
-{
-       struct timeval          now;
-       char                            errorStr[ 64 ];
-       
-       Unused( inSDRef );
-       Unused( inFlags );
-       Unused( inContext );
-       
-       gettimeofday( &now, NULL );
-       
-       if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
-       
-       FPrintF( stdout, "%{du:time}  %s can be reached at %s:%u (interface %d)%?s\n",
-               &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
-       if( inTXTLen == 1 )
-       {
-               FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
-       }
-       else
-       {
-               FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
-       }
-}
-
-//===========================================================================================================================
-//     GetAddrInfoCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSServiceRef                   mainRef;                // Main sdRef for shared connection.
-       DNSServiceRef                   opRef;                  // sdRef for the DNSServiceGetAddrInfo operation.
-       const char *                    name;                   // Hostname to resolve.
-       DNSServiceFlags                 flags;                  // Flags argument for DNSServiceGetAddrInfo().
-       DNSServiceProtocol              protocols;              // Protocols argument for DNSServiceGetAddrInfo().
-       uint32_t                                ifIndex;                // Interface index argument for DNSServiceGetAddrInfo().
-       int                                             timeLimitSecs;  // Time limit for the DNSServiceGetAddrInfo() operation in seconds.
-       Boolean                                 printedHeader;  // True if the results header has been printed.
-       Boolean                                 oneShotMode;    // True if command is done after the first set of results (one-shot mode).
-       Boolean                                 needIPv4;               // True if in one-shot mode and an IPv4 result is needed.
-       Boolean                                 needIPv6;               // True if in one-shot mode and an IPv6 result is needed.
-       
-}      GetAddrInfoContext;
-
-static void    GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext );
-static void    GetAddrInfoContextFree( GetAddrInfoContext *inContext );
-static void DNSSD_API
-       GetAddrInfoCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-
-static void    GetAddrInfoCmd( void )
-{
-       OSStatus                                        err;
-       DNSServiceRef                           sdRef;
-       GetAddrInfoContext *            context                 = NULL;
-       dispatch_source_t                       signalSource    = NULL;
-       int                                                     useMainConnection;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Check command parameters.
-       
-       if( gGetAddrInfo_TimeLimitSecs < 0 )
-       {
-               FPrintF( stderr, "Invalid time limit: %d s.\n", gGetAddrInfo_TimeLimitSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create context.
-       
-       context = (GetAddrInfoContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       // Create main connection.
-       
-       if( gConnectionOpt )
-       {
-               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
-               require_noerr_quiet( err, exit );
-               useMainConnection = true;
-       }
-       else
-       {
-               useMainConnection = false;
-       }
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-       
-       // Get interface.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Set remaining parameters.
-       
-       context->name                   = gGetAddrInfo_Name;
-       context->timeLimitSecs  = gGetAddrInfo_TimeLimitSecs;
-       if( gGetAddrInfo_ProtocolIPv4 ) context->protocols |= kDNSServiceProtocol_IPv4;
-       if( gGetAddrInfo_ProtocolIPv6 ) context->protocols |= kDNSServiceProtocol_IPv6;
-       if( gGetAddrInfo_OneShot )
-       {
-               context->oneShotMode    = true;
-               context->needIPv4               = ( gGetAddrInfo_ProtocolIPv4 || !gGetAddrInfo_ProtocolIPv6 ) ? true : false;
-               context->needIPv6               = ( gGetAddrInfo_ProtocolIPv6 || !gGetAddrInfo_ProtocolIPv4 ) ? true : false;
-       }
-       
-       // Print prologue.
-       
-       GetAddrInfoPrintPrologue( context );
-       
-       // Start operation.
-       
-       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
-       err = DNSServiceGetAddrInfo( &sdRef, context->flags, context->ifIndex, context->protocols, context->name,
-               GetAddrInfoCallback, context );
-       require_noerr( err, exit );
-       
-       context->opRef = sdRef;
-       if( !useMainConnection )
-       {
-               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
-               require_noerr( err, exit );
-       }
-       
-       // Set time limit.
-       
-       if( context->timeLimitSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
-                       kExitReason_TimeLimit, Exit );
-       }
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) GetAddrInfoContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     GetAddrInfoPrintPrologue
-//===========================================================================================================================
-
-static void    GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext )
-{
-       const int               timeLimitSecs = inContext->timeLimitSecs;
-       char                    ifName[ kInterfaceNameBufLen ];
-       
-       InterfaceIndexToName( inContext->ifIndex, ifName );
-       
-       FPrintF( stdout, "Flags:      %#{flags}\n",             inContext->flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:  %d (%s)\n",               (int32_t) inContext->ifIndex, ifName );
-       FPrintF( stdout, "Protocols:  %#{flags}\n",             inContext->protocols, kDNSServiceProtocolDescriptors );
-       FPrintF( stdout, "Name:       %s\n",                    inContext->name );
-       FPrintF( stdout, "Mode:       %s\n",                    inContext->oneShotMode ? "one-shot" : "continuous" );
-       FPrintF( stdout, "Time limit: " );
-       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
-       else                                    FPrintF( stdout, "∞\n" );
-       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
-       FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-//     GetAddrInfoContextFree
-//===========================================================================================================================
-
-static void    GetAddrInfoContextFree( GetAddrInfoContext *inContext )
-{
-       DNSServiceForget( &inContext->opRef );
-       DNSServiceForget( &inContext->mainRef );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     GetAddrInfoCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       GetAddrInfoCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       GetAddrInfoContext * const              context = (GetAddrInfoContext *) inContext;
-       struct timeval                                  now;
-       OSStatus                                                err;
-       const char *                                    addrStr;
-       char                                                    addrStrBuf[ kSockAddrStringMaxSize ];
-       
-       Unused( inSDRef );
-       
-       gettimeofday( &now, NULL );
-       
-       switch( inError )
-       {
-               case kDNSServiceErr_NoError:
-               case kDNSServiceErr_NoSuchRecord:
-                       err = kNoErr;
-                       break;
-               
-               case kDNSServiceErr_Timeout:
-                       Exit( kExitReason_Timeout );
-               
-               default:
-                       err = inError;
-                       goto exit;
-       }
-       
-       if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
-       {
-               dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
-               err = kTypeErr;
-               goto exit;
-       }
-       
-       if( !inError )
-       {
-               err = SockAddrToString( inSockAddr, kSockAddrStringFlagsNone, addrStrBuf );
-               require_noerr( err, exit );
-               addrStr = addrStrBuf;
-       }
-       else
-       {
-               addrStr = ( inSockAddr->sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr;
-       }
-       
-       if( !context->printedHeader )
-       {
-               FPrintF( stdout, "%-26s  %-14s IF %-32s %-38s %6s\n", "Timestamp", "Flags", "Hostname", "Address", "TTL" );
-               context->printedHeader = true;
-       }
-       FPrintF( stdout, "%{du:time}  %{du:arflags} %2d %-32s %-38s %6u\n",
-               &now, inFlags, (int32_t) inInterfaceIndex, inHostname, addrStr, inTTL );
-       
-       if( context->oneShotMode )
-       {
-               if( inFlags & kDNSServiceFlagsAdd )
-               {
-                       if( inSockAddr->sa_family == AF_INET )  context->needIPv4 = false;
-                       else                                                                    context->needIPv6 = false;
-               }
-               if( !( inFlags & kDNSServiceFlagsMoreComing ) && !context->needIPv4 && !context->needIPv6 )
-               {
-                       Exit( kExitReason_OneShotDone );
-               }
-       }
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     QueryRecordCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSServiceRef           mainRef;                // Main sdRef for shared connection.
-       DNSServiceRef           opRef;                  // sdRef for the DNSServiceQueryRecord operation.
-       const char *            recordName;             // Resource record name argument for DNSServiceQueryRecord().
-       DNSServiceFlags         flags;                  // Flags argument for DNSServiceQueryRecord().
-       uint32_t                        ifIndex;                // Interface index argument for DNSServiceQueryRecord().
-       int                                     timeLimitSecs;  // Time limit for the DNSServiceQueryRecord() operation in seconds.
-       uint16_t                        recordType;             // Resource record type argument for DNSServiceQueryRecord().
-       Boolean                         printedHeader;  // True if the results header was printed.
-       Boolean                         oneShotMode;    // True if command is done after the first set of results (one-shot mode).
-       Boolean                         gotRecord;              // True if in one-shot mode and received at least one record of the desired type.
-       Boolean                         printRawRData;  // True if RDATA results are not to be formatted when printed.
-       
-}      QueryRecordContext;
-
-static void    QueryRecordPrintPrologue( const QueryRecordContext *inContext );
-static void    QueryRecordContextFree( QueryRecordContext *inContext );
-static void DNSSD_API
-       QueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-
-static void    QueryRecordCmd( void )
-{
-       OSStatus                                        err;
-       DNSServiceRef                           sdRef;
-       QueryRecordContext *            context                 = NULL;
-       dispatch_source_t                       signalSource    = NULL;
-       int                                                     useMainConnection;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Create context.
-       
-       context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       // Check command parameters.
-       
-       if( gQueryRecord_TimeLimitSecs < 0 )
-       {
-               FPrintF( stderr, "Invalid time limit: %d seconds.\n", gQueryRecord_TimeLimitSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create main connection.
-       
-       if( gConnectionOpt )
-       {
-               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
-               require_noerr_quiet( err, exit );
-               useMainConnection = true;
-       }
-       else
-       {
-               useMainConnection = false;
-       }
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-       
-       // Get interface.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Get record type.
-       
-       err = RecordTypeFromArgString( gQueryRecord_Type, &context->recordType );
-       require_noerr( err, exit );
-       
-       // Set remaining parameters.
-       
-       context->recordName             = gQueryRecord_Name;
-       context->timeLimitSecs  = gQueryRecord_TimeLimitSecs;
-       context->oneShotMode    = gQueryRecord_OneShot  ? true : false;
-       context->printRawRData  = gQueryRecord_RawRData ? true : false;
-       
-       // Print prologue.
-       
-       QueryRecordPrintPrologue( context );
-       
-       // Start operation.
-       
-       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
-       err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
-               kDNSServiceClass_IN, QueryRecordCallback, context );
-       require_noerr( err, exit );
-       
-       context->opRef = sdRef;
-       if( !useMainConnection )
-       {
-               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
-               require_noerr( err, exit );
-       }
-       
-       // Set time limit.
-       
-       if( context->timeLimitSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_TimeLimit,
-                       Exit );
-       }
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) QueryRecordContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     QueryRecordContextFree
-//===========================================================================================================================
-
-static void    QueryRecordContextFree( QueryRecordContext *inContext )
-{
-       DNSServiceForget( &inContext->opRef );
-       DNSServiceForget( &inContext->mainRef );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     QueryRecordPrintPrologue
-//===========================================================================================================================
-
-static void    QueryRecordPrintPrologue( const QueryRecordContext *inContext )
-{
-       const int               timeLimitSecs = inContext->timeLimitSecs;
-       char                    ifName[ kInterfaceNameBufLen ];
-       
-       InterfaceIndexToName( inContext->ifIndex, ifName );
-       
-       FPrintF( stdout, "Flags:       %#{flags}\n",    inContext->flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:   %d (%s)\n",              (int32_t) inContext->ifIndex, ifName );
-       FPrintF( stdout, "Name:        %s\n",                   inContext->recordName );
-       FPrintF( stdout, "Type:        %s (%u)\n",              RecordTypeToString( inContext->recordType ), inContext->recordType );
-       FPrintF( stdout, "Mode:        %s\n",                   inContext->oneShotMode ? "one-shot" : "continuous" );
-       FPrintF( stdout, "Time limit:  " );
-       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
-       else                                    FPrintF( stdout, "∞\n" );
-       FPrintF( stdout, "Start time:  %{du:time}\n",   NULL );
-       FPrintF( stdout, "---\n" );
-       
-}
-
-//===========================================================================================================================
-//     QueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       QueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       QueryRecordContext * const              context         = (QueryRecordContext *) inContext;
-       struct timeval                                  now;
-       OSStatus                                                err;
-       char *                                                  rdataStr        = NULL;
-       
-       Unused( inSDRef );
-       
-       gettimeofday( &now, NULL );
-       
-       switch( inError )
-       {
-               case kDNSServiceErr_NoError:
-               case kDNSServiceErr_NoSuchRecord:
-                       err = kNoErr;
-                       break;
-               
-               case kDNSServiceErr_Timeout:
-                       Exit( kExitReason_Timeout );
-               
-               default:
-                       err = inError;
-                       goto exit;
-       }
-       
-       if( inError != kDNSServiceErr_NoSuchRecord )
-       {
-               if( !context->printRawRData ) DNSRecordDataToString( inRDataPtr, inRDataLen, inType, NULL, 0, &rdataStr );
-               if( !rdataStr )
-               {
-                       ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, INT_MAX );
-                       require_action( rdataStr, exit, err = kNoMemoryErr );
-               }
-       }
-       
-       if( !context->printedHeader )
-       {
-               FPrintF( stdout, "%-26s  %-14s IF %-32s %-5s %-5s %6s RData\n",
-                       "Timestamp", "Flags", "Name", "Type", "Class", "TTL" );
-               context->printedHeader = true;
-       }
-       FPrintF( stdout, "%{du:time}  %{du:arflags} %2d %-32s %-5s %?-5s%?5u %6u %s\n",
-               &now, inFlags, (int32_t) inInterfaceIndex, inFullName, RecordTypeToString( inType ),
-               ( inClass == kDNSServiceClass_IN ), "IN", ( inClass != kDNSServiceClass_IN ), inClass, inTTL,
-               rdataStr ? rdataStr : kNoSuchRecordStr );
-       
-       if( context->oneShotMode )
-       {
-               if( ( inFlags & kDNSServiceFlagsAdd ) &&
-                       ( ( context->recordType == kDNSServiceType_ANY ) || ( context->recordType == inType ) ) )
-               {
-                       context->gotRecord = true;
-               }
-               if( !( inFlags & kDNSServiceFlagsMoreComing ) && context->gotRecord ) Exit( kExitReason_OneShotDone );
-       }
-       
-exit:
-       FreeNullSafe( rdataStr );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     RegisterCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSRecordRef            recordRef;      // Reference returned by DNSServiceAddRecord().
-       uint8_t *                       dataPtr;        // Record data.
-       size_t                          dataLen;        // Record data length.
-       uint32_t                        ttl;            // Record TTL value.
-       uint16_t                        type;           // Record type.
-       
-}      ExtraRecord;
-
-typedef struct
-{
-       DNSServiceRef           opRef;                          // sdRef for DNSServiceRegister operation.
-       const char *            name;                           // Service name argument for DNSServiceRegister().
-       const char *            type;                           // Service type argument for DNSServiceRegister().
-       const char *            domain;                         // Domain in which advertise the service.
-       uint8_t *                       txtPtr;                         // Service TXT record data. (malloc'd)
-       size_t                          txtLen;                         // Service TXT record data len.
-       ExtraRecord *           extraRecords;           // Array of extra records to add to registered service.
-       size_t                          extraRecordsCount;      // Number of extra records.
-       uint8_t *                       updateTXTPtr;           // Pointer to record data for TXT record update. (malloc'd)
-       size_t                          updateTXTLen;           // Length of record data for TXT record update.
-       uint32_t                        updateTTL;                      // TTL of updated TXT record.
-       int                                     updateDelayMs;          // Post-registration TXT record update delay in milliseconds.
-       DNSServiceFlags         flags;                          // Flags argument for DNSServiceRegister().
-       uint32_t                        ifIndex;                        // Interface index argument for DNSServiceRegister().
-       int                                     lifetimeMs;                     // Lifetime of the record registration in milliseconds.
-       uint16_t                        port;                           // Service instance's port number.
-       Boolean                         printedHeader;          // True if results header was printed.
-       Boolean                         didRegister;            // True if service was registered.
-       
-}      RegisterContext;
-
-static void    RegisterPrintPrologue( const RegisterContext *inContext );
-static void    RegisterContextFree( RegisterContext *inContext );
-static void DNSSD_API
-       RegisterCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inType,
-               const char *            inDomain,
-               void *                          inContext );
-static void    RegisterUpdate( void *inContext );
-
-static void    RegisterCmd( void )
-{
-       OSStatus                                err;
-       RegisterContext *               context                 = NULL;
-       dispatch_source_t               signalSource    = NULL;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Create context.
-       
-       context = (RegisterContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       // Check command parameters.
-       
-       if( ( gRegister_Port < 0 ) || ( gRegister_Port > UINT16_MAX ) )
-       {
-               FPrintF( stderr, "Port number %d is out-of-range.\n", gRegister_Port );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       if( ( gAddRecord_DataCount != gAddRecord_TypesCount ) || ( gAddRecord_TTLsCount != gAddRecord_TypesCount ) )
-       {
-               FPrintF( stderr, "There are missing additional record parameters.\n" );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       
-       // Get interface index.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Get TXT record data.
-       
-       if( gRegister_TXT )
-       {
-               err = RecordDataFromArgString( gRegister_TXT, &context->txtPtr, &context->txtLen );
-               require_noerr_quiet( err, exit );
-       }
-       
-       // Set remaining parameters.
-       
-       context->name           = gRegister_Name;
-       context->type           = gRegister_Type;
-       context->domain         = gRegister_Domain;
-       context->port           = (uint16_t) gRegister_Port;
-       context->lifetimeMs     = gRegister_LifetimeMs;
-       
-       if( gAddRecord_TypesCount > 0 )
-       {
-               size_t          i;
-               
-               context->extraRecords = (ExtraRecord *) calloc( gAddRecord_TypesCount, sizeof( ExtraRecord ) );
-               require_action( context, exit, err = kNoMemoryErr );
-               context->extraRecordsCount = gAddRecord_TypesCount;
-               
-               for( i = 0; i < gAddRecord_TypesCount; ++i )
-               {
-                       ExtraRecord * const             extraRecord = &context->extraRecords[ i ];
-                       
-                       err = RecordTypeFromArgString( gAddRecord_Types[ i ], &extraRecord->type );
-                       require_noerr( err, exit );
-                       
-                       err = StringToUInt32( gAddRecord_TTLs[ i ], &extraRecord->ttl );
-                       if( err )
-                       {
-                               FPrintF( stderr, "Invalid TTL value: %s\n", gAddRecord_TTLs[ i ] );
-                               err = kParamErr;
-                               goto exit;
-                       }
-                       
-                       err = RecordDataFromArgString( gAddRecord_Data[ i ], &extraRecord->dataPtr, &extraRecord->dataLen );
-                       require_noerr_quiet( err, exit );
-               }
-       }
-       
-       if( gUpdateRecord_Data )
-       {
-               err = RecordDataFromArgString( gUpdateRecord_Data, &context->updateTXTPtr, &context->updateTXTLen );
-               require_noerr_quiet( err, exit );
-               
-               context->updateTTL              = (uint32_t) gUpdateRecord_TTL;
-               context->updateDelayMs  = gUpdateRecord_DelayMs;
-       }
-       
-       // Print prologue.
-       
-       RegisterPrintPrologue( context );
-       
-       // Start operation.
-       
-       err = DNSServiceRegister( &context->opRef, context->flags, context->ifIndex, context->name, context->type,
-               context->domain, NULL, htons( context->port ), (uint16_t) context->txtLen, context->txtPtr,
-               RegisterCallback, context );
-       ForgetMem( &context->txtPtr );
-       require_noerr( err, exit );
-       
-       err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
-       require_noerr( err, exit );
-       
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) RegisterContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     RegisterPrintPrologue
-//===========================================================================================================================
-
-static void    RegisterPrintPrologue( const RegisterContext *inContext )
-{
-       size_t          i;
-       int                     infinite;
-       char            ifName[ kInterfaceNameBufLen ];
-       
-       InterfaceIndexToName( inContext->ifIndex, ifName );
-       
-       FPrintF( stdout, "Flags:      %#{flags}\n",     inContext->flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:  %d (%s)\n",       (int32_t) inContext->ifIndex, ifName );
-       FPrintF( stdout, "Name:       %s\n",            inContext->name ? inContext->name : "<NULL>" );
-       FPrintF( stdout, "Type:       %s\n",            inContext->type );
-       FPrintF( stdout, "Domain:     %s\n",            inContext->domain ? inContext->domain : "<NULL> (default domains)" );
-       FPrintF( stdout, "Port:       %u\n",            inContext->port );
-       FPrintF( stdout, "TXT data:   %#{txt}\n",       inContext->txtPtr, inContext->txtLen );
-       infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
-       FPrintF( stdout, "Lifetime:   %?s%?d ms\n",     infinite, "∞", !infinite, inContext->lifetimeMs );
-       if( inContext->updateTXTPtr )
-       {
-               FPrintF( stdout, "\nUpdate record:\n" );
-               FPrintF( stdout, "    Delay:    %d ms\n",       ( inContext->updateDelayMs > 0 ) ? inContext->updateDelayMs : 0 );
-               FPrintF( stdout, "    TTL:      %u%?s\n",
-                       inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
-               FPrintF( stdout, "    TXT data: %#{txt}\n",     inContext->updateTXTPtr, inContext->updateTXTLen );
-       }
-       if( inContext->extraRecordsCount > 0 ) FPrintF( stdout, "\n" );
-       for( i = 0; i < inContext->extraRecordsCount; ++i )
-       {
-               const ExtraRecord *             record = &inContext->extraRecords[ i ];
-               
-               FPrintF( stdout, "Extra record %zu:\n",         i + 1 );
-               FPrintF( stdout, "    Type:  %s (%u)\n",        RecordTypeToString( record->type ), record->type );
-               FPrintF( stdout, "    TTL:   %u%?s\n",          record->ttl, record->ttl == 0, " (system will use a default value.)" );
-               FPrintF( stdout, "    RData: %#H\n\n",          record->dataPtr, (int) record->dataLen, INT_MAX );
-       }
-       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
-       FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-//     RegisterContextFree
-//===========================================================================================================================
-
-static void    RegisterContextFree( RegisterContext *inContext )
-{
-       ExtraRecord *                                   record;
-       const ExtraRecord * const               end = inContext->extraRecords + inContext->extraRecordsCount;
-       
-       DNSServiceForget( &inContext->opRef );
-       ForgetMem( &inContext->txtPtr );
-       for( record = inContext->extraRecords; record < end; ++record )
-       {
-               check( !record->recordRef );
-               ForgetMem( &record->dataPtr );
-       }
-       ForgetMem( &inContext->extraRecords );
-       ForgetMem( &inContext->updateTXTPtr );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     RegisterCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       RegisterCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inType,
-               const char *            inDomain,
-               void *                          inContext )
-{
-       RegisterContext * const         context = (RegisterContext *) inContext;
-       OSStatus                                        err;
-       struct timeval                          now;
-       
-       Unused( inSDRef );
-       
-       gettimeofday( &now, NULL );
-       
-       if( !context->printedHeader )
-       {
-               FPrintF( stdout, "%-26s  %-14s Service\n", "Timestamp", "Flags" );
-               context->printedHeader = true;
-       }
-       FPrintF( stdout, "%{du:time}  %{du:arflags} %s.%s%s %?#m\n", &now, inFlags, inName, inType, inDomain, inError, inError );
-       
-       require_noerr_action_quiet( inError, exit, err = inError );
-       
-       if( !context->didRegister && ( inFlags & kDNSServiceFlagsAdd ) )
-       {
-               context->didRegister = true;
-               if( context->updateTXTPtr )
-               {
-                       if( context->updateDelayMs > 0 )
-                       {
-                               dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
-                                       context, RegisterUpdate );
-                       }
-                       else
-                       {
-                               RegisterUpdate( context );
-                       }
-               }
-               if( context->extraRecordsCount > 0 )
-               {
-                       ExtraRecord *                                   record;
-                       const ExtraRecord * const               end = context->extraRecords + context->extraRecordsCount;
-                       
-                       for( record = context->extraRecords; record < end; ++record )
-                       {
-                               err = DNSServiceAddRecord( context->opRef, &record->recordRef, 0, record->type,
-                                       (uint16_t) record->dataLen, record->dataPtr, record->ttl );
-                               require_noerr( err, exit );
-                       }
-               }
-               if( context->lifetimeMs == 0 )
-               {
-                       Exit( kExitReason_TimeLimit );
-               }
-               else if( context->lifetimeMs > 0 )
-               {
-                       dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
-                               kExitReason_TimeLimit, Exit );
-               }
-       }
-       err = kNoErr;
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     RegisterUpdate
-//===========================================================================================================================
-
-static void    RegisterUpdate( void *inContext )
-{
-       OSStatus                                        err;
-       RegisterContext * const         context = (RegisterContext *) inContext;
-       
-       err = DNSServiceUpdateRecord( context->opRef, NULL, 0, (uint16_t) context->updateTXTLen, context->updateTXTPtr,
-               context->updateTTL );
-       require_noerr( err, exit );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     RegisterRecordCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSServiceRef           conRef;                 // sdRef to be initialized by DNSServiceCreateConnection().
-       DNSRecordRef            recordRef;              // Registered record reference.
-       const char *            recordName;             // Name of resource record.
-       uint8_t *                       dataPtr;                // Pointer to resource record data.
-       size_t                          dataLen;                // Length of resource record data.
-       uint32_t                        ttl;                    // TTL value of resource record in seconds.
-       uint32_t                        ifIndex;                // Interface index argument for DNSServiceRegisterRecord().
-       DNSServiceFlags         flags;                  // Flags argument for DNSServiceRegisterRecord().
-       int                                     lifetimeMs;             // Lifetime of the record registration in milliseconds.
-       uint16_t                        recordType;             // Resource record type.
-       uint8_t *                       updateDataPtr;  // Pointer to data for record update. (malloc'd)
-       size_t                          updateDataLen;  // Length of data for record update.
-       uint32_t                        updateTTL;              // TTL for updated record.
-       int                                     updateDelayMs;  // Post-registration record update delay in milliseconds.
-       Boolean                         didRegister;    // True if the record was registered.
-       
-}      RegisterRecordContext;
-
-static void    RegisterRecordPrintPrologue( const RegisterRecordContext *inContext );
-static void    RegisterRecordContextFree( RegisterRecordContext *inContext );
-static void DNSSD_API
-       RegisterRecordCallback(
-               DNSServiceRef           inSDRef,
-               DNSRecordRef            inRecordRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               void *                          inContext );
-static void    RegisterRecordUpdate( void *inContext );
-
-static void    RegisterRecordCmd( void )
-{
-       OSStatus                                        err;
-       RegisterRecordContext *         context                 = NULL;
-       dispatch_source_t                       signalSource    = NULL;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Create context.
-       
-       context = (RegisterRecordContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       // Create connection.
-       
-       err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->conRef, NULL );
-       require_noerr_quiet( err, exit );
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       
-       // Get interface.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Get record type.
-       
-       err = RecordTypeFromArgString( gRegisterRecord_Type, &context->recordType );
-       require_noerr( err, exit );
-       
-       // Get record data.
-       
-       if( gRegisterRecord_Data )
-       {
-               err = RecordDataFromArgString( gRegisterRecord_Data, &context->dataPtr, &context->dataLen );
-               require_noerr_quiet( err, exit );
-       }
-       
-       // Set remaining parameters.
-       
-       context->recordName     = gRegisterRecord_Name;
-       context->ttl            = (uint32_t) gRegisterRecord_TTL;
-       context->lifetimeMs     = gRegisterRecord_LifetimeMs;
-       
-       // Get update data.
-       
-       if( gRegisterRecord_UpdateData )
-       {
-               err = RecordDataFromArgString( gRegisterRecord_UpdateData, &context->updateDataPtr, &context->updateDataLen );
-               require_noerr_quiet( err, exit );
-               
-               context->updateTTL              = (uint32_t) gRegisterRecord_UpdateTTL;
-               context->updateDelayMs  = gRegisterRecord_UpdateDelayMs;
-       }
-       
-       // Print prologue.
-       
-       RegisterRecordPrintPrologue( context );
-       
-       // Start operation.
-       
-       err = DNSServiceRegisterRecord( context->conRef, &context->recordRef, context->flags, context->ifIndex,
-               context->recordName, context->recordType, kDNSServiceClass_IN, (uint16_t) context->dataLen, context->dataPtr,
-               context->ttl, RegisterRecordCallback, context );
-       if( err )
-       {
-               FPrintF( stderr, "DNSServiceRegisterRecord() returned %#m\n", err );
-               goto exit;
-       }
-       
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) RegisterRecordContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     RegisterRecordPrintPrologue
-//===========================================================================================================================
-
-static void    RegisterRecordPrintPrologue( const RegisterRecordContext *inContext )
-{
-       int                     infinite;
-       char            ifName[ kInterfaceNameBufLen ];
-       
-       InterfaceIndexToName( inContext->ifIndex, ifName );
-       
-       FPrintF( stdout, "Flags:       %#{flags}\n",    inContext->flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:   %d (%s)\n",              (int32_t) inContext->ifIndex, ifName );
-       FPrintF( stdout, "Name:        %s\n",                   inContext->recordName );
-       FPrintF( stdout, "Type:        %s (%u)\n",              RecordTypeToString( inContext->recordType ), inContext->recordType );
-       FPrintF( stdout, "TTL:         %u\n",                   inContext->ttl );
-       FPrintF( stdout, "Data:        %#H\n",                  inContext->dataPtr, (int) inContext->dataLen, INT_MAX );
-       infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
-       FPrintF( stdout, "Lifetime:    %?s%?d ms\n",    infinite, "∞", !infinite, inContext->lifetimeMs );
-       if( inContext->updateDataPtr )
-       {
-               FPrintF( stdout, "\nUpdate record:\n" );
-               FPrintF( stdout, "    Delay:    %d ms\n",       ( inContext->updateDelayMs >= 0 ) ? inContext->updateDelayMs : 0 );
-               FPrintF( stdout, "    TTL:      %u%?s\n",
-                       inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
-               FPrintF( stdout, "    RData:    %#H\n",         inContext->updateDataPtr, (int) inContext->updateDataLen, INT_MAX );
-       }
-       FPrintF( stdout, "Start time:  %{du:time}\n",   NULL );
-       FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-//     RegisterRecordContextFree
-//===========================================================================================================================
-
-static void    RegisterRecordContextFree( RegisterRecordContext *inContext )
-{
-       DNSServiceForget( &inContext->conRef );
-       ForgetMem( &inContext->dataPtr );
-       ForgetMem( &inContext->updateDataPtr );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     RegisterRecordCallback
-//===========================================================================================================================
-
-static void
-       RegisterRecordCallback(
-               DNSServiceRef           inSDRef,
-               DNSRecordRef            inRecordRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               void *                          inContext )
-{
-       RegisterRecordContext *         context = (RegisterRecordContext *) inContext;
-       struct timeval                          now;
-       
-       Unused( inSDRef );
-       Unused( inRecordRef );
-       Unused( inFlags );
-       Unused( context );
-       
-       gettimeofday( &now, NULL );
-       FPrintF( stdout, "%{du:time} Record registration result (error %#m)\n", &now, inError );
-       
-       if( !context->didRegister && !inError )
-       {
-               context->didRegister = true;
-               if( context->updateDataPtr )
-               {
-                       if( context->updateDelayMs > 0 )
-                       {
-                               dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
-                                       context, RegisterRecordUpdate );
-                       }
-                       else
-                       {
-                               RegisterRecordUpdate( context );
-                       }
-               }
-               if( context->lifetimeMs == 0 )
-               {
-                       Exit( kExitReason_TimeLimit );
-               }
-               else if( context->lifetimeMs > 0 )
-               {
-                       dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
-                               kExitReason_TimeLimit, Exit );
-               }
-       }
-}
-
-//===========================================================================================================================
-//     RegisterRecordUpdate
-//===========================================================================================================================
-
-static void    RegisterRecordUpdate( void *inContext )
-{
-       OSStatus                                                        err;
-       RegisterRecordContext * const           context = (RegisterRecordContext *) inContext;
-       
-       err = DNSServiceUpdateRecord( context->conRef, context->recordRef, 0, (uint16_t) context->updateDataLen,
-               context->updateDataPtr, context->updateTTL );
-       require_noerr( err, exit );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     ResolveCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSServiceRef           mainRef;                // Main sdRef for shared connections.
-       DNSServiceRef           opRef;                  // sdRef for the DNSServiceResolve operation.
-       DNSServiceFlags         flags;                  // Flags argument for DNSServiceResolve().
-       const char *            name;                   // Service name argument for DNSServiceResolve().
-       const char *            type;                   // Service type argument for DNSServiceResolve().
-       const char *            domain;                 // Domain argument for DNSServiceResolve().
-       uint32_t                        ifIndex;                // Interface index argument for DNSServiceResolve().
-       int                                     timeLimitSecs;  // Time limit for the DNSServiceResolve operation in seconds.
-       
-}      ResolveContext;
-
-static void    ResolvePrintPrologue( const ResolveContext *inContext );
-static void    ResolveContextFree( ResolveContext *inContext );
-static void DNSSD_API
-       ResolveCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               uint16_t                                inTXTLen,
-               const unsigned char *   inTXTPtr,
-               void *                                  inContext );
-
-static void    ResolveCmd( void )
-{
-       OSStatus                                err;
-       DNSServiceRef                   sdRef;
-       ResolveContext *                context                 = NULL;
-       dispatch_source_t               signalSource    = NULL;
-       int                                             useMainConnection;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Create context.
-       
-       context = (ResolveContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       // Check command parameters.
-       
-       if( gResolve_TimeLimitSecs < 0 )
-       {
-               FPrintF( stderr, "Invalid time limit: %d seconds.\n", gResolve_TimeLimitSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create main connection.
-       
-       if( gConnectionOpt )
-       {
-               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
-               require_noerr_quiet( err, exit );
-               useMainConnection = true;
-       }
-       else
-       {
-               useMainConnection = false;
-       }
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-       
-       // Get interface index.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Set remaining parameters.
-       
-       context->name                   = gResolve_Name;
-       context->type                   = gResolve_Type;
-       context->domain                 = gResolve_Domain;
-       context->timeLimitSecs  = gResolve_TimeLimitSecs;
-       
-       // Print prologue.
-       
-       ResolvePrintPrologue( context );
-       
-       // Start operation.
-       
-       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
-       err = DNSServiceResolve( &sdRef, context->flags, context->ifIndex, context->name, context->type, context->domain,
-               ResolveCallback, NULL );
-       require_noerr( err, exit );
-       
-       context->opRef = sdRef;
-       if( !useMainConnection )
-       {
-               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
-               require_noerr( err, exit );
-       }
-       
-       // Set time limit.
-       
-       if( context->timeLimitSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
-                       kExitReason_TimeLimit, Exit );
-       }
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) ResolveContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     ReconfirmCmd
-//===========================================================================================================================
-
-static void    ReconfirmCmd( void )
-{
-       OSStatus                        err;
-       uint8_t *                       rdataPtr = NULL;
-       size_t                          rdataLen = 0;
-       DNSServiceFlags         flags;
-       uint32_t                        ifIndex;
-       uint16_t                        type, class;
-       char                            ifName[ kInterfaceNameBufLen ];
-       
-       // Get flags.
-       
-       flags = GetDNSSDFlagsFromOpts();
-       
-       // Get interface index.
-       
-       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Get record type.
-       
-       err = RecordTypeFromArgString( gReconfirmRecord_Type, &type );
-       require_noerr( err, exit );
-       
-       // Get record data.
-       
-       if( gReconfirmRecord_Data )
-       {
-               err = RecordDataFromArgString( gReconfirmRecord_Data, &rdataPtr, &rdataLen );
-               require_noerr_quiet( err, exit );
-       }
-       
-       // Get record class.
-       
-       if( gReconfirmRecord_Class )
-       {
-               err = RecordClassFromArgString( gReconfirmRecord_Class, &class );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               class = kDNSServiceClass_IN;
-       }
-       
-       // Print prologue.
-       
-       FPrintF( stdout, "Flags:     %#{flags}\n",      flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface: %d (%s)\n",        (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
-       FPrintF( stdout, "Name:      %s\n",                     gReconfirmRecord_Name );
-       FPrintF( stdout, "Type:      %s (%u)\n",        RecordTypeToString( type ), type );
-       FPrintF( stdout, "Class:     %s (%u)\n",        ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
-       FPrintF( stdout, "Data:      %#H\n",            rdataPtr, (int) rdataLen, INT_MAX );
-       FPrintF( stdout, "---\n" );
-       
-       err = DNSServiceReconfirmRecord( flags, ifIndex, gReconfirmRecord_Name, type, class, (uint16_t) rdataLen, rdataPtr );
-       FPrintF( stdout, "Error:     %#m\n", err );
-       
-exit:
-       FreeNullSafe( rdataPtr );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     ResolvePrintPrologue
-//===========================================================================================================================
-
-static void    ResolvePrintPrologue( const ResolveContext *inContext )
-{
-       const int               timeLimitSecs = inContext->timeLimitSecs;
-       char                    ifName[ kInterfaceNameBufLen ];
-       
-       InterfaceIndexToName( inContext->ifIndex, ifName );
-       
-       FPrintF( stdout, "Flags:      %#{flags}\n",             inContext->flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:  %d (%s)\n",               (int32_t) inContext->ifIndex, ifName );
-       FPrintF( stdout, "Name:       %s\n",                    inContext->name );
-       FPrintF( stdout, "Type:       %s\n",                    inContext->type );
-       FPrintF( stdout, "Domain:     %s\n",                    inContext->domain );
-       FPrintF( stdout, "Time limit: " );
-       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
-       else                                    FPrintF( stdout, "∞\n" );
-       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
-       FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-//     ResolveContextFree
-//===========================================================================================================================
-
-static void    ResolveContextFree( ResolveContext *inContext )
-{
-       DNSServiceForget( &inContext->opRef );
-       DNSServiceForget( &inContext->mainRef );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     ResolveCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       ResolveCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               uint16_t                                inTXTLen,
-               const unsigned char *   inTXTPtr,
-               void *                                  inContext )
-{
-       struct timeval          now;
-       char                            errorStr[ 64 ];
-       
-       Unused( inSDRef );
-       Unused( inFlags );
-       Unused( inContext );
-       
-       gettimeofday( &now, NULL );
-       
-       if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
-       
-       FPrintF( stdout, "%{du:time}: %s can be reached at %s:%u (interface %d)%?s\n",
-               &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
-       if( inTXTLen == 1 )
-       {
-               FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
-       }
-       else
-       {
-               FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
-       }
-}
-
-//===========================================================================================================================
-//     GetAddrInfoPOSIXCmd
-//===========================================================================================================================
-
-#define AddressFamilyStr( X ) (                                \
-       ( (X) == AF_INET )              ? "inet"        :       \
-       ( (X) == AF_INET6 )             ? "inet6"       :       \
-       ( (X) == AF_UNSPEC )    ? "unspec"      :       \
-                                                         "???" )
-
-typedef struct
-{
-    unsigned int               flag;
-    const char *        str;
-
-}   FlagStringPair;
-
-#define CaseFlagStringify( X )         { (X), # X }
-
-const FlagStringPair           kGAIPOSIXFlagStringPairs[] =
-{
-#if( defined( AI_UNUSABLE ) )
-       CaseFlagStringify( AI_UNUSABLE ),
-#endif
-       CaseFlagStringify( AI_NUMERICSERV ),
-       CaseFlagStringify( AI_V4MAPPED ),
-       CaseFlagStringify( AI_ADDRCONFIG ),
-#if( defined( AI_V4MAPPED_CFG ) )
-       CaseFlagStringify( AI_V4MAPPED_CFG ),
-#endif
-       CaseFlagStringify( AI_ALL ),
-       CaseFlagStringify( AI_NUMERICHOST ),
-       CaseFlagStringify( AI_CANONNAME ),
-       CaseFlagStringify( AI_PASSIVE ),
-       { 0, NULL }
-};
-
-static void    GetAddrInfoPOSIXCmd( void )
-{
-       OSStatus                                        err;
-       struct addrinfo                         hints;
-       struct timeval                          now;
-       const struct addrinfo *         addrInfo;
-       struct addrinfo *                       addrInfoList = NULL;
-       const FlagStringPair *          pair;
-       
-       memset( &hints, 0, sizeof( hints ) );
-       hints.ai_socktype = SOCK_STREAM;
-       
-       // Set hints address family.
-       
-       if( !gGAIPOSIX_Family )                                                                         hints.ai_family = AF_UNSPEC;
-       else if( strcasecmp( gGAIPOSIX_Family, "inet" ) == 0 )          hints.ai_family = AF_INET;
-       else if( strcasecmp( gGAIPOSIX_Family, "inet6" ) == 0 )         hints.ai_family = AF_INET6;
-       else if( strcasecmp( gGAIPOSIX_Family, "unspec" ) == 0 )        hints.ai_family = AF_UNSPEC;
-       else
-       {
-               FPrintF( stderr, "Invalid address family: %s.\n", gGAIPOSIX_Family );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Set hints flags.
-       
-       if( gGAIPOSIXFlag_AddrConfig )  hints.ai_flags |= AI_ADDRCONFIG;
-       if( gGAIPOSIXFlag_All )                 hints.ai_flags |= AI_ALL;
-       if( gGAIPOSIXFlag_CanonName )   hints.ai_flags |= AI_CANONNAME;
-       if( gGAIPOSIXFlag_NumericHost ) hints.ai_flags |= AI_NUMERICHOST;
-       if( gGAIPOSIXFlag_NumericServ ) hints.ai_flags |= AI_NUMERICSERV;
-       if( gGAIPOSIXFlag_Passive )             hints.ai_flags |= AI_PASSIVE;
-       if( gGAIPOSIXFlag_V4Mapped )    hints.ai_flags |= AI_V4MAPPED;
-#if( defined( AI_V4MAPPED_CFG ) )
-       if( gGAIPOSIXFlag_V4MappedCFG ) hints.ai_flags |= AI_V4MAPPED_CFG;
-#endif
-#if( defined( AI_DEFAULT ) )
-       if( gGAIPOSIXFlag_Default )             hints.ai_flags |= AI_DEFAULT;
-#endif
-#if( defined( AI_UNUSABLE ) )
-       if( gGAIPOSIXFlag_Unusable )    hints.ai_flags |= AI_UNUSABLE;
-#endif
-       
-       // Print prologue.
-       
-       FPrintF( stdout, "Hostname:       %s\n",        gGAIPOSIX_HostName );
-       FPrintF( stdout, "Servname:       %s\n",        gGAIPOSIX_ServName );
-       FPrintF( stdout, "Address family: %s\n",        AddressFamilyStr( hints.ai_family ) );
-       FPrintF( stdout, "Flags:          0x%X < ",     hints.ai_flags );
-       for( pair = kGAIPOSIXFlagStringPairs; pair->str != NULL; ++pair )
-       {
-               if( ( (unsigned int) hints.ai_flags ) & pair->flag ) FPrintF( stdout, "%s ", pair->str );
-       }
-       FPrintF( stdout, ">\n" );
-       FPrintF( stdout, "Start time:     %{du:time}\n", NULL );
-       FPrintF( stdout, "---\n" );
-       
-       // Call getaddrinfo().
-       
-       err = getaddrinfo( gGAIPOSIX_HostName, gGAIPOSIX_ServName, &hints, &addrInfoList );
-       gettimeofday( &now, NULL );
-       if( err )
-       {
-               FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
-       }
-       else
-       {
-               int             addrCount = 0;
-               
-               for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next ) { ++addrCount; }
-               
-               FPrintF( stdout, "Addresses (%d total):\n", addrCount );
-               for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next )
-               {
-                       FPrintF( stdout, "%##a\n", addrInfo->ai_addr );
-               }
-       }
-       FPrintF( stdout, "---\n" );
-       FPrintF( stdout, "End time:       %{du:time}\n", &now );
-       
-exit:
-       if( addrInfoList ) freeaddrinfo( addrInfoList );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     ReverseLookupCmd
-//===========================================================================================================================
-
-#define kIP6ARPADomainStr              "ip6.arpa."
-
-static void    ReverseLookupCmd( void )
-{
-       OSStatus                                        err;
-       QueryRecordContext *            context                 = NULL;
-       DNSServiceRef                           sdRef;
-       dispatch_source_t                       signalSource    = NULL;
-       uint32_t                                        ipv4Addr;
-       uint8_t                                         ipv6Addr[ 16 ];
-       char                                            recordName[ ( 16 * 4 ) + sizeof( kIP6ARPADomainStr ) ];
-       int                                                     useMainConnection;
-       const char *                            endPtr;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Create context.
-       
-       context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       // Check command parameters.
-       
-       if( gReverseLookup_TimeLimitSecs < 0 )
-       {
-               FPrintF( stderr, "Invalid time limit: %d s.\n", gReverseLookup_TimeLimitSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create main connection.
-       
-       if( gConnectionOpt )
-       {
-               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
-               require_noerr_quiet( err, exit );
-               useMainConnection = true;
-       }
-       else
-       {
-               useMainConnection = false;
-       }
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-       
-       // Get interface index.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Create reverse lookup record name.
-       
-       err = StringToIPv4Address( gReverseLookup_IPAddr, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix,
-               &ipv4Addr, NULL, NULL, NULL, &endPtr );
-       if( err || ( *endPtr != '\0' ) )
-       {
-               char *          dst;
-               int                     i;
-               
-               err = StringToIPv6Address( gReverseLookup_IPAddr,
-                       kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
-                       ipv6Addr, NULL, NULL, NULL, &endPtr );
-               if( err || ( *endPtr != '\0' ) )
-               {
-                       FPrintF( stderr, "Invalid IP address: \"%s\".\n", gReverseLookup_IPAddr );
-                       err = kParamErr;
-                       goto exit;
-               }
-               dst = recordName;
-               for( i = 15; i >= 0; --i )
-               {
-                       *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] & 0x0F ];
-                       *dst++ = '.';
-                       *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] >> 4 ];
-                       *dst++ = '.';
-               }
-               strcpy_literal( dst, kIP6ARPADomainStr );
-               check( ( strlen( recordName ) + 1 ) <= sizeof( recordName ) );
-       }
-       else
-       {
-               SNPrintF( recordName, sizeof( recordName ), "%u.%u.%u.%u.in-addr.arpa.",
-                         ipv4Addr         & 0xFF,
-                       ( ipv4Addr >>  8 ) & 0xFF,
-                       ( ipv4Addr >> 16 ) & 0xFF,
-                       ( ipv4Addr >> 24 ) & 0xFF );
-       }
-       
-       // Set remaining parameters.
-       
-       context->recordName             = recordName;
-       context->recordType             = kDNSServiceType_PTR;
-       context->timeLimitSecs  = gReverseLookup_TimeLimitSecs;
-       context->oneShotMode    = gReverseLookup_OneShot ? true : false;
-       
-       // Print prologue.
-       
-       QueryRecordPrintPrologue( context );
-       
-       // Start operation.
-       
-       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
-       err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
-               kDNSServiceClass_IN, QueryRecordCallback, context );
-       require_noerr( err, exit );
-       
-       context->opRef = sdRef;
-       if( !useMainConnection )
-       {
-               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
-               require_noerr( err, exit );
-       }
-       
-       // Set time limit.
-       
-       if( context->timeLimitSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
-                       kExitReason_TimeLimit, Exit );
-       }
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) QueryRecordContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     PortMappingCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSServiceRef                   mainRef;                // Main sdRef for shared connection.
-       DNSServiceRef                   opRef;                  // sdRef for the DNSServiceNATPortMappingCreate operation.
-       DNSServiceFlags                 flags;                  // Flags for DNSServiceNATPortMappingCreate operation.
-       uint32_t                                ifIndex;                // Interface index argument for DNSServiceNATPortMappingCreate operation.
-       DNSServiceProtocol              protocols;              // Protocols argument for DNSServiceNATPortMappingCreate operation.
-       uint32_t                                ttl;                    // TTL argument for DNSServiceNATPortMappingCreate operation.
-       uint16_t                                internalPort;   // Internal port argument for DNSServiceNATPortMappingCreate operation.
-       uint16_t                                externalPort;   // External port argument for DNSServiceNATPortMappingCreate operation.
-       Boolean                                 printedHeader;  // True if results header was printed.
-       
-}      PortMappingContext;
-
-static void    PortMappingPrintPrologue( const PortMappingContext *inContext );
-static void    PortMappingContextFree( PortMappingContext *inContext );
-static void DNSSD_API
-       PortMappingCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inError,
-               uint32_t                        inExternalIPv4Address,
-               DNSServiceProtocol      inProtocol,
-               uint16_t                        inInternalPort,
-               uint16_t                        inExternalPort,
-               uint32_t                        inTTL,
-               void *                          inContext );
-
-static void    PortMappingCmd( void )
-{
-       OSStatus                                        err;
-       PortMappingContext *            context                 = NULL;
-       DNSServiceRef                           sdRef;
-       dispatch_source_t                       signalSource    = NULL;
-       int                                                     useMainConnection;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Create context.
-       
-       context = (PortMappingContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       // Check command parameters.
-       
-       if( ( gPortMapping_InternalPort < 0 ) || ( gPortMapping_InternalPort > UINT16_MAX ) )
-       {
-               FPrintF( stderr, "Internal port number %d is out-of-range.\n", gPortMapping_InternalPort );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       if( ( gPortMapping_ExternalPort < 0 ) || ( gPortMapping_ExternalPort > UINT16_MAX ) )
-       {
-               FPrintF( stderr, "External port number %d is out-of-range.\n", gPortMapping_ExternalPort );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create main connection.
-       
-       if( gConnectionOpt )
-       {
-               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
-               require_noerr_quiet( err, exit );
-               useMainConnection = true;
-       }
-       else
-       {
-               useMainConnection = false;
-       }
-       
-       // Get flags.
-       
-       context->flags = GetDNSSDFlagsFromOpts();
-       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
-       
-       // Get interface index.
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Set remaining parameters.
-       
-       if( gPortMapping_ProtocolTCP ) context->protocols |= kDNSServiceProtocol_TCP;
-       if( gPortMapping_ProtocolUDP ) context->protocols |= kDNSServiceProtocol_UDP;
-       context->ttl                    = (uint32_t) gPortMapping_TTL;
-       context->internalPort   = (uint16_t) gPortMapping_InternalPort;
-       context->externalPort   = (uint16_t) gPortMapping_ExternalPort;
-       
-       // Print prologue.
-       
-       PortMappingPrintPrologue( context );
-       
-       // Start operation.
-       
-       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
-       err = DNSServiceNATPortMappingCreate( &sdRef, context->flags, context->ifIndex, context->protocols,
-               htons( context->internalPort ), htons( context->externalPort ), context->ttl, PortMappingCallback, context );
-       require_noerr( err, exit );
-       
-       context->opRef = sdRef;
-       if( !useMainConnection )
-       {
-               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
-               require_noerr( err, exit );
-       }
-       
-       dispatch_main();
-       
-exit:
-       dispatch_source_forget( &signalSource );
-       if( context ) PortMappingContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     PortMappingPrintPrologue
-//===========================================================================================================================
-
-static void    PortMappingPrintPrologue( const PortMappingContext *inContext )
-{
-       char            ifName[ kInterfaceNameBufLen ];
-       
-       InterfaceIndexToName( inContext->ifIndex, ifName );
-       
-       FPrintF( stdout, "Flags:         %#{flags}\n",          inContext->flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:     %d (%s)\n",            (int32_t) inContext->ifIndex, ifName );
-       FPrintF( stdout, "Protocols:     %#{flags}\n",          inContext->protocols, kDNSServiceProtocolDescriptors );
-       FPrintF( stdout, "Internal Port: %u\n",                         inContext->internalPort );
-       FPrintF( stdout, "External Port: %u\n",                         inContext->externalPort );
-       FPrintF( stdout, "TTL:           %u%?s\n",                      inContext->ttl, !inContext->ttl,
-               " (system will use a default value.)" );
-       FPrintF( stdout, "Start time:    %{du:time}\n", NULL );
-       FPrintF( stdout, "---\n" );
-       
-}
-
-//===========================================================================================================================
-//     PortMappingContextFree
-//===========================================================================================================================
-
-static void    PortMappingContextFree( PortMappingContext *inContext )
-{
-       DNSServiceForget( &inContext->opRef );
-       DNSServiceForget( &inContext->mainRef );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     PortMappingCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       PortMappingCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inError,
-               uint32_t                        inExternalIPv4Address,
-               DNSServiceProtocol      inProtocol,
-               uint16_t                        inInternalPort,
-               uint16_t                        inExternalPort,
-               uint32_t                        inTTL,
-               void *                          inContext )
-{
-       PortMappingContext * const              context = (PortMappingContext *) inContext;
-       struct timeval                                  now;
-       char                                                    errorStr[ 128 ];
-       
-       Unused( inSDRef );
-       Unused( inFlags );
-       
-       gettimeofday( &now, NULL );
-       
-       if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " (error: %#m)", inError );
-       if( !context->printedHeader )
-       {
-               FPrintF( stdout, "%-26s  IF %7s %15s %7s %6s Protocol\n", "Timestamp", "IntPort", "ExtAddr", "ExtPort", "TTL" );
-               context->printedHeader = true;
-       }
-       FPrintF( stdout, "%{du:time}  %2u %7u %15.4a %7u %6u %#{flags}%?s\n",
-               &now, inInterfaceIndex, ntohs( inInternalPort), &inExternalIPv4Address, ntohs( inExternalPort ), inTTL,
-               inProtocol, kDNSServiceProtocolDescriptors, inError, errorStr );
-}
-
-//===========================================================================================================================
-//     BrowseAllCmd
-//===========================================================================================================================
-
-typedef struct BrowseAllConnection             BrowseAllConnection;
-
-typedef struct
-{
-       ServiceBrowserRef                       browser;                                // Service browser.
-       ServiceBrowserResults *         results;                                // Results from the service browser.
-       BrowseAllConnection *           connectionList;                 // List of connections.
-       dispatch_source_t                       connectionTimer;                // Timer for connection timeout.
-       int                                                     connectionPendingCount; // Number of pending connections.
-       int                                                     connectionTimeoutSecs;  // Timeout value for connections in seconds.
-       
-}      BrowseAllContext;
-
-struct BrowseAllConnection
-{
-       BrowseAllConnection *           next;                           // Next connection object in list.
-       sockaddr_ip                                     sip;                            // IPv4 or IPv6 address to connect to.
-       uint16_t                                        port;                           // TCP port to connect to.
-       AsyncConnectionRef                      asyncCnx;                       // AsyncConnection object to handle the actual connection.
-       OSStatus                                        status;                         // Status of connection. NoErr means connection succeeded.
-       CFTimeInterval                          connectTimeSecs;        // Time it took to connect in seconds.
-       int32_t                                         refCount;                       // This object's reference count.
-       BrowseAllContext *                      context;                        // Back pointer to parent context.
-};
-
-static void    _BrowseAllContextFree( BrowseAllContext *inContext );
-static void    _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
-static OSStatus
-       _BrowseAllConnectionCreate(
-               const struct sockaddr * inSockAddr,
-               uint16_t                                inPort,
-               BrowseAllContext *              inContext,
-               BrowseAllConnection **  outConnection );
-static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection );
-static void    _BrowseAllConnectionRelease( BrowseAllConnection *inConnection );
-static void    _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg );
-static void    _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg );
-static void    _BrowseAllExit( void *inContext );
-
-static Boolean _IsServiceTypeTCP( const char *inServiceType );
-
-static void    BrowseAllCmd( void )
-{
-       OSStatus                                err;
-       BrowseAllContext *              context = NULL;
-       size_t                                  i;
-       uint32_t                                ifIndex;
-       char                                    ifName[ kInterfaceNameBufLen ];
-       
-       // Check parameters.
-       
-       if( gBrowseAll_BrowseTimeSecs <= 0 )
-       {
-               FPrintF( stdout, "Invalid browse time: %d seconds.\n", gBrowseAll_BrowseTimeSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       context = (BrowseAllContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->connectionTimeoutSecs  = gBrowseAll_ConnectTimeout;
-#if( TARGET_OS_POSIX )
-       // Increase the open file descriptor limit for connection sockets.
-       
-       if( context->connectionTimeoutSecs > 0 )
-       {
-               struct rlimit           fdLimits;
-               
-               err = getrlimit( RLIMIT_NOFILE, &fdLimits );
-               err = map_global_noerr_errno( err );
-               require_noerr( err, exit );
-               
-               if( fdLimits.rlim_cur < 4096 )
-               {
-                       fdLimits.rlim_cur = 4096;
-                       err = setrlimit( RLIMIT_NOFILE, &fdLimits );
-                       err = map_global_noerr_errno( err );
-                       require_noerr( err, exit );
-               }
-       }
-#endif
-       
-       // Get interface index.
-       
-       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       // Print prologue.
-       
-       FPrintF( stdout, "Interface:       %d (%s)\n",  (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
-       FPrintF( stdout, "Service types:   ");
-       if( gBrowseAll_ServiceTypesCount > 0 )
-       {
-               FPrintF( stdout, "%s", gBrowseAll_ServiceTypes[ 0 ] );
-               for( i = 1; i < gBrowseAll_ServiceTypesCount; ++i )
-               {
-                       FPrintF( stdout, ", %s", gBrowseAll_ServiceTypes[ i ] );
-               }
-               FPrintF( stdout, "\n" );
-       }
-       else
-       {
-               FPrintF( stdout, "all services\n" );
-       }
-       FPrintF( stdout, "Domain:          %s\n", gBrowseAll_Domain ? gBrowseAll_Domain : "default domains" );
-       FPrintF( stdout, "Browse time:     %d second%?c\n", gBrowseAll_BrowseTimeSecs, gBrowseAll_BrowseTimeSecs != 1, 's' );
-       FPrintF( stdout, "Connect timeout: %d second%?c\n",
-               context->connectionTimeoutSecs, context->connectionTimeoutSecs != 1, 's' );
-       FPrintF( stdout, "IncludeAWDL:     %s\n", gDNSSDFlag_IncludeAWDL ? "yes" : "no" );
-       FPrintF( stdout, "Start time:      %{du:time}\n", NULL );
-       FPrintF( stdout, "---\n" );
-       
-       err = ServiceBrowserCreate( dispatch_get_main_queue(), ifIndex, gBrowseAll_Domain,
-               (unsigned int) gBrowseAll_BrowseTimeSecs, gDNSSDFlag_IncludeAWDL ? true : false, &context->browser );
-       require_noerr( err, exit );
-       
-       for( i = 0; i < gBrowseAll_ServiceTypesCount; ++i )
-       {
-               err = ServiceBrowserAddServiceType( context->browser, gBrowseAll_ServiceTypes[ i ] );
-               require_noerr( err, exit );
-       }
-       ServiceBrowserSetCallback( context->browser, _BrowseAllServiceBrowserCallback, context );
-       ServiceBrowserStart( context->browser );
-       dispatch_main();
-       
-exit:
-       if( context ) _BrowseAllContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     _BrowseAllContextFree
-//===========================================================================================================================
-
-static void    _BrowseAllContextFree( BrowseAllContext *inContext )
-{
-       check( !inContext->browser );
-       check( !inContext->connectionTimer );
-       check( !inContext->connectionList );
-       ForgetServiceBrowserResults( &inContext->results );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     _BrowseAllServiceBrowserCallback
-//===========================================================================================================================
-
-#define kDiscardProtocolPort           9
-
-static void    _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
-{
-       OSStatus                                                err;
-       BrowseAllContext * const                context = (BrowseAllContext *) inContext;
-       SBRDomain *                                             domain;
-       SBRServiceType *                                type;
-       SBRServiceInstance *                    instance;
-       SBRIPAddress *                                  ipaddr;
-       
-       Unused( inError );
-       
-       require_action( inResults, exit, err = kUnexpectedErr );
-       
-       check( !context->results );
-       context->results = inResults;
-       ServiceBrowserResultsRetain( context->results );
-       
-       check( context->connectionPendingCount == 0 );
-       if( context->connectionTimeoutSecs > 0 )
-       {
-               BrowseAllConnection *                   connection;
-               BrowseAllConnection **                  connectionPtr = &context->connectionList;
-               char                                                    destination[ kSockAddrStringMaxSize ];
-               
-               for( domain = context->results->domainList; domain; domain = domain->next )
-               {
-                       for( type = domain->typeList; type; type = type->next )
-                       {
-                               if( !_IsServiceTypeTCP( type->name ) ) continue;
-                               for( instance = type->instanceList; instance; instance = instance->next )
-                               {
-                                       if( instance->port == kDiscardProtocolPort ) continue;
-                                       for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
-                                       {
-                                               err = _BrowseAllConnectionCreate( &ipaddr->sip.sa, instance->port, context, &connection );
-                                               require_noerr( err, exit );
-                                               
-                                               *connectionPtr = connection;
-                                                connectionPtr = &connection->next;
-                                               
-                                               err = SockAddrToString( &ipaddr->sip, kSockAddrStringFlagsNoPort, destination );
-                                               check_noerr( err );
-                                               if( !err )
-                                               {
-                                                       err = AsyncConnection_Connect( &connection->asyncCnx, destination, -instance->port,
-                                                               kAsyncConnectionFlag_P2P, kAsyncConnectionNoTimeout,
-                                                               kSocketBufferSize_DontSet, kSocketBufferSize_DontSet,
-                                                               _BrowseAllConnectionProgress, connection, _BrowseAllConnectionHandler, connection,
-                                                               dispatch_get_main_queue() );
-                                                       check_noerr( err );
-                                               }
-                                               if( !err )
-                                               {
-                                                       _BrowseAllConnectionRetain( connection );
-                                                       connection->status = kInProgressErr;
-                                                       ++context->connectionPendingCount;
-                                               }
-                                               else
-                                               {
-                                                       connection->status = err;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       if( context->connectionPendingCount > 0 )
-       {
-               check( !context->connectionTimer );
-               err = DispatchTimerCreate( dispatch_time_seconds( context->connectionTimeoutSecs ), DISPATCH_TIME_FOREVER,
-                       100 * kNanosecondsPerMillisecond, NULL, _BrowseAllExit, NULL, context, &context->connectionTimer );
-               require_noerr( err, exit );
-               dispatch_resume( context->connectionTimer );
-       }
-       else
-       {
-               dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
-       }
-       err = kNoErr;
-       
-exit:
-       ForgetCF( &context->browser );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     _BrowseAllConnectionCreate
-//===========================================================================================================================
-
-static OSStatus
-       _BrowseAllConnectionCreate(
-               const struct sockaddr * inSockAddr,
-               uint16_t                                inPort,
-               BrowseAllContext *              inContext,
-               BrowseAllConnection **  outConnection )
-{
-       OSStatus                                        err;
-       BrowseAllConnection *           obj;
-       
-       obj = (BrowseAllConnection *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->refCount   = 1;
-       SockAddrCopy( inSockAddr, &obj->sip );
-       obj->port               = inPort;
-       obj->context    = inContext;
-       
-       *outConnection = obj;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _BrowseAllConnectionRetain
-//===========================================================================================================================
-
-static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection )
-{
-       ++inConnection->refCount;
-}
-
-//===========================================================================================================================
-//     _BrowseAllConnectionRelease
-//===========================================================================================================================
-
-static void    _BrowseAllConnectionRelease( BrowseAllConnection *inConnection )
-{
-       if( --inConnection->refCount == 0 ) free( inConnection );
-}
-
-//===========================================================================================================================
-//     _BrowseAllConnectionProgress
-//===========================================================================================================================
-
-static void    _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg )
-{
-       BrowseAllConnection * const             connection = (BrowseAllConnection *) inArg;
-       
-       if( inPhase == kAsyncConnectionPhase_Connected )
-       {
-               const AsyncConnectedInfo * const                info = (AsyncConnectedInfo *) inDetails;
-               
-               connection->connectTimeSecs = info->connectSecs;
-       }
-}
-
-//===========================================================================================================================
-//     _BrowseAllConnectionHandler
-//===========================================================================================================================
-
-static void    _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg )
-{
-       BrowseAllConnection * const             connection      = (BrowseAllConnection *) inArg;
-       BrowseAllContext * const                context         = connection->context;
-       
-       connection->status = inError;
-       ForgetSocket( &inSock );
-       if( context )
-       {
-               check( context->connectionPendingCount > 0 );
-               if( ( --context->connectionPendingCount == 0 ) && context->connectionTimer )
-               {
-                       dispatch_source_forget( &context->connectionTimer );
-                       dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
-               }
-       }
-       _BrowseAllConnectionRelease( connection );
-}
-
-//===========================================================================================================================
-//     _BrowseAllExit
-//===========================================================================================================================
-
-#define Indent( X )            ( (X) * 4 ), ""
-
-static void    _BrowseAllExit( void *inContext )
-{
-       BrowseAllContext * const                context         = (BrowseAllContext *) inContext;
-       SBRDomain *                                             domain;
-       SBRServiceType *                                type;
-       SBRServiceInstance *                    instance;
-       SBRIPAddress *                                  ipaddr;
-       char                                                    textBuf[ 512 ];
-#if( TARGET_OS_POSIX )
-       const Boolean                                   useColor        = isatty( STDOUT_FILENO ) ? true : false;
-#endif
-       
-       dispatch_source_forget( &context->connectionTimer );
-       
-       for( domain = context->results->domainList; domain; domain = domain->next )
-       {
-               FPrintF( stdout, "%s\n\n", domain->name );
-               
-               for( type = domain->typeList; type; type = type->next )
-               {
-                       const char *            description;
-                       const Boolean           serviceTypeIsTCP = _IsServiceTypeTCP( type->name );
-                       
-                       description = ServiceTypeDescription( type->name );
-                       if( description )       FPrintF( stdout, "%*s" "%s (%s)\n\n",   Indent( 1 ), description, type->name );
-                       else                            FPrintF( stdout, "%*s" "%s\n\n",                Indent( 1 ), type->name );
-                       
-                       for( instance = type->instanceList; instance; instance = instance->next )
-                       {
-                               char *                          dst = textBuf;
-                               char * const            lim = &textBuf[ countof( textBuf ) ];
-                               char                            ifname[ IF_NAMESIZE + 1 ];
-                               
-                               SNPrintF_Add( &dst, lim, "%s via ", instance->name );
-                               if( instance->ifIndex == 0 )
-                               {
-                                       SNPrintF_Add( &dst, lim, "the Internet" );
-                               }
-                               else if( if_indextoname( instance->ifIndex, ifname ) )
-                               {
-                                       NetTransportType                netType;
-                                       
-                                       SocketGetInterfaceInfo( kInvalidSocketRef, ifname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &netType );
-                                       SNPrintF_Add( &dst, lim, "%s (%s)",
-                                               ( netType == kNetTransportType_Ethernet ) ? "Ethernet" : NetTransportTypeToString( netType ),
-                                               ifname );
-                               }
-                               else
-                               {
-                                       SNPrintF_Add( &dst, lim, "interface index %u", instance->ifIndex );
-                               }
-                               FPrintF( stdout, "%*s" "%-55s %4llu.%03llu ms\n\n",
-                                       Indent( 2 ), textBuf, instance->discoverTimeUs / 1000, instance->discoverTimeUs % 1000 );
-                               
-                               if( instance->hostname )
-                               {
-                                       SNPrintF( textBuf, sizeof( textBuf ), "%s:%u", instance->hostname, instance->port );
-                                       FPrintF( stdout, "%*s" "%-51s %4llu.%03llu ms\n",
-                                               Indent( 3 ), textBuf, instance->resolveTimeUs / 1000, instance->resolveTimeUs % 1000 );
-                               }
-                               else
-                               {
-                                       FPrintF( stdout, "%*s" "%s:%u\n", Indent( 3 ), instance->hostname, instance->port );
-                               }
-                               
-                               for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
-                               {
-                                       BrowseAllConnection *           conn;
-                                       BrowseAllConnection **          connPtr;
-                                       
-                                       FPrintF( stdout, "%*s" "%-##47a %4llu.%03llu ms",
-                                               Indent( 4 ), &ipaddr->sip.sa, ipaddr->resolveTimeUs / 1000, ipaddr->resolveTimeUs % 1000 );
-                                       
-                                       conn = NULL;
-                                       if( serviceTypeIsTCP && ( instance->port != kDiscardProtocolPort ) )
-                                       {
-                                               for( connPtr = &context->connectionList; ( conn = *connPtr ) != NULL; connPtr = &conn->next )
-                                               {
-                                                       if( ( conn->port == instance->port ) &&
-                                                               ( SockAddrCompareAddr( &conn->sip, &ipaddr->sip ) == 0 ) ) break;
-                                               }
-                                               if( conn )
-                                               {
-                                                       if( conn->status == kInProgressErr ) conn->status = kTimeoutErr;
-                                                       *connPtr = conn->next;
-                                                       conn->context = NULL;
-                                                       AsyncConnection_Forget( &conn->asyncCnx );
-                                               }
-                                       }
-                                       
-                                       if( conn )
-                                       {
-                                               if( conn->status == kNoErr )
-                                               {
-                                                       FPrintF( stdout, " (%sconnected%s in %.3f ms)\n",
-                                                               useColor ? kANSIGreen : "", useColor ? kANSINormal : "", conn->connectTimeSecs * 1000 );
-                                               }
-                                               else
-                                               {
-                                                       FPrintF( stdout, " (%scould not connect%s: %m)\n",
-                                                               useColor ? kANSIRed : "", useColor ? kANSINormal : "", conn->status );
-                                               }
-                                               _BrowseAllConnectionRelease( conn );
-                                       }
-                                       else
-                                       {
-                                               FPrintF( stdout, " (no connection attempted)\n" );
-                                       }
-                               }
-                               
-                               FPrintF( stdout, "\n" );
-                               if( instance->txtLen == 0 ) continue;
-                               
-                               FPrintF( stdout, "%*s" "TXT record (%zu byte%?c):\n",
-                                       Indent( 3 ), instance->txtLen, instance->txtLen != 1, 's' );
-                               if( instance->txtLen > 1 )
-                               {
-                                       FPrintF( stdout, "%3{txt}", instance->txtPtr, instance->txtLen );
-                               }
-                               else
-                               {
-                                       FPrintF( stdout, "%*s" "%#H\n", Indent( 3 ), instance->txtPtr, (int) instance->txtLen, INT_MAX );
-                               }
-                               FPrintF( stdout, "\n" );
-                       }
-                       FPrintF( stdout, "\n" );
-               }
-       }
-       
-       _BrowseAllContextFree( context );
-       Exit( NULL );
-}
-
-//===========================================================================================================================
-//     _IsServiceTypeTCP
-//===========================================================================================================================
-
-static Boolean _IsServiceTypeTCP( const char *inServiceType )
-{
-       OSStatus                        err;
-       const uint8_t *         secondLabel;
-       uint8_t                         name[ kDomainNameLengthMax ];
-       
-       err = DomainNameFromString( name, inServiceType, NULL );
-       if( !err )
-       {
-               secondLabel = NextLabel( name );
-               if( secondLabel && DomainNameEqual( secondLabel, (const uint8_t *) "\x04" "_tcp" ) ) return( true );
-       }
-       return( false );
-}
-
-//===========================================================================================================================
-//     GetNameInfoCmd
-//===========================================================================================================================
-
-const FlagStringPair           kGetNameInfoFlagStringPairs[] =
-{
-       CaseFlagStringify( NI_NUMERICSCOPE ),
-       CaseFlagStringify( NI_DGRAM ),
-       CaseFlagStringify( NI_NUMERICSERV ),
-       CaseFlagStringify( NI_NAMEREQD ),
-       CaseFlagStringify( NI_NUMERICHOST ),
-       CaseFlagStringify( NI_NOFQDN ),
-       { 0, NULL }
-};
-
-static void    GetNameInfoCmd( void )
-{
-       OSStatus                                        err;
-       sockaddr_ip                                     sip;
-       size_t                                          sockAddrLen;
-       unsigned int                            flags;
-       const FlagStringPair *          pair;
-       struct timeval                          now;
-       char                                            host[ NI_MAXHOST ];
-       char                                            serv[ NI_MAXSERV ];
-       
-       err = StringToSockAddr( gGetNameInfo_IPAddress, &sip, sizeof( sip ), &sockAddrLen );
-       check_noerr( err );
-       if( err )
-       {
-               FPrintF( stderr, "Failed to convert \"%s\" to a sockaddr.\n", gGetNameInfo_IPAddress );
-               goto exit;
-       }
-       
-       flags = 0;
-       if( gGetNameInfoFlag_DGram )            flags |= NI_DGRAM;
-       if( gGetNameInfoFlag_NameReqd )         flags |= NI_NAMEREQD;
-       if( gGetNameInfoFlag_NoFQDN )           flags |= NI_NOFQDN;
-       if( gGetNameInfoFlag_NumericHost )      flags |= NI_NUMERICHOST;
-       if( gGetNameInfoFlag_NumericScope )     flags |= NI_NUMERICSCOPE;
-       if( gGetNameInfoFlag_NumericServ )      flags |= NI_NUMERICSERV;
-       
-       // Print prologue.
-       
-       FPrintF( stdout, "SockAddr:   %##a\n",  &sip.sa );
-       FPrintF( stdout, "Flags:      0x%X < ", flags );
-       for( pair = kGetNameInfoFlagStringPairs; pair->str != NULL; ++pair )
-       {
-               if( flags & pair->flag ) FPrintF( stdout, "%s ", pair->str );
-       }
-       FPrintF( stdout, ">\n" );
-       FPrintF( stdout, "Start time: %{du:time}\n", NULL );
-       FPrintF( stdout, "---\n" );
-       
-       // Call getnameinfo().
-       
-       err = getnameinfo( &sip.sa, (socklen_t) sockAddrLen, host, (socklen_t) sizeof( host ), serv, (socklen_t) sizeof( serv ),
-               (int) flags );
-       gettimeofday( &now, NULL );
-       if( err )
-       {
-               FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
-       }
-       else
-       {
-               FPrintF( stdout, "host: %s\n", host );
-               FPrintF( stdout, "serv: %s\n", serv );
-       }
-       FPrintF( stdout, "---\n" );
-       FPrintF( stdout, "End time:   %{du:time}\n", &now );
-       
-exit:
-       gExitCode = err ? 1 : 0;
-}
-
-//===========================================================================================================================
-//     GetAddrInfoStressCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSServiceRef                   mainRef;
-       DNSServiceRef                   sdRef;
-       DNSServiceFlags                 flags;
-       unsigned int                    interfaceIndex;
-       unsigned int                    connectionNumber;
-       unsigned int                    requestCount;
-       unsigned int                    requestCountMax;
-       unsigned int                    requestCountLimit;
-       unsigned int                    durationMinMs;
-       unsigned int                    durationMaxMs;
-       
-}      GAIStressContext;
-
-static void    GetAddrInfoStressEvent( void *inContext );
-static void    DNSSD_API
-       GetAddrInfoStressCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-
-static void    GetAddrInfoStressCmd( void )
-{
-       OSStatus                                err;
-       GAIStressContext *              context = NULL;
-       int                                             i;
-       DNSServiceFlags                 flags;
-       uint32_t                                ifIndex;
-       char                                    ifName[ kInterfaceNameBufLen ];
-       
-       if( gGAIStress_TestDurationSecs < 0 )
-       {
-               FPrintF( stdout, "Invalid test duration: %d s.\n", gGAIStress_TestDurationSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       if( gGAIStress_ConnectionCount <= 0 )
-       {
-               FPrintF( stdout, "Invalid simultaneous connection count: %d.\n", gGAIStress_ConnectionCount );
-               err = kParamErr;
-               goto exit;
-       }
-       if( gGAIStress_DurationMinMs <= 0 )
-       {
-               FPrintF( stdout, "Invalid minimum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMinMs );
-               err = kParamErr;
-               goto exit;
-       }
-       if( gGAIStress_DurationMaxMs <= 0 )
-       {
-               FPrintF( stdout, "Invalid maximum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMaxMs );
-               err = kParamErr;
-               goto exit;
-       }
-       if( gGAIStress_DurationMinMs > gGAIStress_DurationMaxMs )
-       {
-               FPrintF( stdout, "Invalid minimum and maximum DNSServiceGetAddrInfo() durations: %d ms and %d ms.\n",
-                       gGAIStress_DurationMinMs, gGAIStress_DurationMaxMs );
-               err = kParamErr;
-               goto exit;
-       }
-       if( gGAIStress_RequestCountMax <= 0 )
-       {
-               FPrintF( stdout, "Invalid maximum request count: %d.\n", gGAIStress_RequestCountMax );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Set flags.
-       
-       flags = GetDNSSDFlagsFromOpts();
-       
-       // Set interface index.
-       
-       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       for( i = 0; i < gGAIStress_ConnectionCount; ++i )
-       {
-               context = (GAIStressContext *) calloc( 1, sizeof( *context ) );
-               require_action( context, exit, err = kNoMemoryErr );
-               
-               context->flags                          = flags;
-               context->interfaceIndex         = ifIndex;
-               context->connectionNumber       = (unsigned int)( i + 1 );
-               context->requestCountMax        = (unsigned int) gGAIStress_RequestCountMax;
-               context->durationMinMs          = (unsigned int) gGAIStress_DurationMinMs;
-               context->durationMaxMs          = (unsigned int) gGAIStress_DurationMaxMs;
-               
-               dispatch_async_f( dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
-               context = NULL;
-       }
-       
-       if( gGAIStress_TestDurationSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( gGAIStress_TestDurationSecs ), dispatch_get_main_queue(), NULL, Exit );
-       }
-       
-       FPrintF( stdout, "Flags:                %#{flags}\n",   flags, kDNSServiceFlagsDescriptors );
-       FPrintF( stdout, "Interface:            %d (%s)\n",             (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
-       FPrintF( stdout, "Test duration:        " );
-       if( gGAIStress_TestDurationSecs == 0 )
-       {
-               FPrintF( stdout, "∞\n" );
-       }
-       else
-       {
-               FPrintF( stdout, "%d s\n", gGAIStress_TestDurationSecs );
-       }
-       FPrintF( stdout, "Connection count:     %d\n",                  gGAIStress_ConnectionCount );
-       FPrintF( stdout, "Request duration min: %d ms\n",               gGAIStress_DurationMinMs );
-       FPrintF( stdout, "Request duration max: %d ms\n",               gGAIStress_DurationMaxMs );
-       FPrintF( stdout, "Request count max:    %d\n",                  gGAIStress_RequestCountMax );
-       FPrintF( stdout, "Start time:           %{du:time}\n",  NULL);
-       FPrintF( stdout, "---\n" );
-       
-       dispatch_main();
-       
-exit:
-       FreeNullSafe( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     GetAddrInfoStressEvent
-//===========================================================================================================================
-
-#define kStressRandStrLen              5
-
-#define kLowercaseAlphaCharSet         "abcdefghijklmnopqrstuvwxyz"
-
-static void    GetAddrInfoStressEvent( void *inContext )
-{
-       GAIStressContext * const                context = (GAIStressContext *) inContext;
-       OSStatus                                                err;
-       DNSServiceRef                                   sdRef;
-       unsigned int                                    nextMs;
-       char                                                    randomStr[ kStressRandStrLen + 1 ];
-       char                                                    hostname[ kStressRandStrLen + 4 + 1 ];
-       Boolean                                                 isConnectionNew = false;
-       static Boolean                                  printedHeader   = false;
-       
-       if( !context->mainRef || ( context->requestCount >= context->requestCountLimit ) )
-       {
-               DNSServiceForget( &context->mainRef );
-               context->sdRef                          = NULL;
-               context->requestCount           = 0;
-               context->requestCountLimit      = RandomRange( 1, context->requestCountMax );
-               
-               err = DNSServiceCreateConnection( &context->mainRef );
-               require_noerr( err, exit );
-               
-               err = DNSServiceSetDispatchQueue( context->mainRef, dispatch_get_main_queue() );
-               require_noerr( err, exit );
-               
-               isConnectionNew = true;
-       }
-       
-       RandomString( kLowercaseAlphaCharSet, sizeof_string( kLowercaseAlphaCharSet ), 2, kStressRandStrLen, randomStr );
-       SNPrintF( hostname, sizeof( hostname ), "%s.com", randomStr );
-       
-       nextMs = RandomRange( context->durationMinMs, context->durationMaxMs );
-       
-       if( !printedHeader )
-       {
-               FPrintF( stdout, "%-26s Conn  Hostname Dur (ms)\n", "Timestamp" );
-               printedHeader = true;
-       }
-       FPrintF( stdout, "%{du:time} %3u%c %9s %8u\n",
-               NULL, context->connectionNumber, isConnectionNew ? '*': ' ', hostname, nextMs );
-       
-       DNSServiceForget( &context->sdRef );
-       sdRef = context->mainRef;
-       err = DNSServiceGetAddrInfo( &sdRef, context->flags | kDNSServiceFlagsShareConnection, context->interfaceIndex,
-               kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, hostname, GetAddrInfoStressCallback, NULL );
-       require_noerr( err, exit );
-       context->sdRef = sdRef;
-       
-       context->requestCount++;
-       
-       dispatch_after_f( dispatch_time_milliseconds( nextMs ), dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     GetAddrInfoStressCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       GetAddrInfoStressCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       Unused( inSDRef );
-       Unused( inFlags );
-       Unused( inInterfaceIndex );
-       Unused( inError );
-       Unused( inHostname );
-       Unused( inSockAddr );
-       Unused( inTTL );
-       Unused( inContext );
-}
-
-//===========================================================================================================================
-//     DNSQueryCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       sockaddr_ip                             serverAddr;
-       uint64_t                                sendTicks;
-       uint8_t *                               msgPtr;
-       size_t                                  msgLen;
-       size_t                                  msgOffset;
-       const char *                    name;
-       dispatch_source_t               readSource;
-       SocketRef                               sock;
-       int                                             timeLimitSecs;
-       uint16_t                                queryID;
-       uint16_t                                type;
-       Boolean                                 haveTCPLen;
-       Boolean                                 useTCP;
-       Boolean                                 printRawRData;  // True if RDATA results are not to be formatted.
-       uint8_t                                 msgBuf[ 512 ];
-       
-}      DNSQueryContext;
-
-static void    DNSQueryPrintPrologue( const DNSQueryContext *inContext );
-static void    DNSQueryReadHandler( void *inContext );
-static void    DNSQueryCancelHandler( void *inContext );
-
-static void    DNSQueryCmd( void )
-{
-       OSStatus                                err;
-       DNSQueryContext *               context = NULL;
-       uint8_t *                               msgPtr;
-       size_t                                  msgLen, sendLen;
-       
-       // Check command parameters.
-       
-       if( gDNSQuery_TimeLimitSecs < -1 )
-       {
-               FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSQuery_TimeLimitSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       if( ( gDNSQuery_Flags < INT16_MIN ) || ( gDNSQuery_Flags > UINT16_MAX ) )
-       {
-               FPrintF( stdout, "DNS flags-and-codes value is out of the unsigned 16-bit range: 0x%08X.\n", gDNSQuery_Flags );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create context.
-       
-       context = (DNSQueryContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->name                   = gDNSQuery_Name;
-       context->sock                   = kInvalidSocketRef;
-       context->timeLimitSecs  = gDNSQuery_TimeLimitSecs;
-       context->queryID                = (uint16_t) Random32();
-       context->useTCP                 = gDNSQuery_UseTCP       ? true : false;
-       context->printRawRData  = gDNSQuery_RawRData ? true : false;
-       
-#if( TARGET_OS_DARWIN )
-       if( gDNSQuery_Server )
-#endif
-       {
-               err = StringToSockAddr( gDNSQuery_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
-               require_noerr( err, exit );
-       }
-#if( TARGET_OS_DARWIN )
-       else
-       {
-               err = GetDefaultDNSServer( &context->serverAddr );
-               require_noerr( err, exit );
-       }
-#endif
-       if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSPort );
-       
-       err = RecordTypeFromArgString( gDNSQuery_Type, &context->type );
-       require_noerr( err, exit );
-       
-       // Write query message.
-       
-       check_compile_time_code( sizeof( context->msgBuf ) >= ( kDNSQueryMessageMaxLen + 2 ) );
-       
-       msgPtr = context->useTCP ? &context->msgBuf[ 2 ] : context->msgBuf;
-       err = WriteDNSQueryMessage( msgPtr, context->queryID, (uint16_t) gDNSQuery_Flags, context->name, context->type,
-               kDNSServiceClass_IN, &msgLen );
-       require_noerr( err, exit );
-       check( msgLen <= UINT16_MAX );
-       
-       if( context->useTCP )
-       {
-               WriteBig16( context->msgBuf, msgLen );
-               sendLen = 2 + msgLen;
-       }
-       else
-       {
-               sendLen = msgLen;
-       }
-       
-       DNSQueryPrintPrologue( context );
-       
-       if( gDNSQuery_Verbose )
-       {
-               FPrintF( stdout, "DNS message to send:\n\n%{du:dnsmsg}", msgPtr, msgLen );
-               FPrintF( stdout, "---\n" );
-       }
-       
-       if( context->useTCP )
-       {
-               // Create TCP socket.
-               
-               context->sock = socket( context->serverAddr.sa.sa_family, SOCK_STREAM, IPPROTO_TCP );
-               err = map_socket_creation_errno( context->sock );
-               require_noerr( err, exit );
-               
-               err = SocketConnect( context->sock, &context->serverAddr, 5 );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               // Create UDP socket.
-               
-               err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &context->sock );
-               require_noerr( err, exit );
-       }
-       
-       context->sendTicks = UpTicks();
-       err = SocketWriteAll( context->sock, context->msgBuf, sendLen, 5 );
-       require_noerr( err, exit );
-       
-       if( context->timeLimitSecs == 0 ) goto exit;
-       
-       err = DispatchReadSourceCreate( context->sock, NULL, DNSQueryReadHandler, DNSQueryCancelHandler, context,
-               &context->readSource );
-       require_noerr( err, exit );
-       dispatch_resume( context->readSource );
-       
-       if( context->timeLimitSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
-                       Exit );
-       }
-       dispatch_main();
-       
-exit:
-       if( context )
-       {
-               dispatch_source_forget( &context->readSource );
-               ForgetSocket( &context->sock );
-               free( context );
-       }
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     DNSQueryPrintPrologue
-//===========================================================================================================================
-
-static void    DNSQueryPrintPrologue( const DNSQueryContext *inContext )
-{
-       const int               timeLimitSecs = inContext->timeLimitSecs;
-       
-       FPrintF( stdout, "Name:        %s\n",           inContext->name );
-       FPrintF( stdout, "Type:        %s (%u)\n",      RecordTypeToString( inContext->type ), inContext->type );
-       FPrintF( stdout, "Server:      %##a\n",         &inContext->serverAddr );
-       FPrintF( stdout, "Transport:   %s\n",           inContext->useTCP ? "TCP" : "UDP" );
-       FPrintF( stdout, "Time limit:  " );
-       if( timeLimitSecs >= 0 )        FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
-       else                                            FPrintF( stdout, "∞\n" );
-       FPrintF( stdout, "Start time:  %{du:time}\n", NULL );
-       FPrintF( stdout, "---\n" );
-}
-
-//===========================================================================================================================
-//     DNSQueryReadHandler
-//===========================================================================================================================
-
-static void    DNSQueryReadHandler( void *inContext )
-{
-       OSStatus                                        err;
-       struct timeval                          now;
-       const uint64_t                          nowTicks        = UpTicks();
-       DNSQueryContext * const         context         = (DNSQueryContext *) inContext;
-       
-       gettimeofday( &now, NULL );
-       
-       if( context->useTCP )
-       {
-               if( !context->haveTCPLen )
-               {
-                       err = SocketReadData( context->sock, &context->msgBuf, 2, &context->msgOffset );
-                       if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
-                       require_noerr( err, exit );
-                       
-                       context->msgOffset      = 0;
-                       context->msgLen         = ReadBig16( context->msgBuf );
-                       context->haveTCPLen     = true;
-                       if( context->msgLen <= sizeof( context->msgBuf ) )
-                       {
-                               context->msgPtr = context->msgBuf;
-                       }
-                       else
-                       {
-                               context->msgPtr = (uint8_t *) malloc( context->msgLen );
-                               require_action( context->msgPtr, exit, err = kNoMemoryErr );
-                       }
-               }
-               
-               err = SocketReadData( context->sock, context->msgPtr, context->msgLen, &context->msgOffset );
-               if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
-               require_noerr( err, exit );
-               context->msgOffset      = 0;
-               context->haveTCPLen     = false;
-       }
-       else
-       {
-               sockaddr_ip             fromAddr;
-               
-               context->msgPtr = context->msgBuf;
-               err = SocketRecvFrom( context->sock, context->msgPtr, sizeof( context->msgBuf ), &context->msgLen, &fromAddr,
-                       sizeof( fromAddr ), NULL, NULL, NULL, NULL );
-               require_noerr( err, exit );
-               
-               check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
-       }
-       
-       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
-       FPrintF( stdout, "Source:       %##a\n",                &context->serverAddr );
-       FPrintF( stdout, "Message size: %zu\n",                 context->msgLen );
-       FPrintF( stdout, "RTT:          %llu ms\n\n",   UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
-       FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgPtr, context->msgLen );
-       
-       if( ( context->msgLen >= kDNSHeaderLength ) && ( DNSHeaderGetID( (DNSHeader *) context->msgPtr ) == context->queryID ) )
-       {
-               Exit( kExitReason_ReceivedResponse );
-       }
-       
-exit:
-       if( err ) dispatch_source_forget( &context->readSource );
-}
-
-//===========================================================================================================================
-//     DNSQueryCancelHandler
-//===========================================================================================================================
-
-static void    DNSQueryCancelHandler( void *inContext )
-{
-       DNSQueryContext * const         context = (DNSQueryContext *) inContext;
-       
-       check( !context->readSource );
-       ForgetSocket( &context->sock );
-       if( context->msgPtr != context->msgBuf ) ForgetMem( &context->msgPtr );
-       free( context );
-       dispatch_async_f( dispatch_get_main_queue(), NULL, Exit );
-}
-
-#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
-//===========================================================================================================================
-//     DNSCryptCmd
-//===========================================================================================================================
-
-#define kDNSCryptPort          443
-
-#define kDNSCryptMinPadLength                          8
-#define kDNSCryptMaxPadLength                          256
-#define kDNSCryptBlockSize                                     64
-#define kDNSCryptCertMinimumLength                     124
-#define kDNSCryptClientMagicLength                     8
-#define kDNSCryptResolverMagicLength           8
-#define kDNSCryptHalfNonceLength                       12
-#define kDNSCryptCertMagicLength                       4
-
-check_compile_time( ( kDNSCryptHalfNonceLength * 2 ) == crypto_box_NONCEBYTES );
-
-static const uint8_t           kDNSCryptCertMagic[ kDNSCryptCertMagicLength ] = { 'D', 'N', 'S', 'C' };
-static const uint8_t           kDNSCryptResolverMagic[ kDNSCryptResolverMagicLength ] =
-{
-       0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38
-};
-
-typedef struct
-{
-       uint8_t         certMagic[ kDNSCryptCertMagicLength ];
-       uint8_t         esVersion[ 2 ];
-       uint8_t         minorVersion[ 2 ];
-       uint8_t         signature[ crypto_sign_BYTES ];
-       uint8_t         publicKey[ crypto_box_PUBLICKEYBYTES ];
-       uint8_t         clientMagic[ kDNSCryptClientMagicLength ];
-       uint8_t         serial[ 4 ];
-       uint8_t         startTime[ 4 ];
-       uint8_t         endTime[ 4 ];
-       uint8_t         extensions[ 1 ];        // Variably-sized extension data.
-       
-}      DNSCryptCert;
-
-check_compile_time( offsetof( DNSCryptCert, extensions ) == kDNSCryptCertMinimumLength );
-
-typedef struct
-{
-       uint8_t         clientMagic[ kDNSCryptClientMagicLength ];
-       uint8_t         clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
-       uint8_t         clientNonce[ kDNSCryptHalfNonceLength ];
-       uint8_t         poly1305MAC[ 16 ];
-       
-}      DNSCryptQueryHeader;
-
-check_compile_time( sizeof( DNSCryptQueryHeader ) == 68 );
-check_compile_time( sizeof( DNSCryptQueryHeader ) >= crypto_box_ZEROBYTES );
-check_compile_time( ( sizeof( DNSCryptQueryHeader ) - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES ) ==
-       offsetof( DNSCryptQueryHeader, poly1305MAC ) );
-
-typedef struct
-{
-       uint8_t         resolverMagic[ kDNSCryptResolverMagicLength ];
-       uint8_t         clientNonce[ kDNSCryptHalfNonceLength ];
-       uint8_t         resolverNonce[ kDNSCryptHalfNonceLength ];
-       uint8_t         poly1305MAC[ 16 ];
-       
-}      DNSCryptResponseHeader;
-
-check_compile_time( sizeof( DNSCryptResponseHeader ) == 48 );
-check_compile_time( offsetof( DNSCryptResponseHeader, poly1305MAC ) >= crypto_box_BOXZEROBYTES );
-check_compile_time( ( offsetof( DNSCryptResponseHeader, poly1305MAC ) - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES ) ==
-       sizeof( DNSCryptResponseHeader ) );
-
-typedef struct
-{
-       sockaddr_ip                             serverAddr;
-       uint64_t                                sendTicks;
-       const char *                    providerName;
-       const char *                    qname;
-       const uint8_t *                 certPtr;
-       size_t                                  certLen;
-       dispatch_source_t               readSource;
-       size_t                                  msgLen;
-       int                                             timeLimitSecs;
-       uint16_t                                queryID;
-       uint16_t                                qtype;
-       Boolean                                 printRawRData;
-       uint8_t                                 serverPublicSignKey[ crypto_sign_PUBLICKEYBYTES ];
-       uint8_t                                 serverPublicKey[ crypto_box_PUBLICKEYBYTES ];
-       uint8_t                                 clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
-       uint8_t                                 clientSecretKey[ crypto_box_SECRETKEYBYTES ];
-       uint8_t                                 clientMagic[ kDNSCryptClientMagicLength ];
-       uint8_t                                 clientNonce[ kDNSCryptHalfNonceLength ];
-       uint8_t                                 nmKey[ crypto_box_BEFORENMBYTES ];
-       uint8_t                                 msgBuf[ 512 ];
-       
-}      DNSCryptContext;
-
-static void            DNSCryptReceiveCertHandler( void *inContext );
-static void            DNSCryptReceiveResponseHandler( void *inContext );
-static void            DNSCryptProceed( void *inContext );
-static OSStatus        DNSCryptProcessCert( DNSCryptContext *inContext );
-static OSStatus        DNSCryptBuildQuery( DNSCryptContext *inContext );
-static OSStatus        DNSCryptSendQuery( DNSCryptContext *inContext );
-static void            DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen );
-
-static void    DNSCryptCmd( void )
-{
-       OSStatus                                err;
-       DNSCryptContext *               context         = NULL;
-       size_t                                  writtenBytes;
-       size_t                                  totalBytes;
-       SocketContext *                 sockCtx;
-       SocketRef                               sock            = kInvalidSocketRef;
-       const char *                    ptr;
-       
-       // Check command parameters.
-       
-       if( gDNSCrypt_TimeLimitSecs < -1 )
-       {
-               FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSCrypt_TimeLimitSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create context.
-       
-       context = (DNSCryptContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->providerName   = gDNSCrypt_ProviderName;
-       context->qname                  = gDNSCrypt_Name;
-       context->timeLimitSecs  = gDNSCrypt_TimeLimitSecs;
-       context->printRawRData  = gDNSCrypt_RawRData ? true : false;
-       
-       err = crypto_box_keypair( context->clientPublicKey, context->clientSecretKey );
-       require_noerr( err, exit );
-       
-       err = HexToData( gDNSCrypt_ProviderKey, kSizeCString, kHexToData_DefaultFlags,
-               context->serverPublicSignKey, sizeof( context->serverPublicSignKey ), &writtenBytes, &totalBytes, &ptr );
-       if( err || ( *ptr != '\0' ) )
-       {
-               FPrintF( stderr, "Failed to parse public signing key hex string (%s).\n", gDNSCrypt_ProviderKey );
-               goto exit;
-       }
-       else if( totalBytes != sizeof( context->serverPublicSignKey ) )
-       {
-               FPrintF( stderr, "Public signing key contains incorrect number of hex bytes (%zu != %zu)\n",
-                       totalBytes, sizeof( context->serverPublicSignKey ) );
-               err = kSizeErr;
-               goto exit;
-       }
-       check( writtenBytes == totalBytes );
-       
-       err = StringToSockAddr( gDNSCrypt_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
-       require_noerr( err, exit );
-       if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSCryptPort );
-       
-       err = RecordTypeFromArgString( gDNSCrypt_Type, &context->qtype );
-       require_noerr( err, exit );
-       
-       // Write query message.
-       
-       context->queryID = (uint16_t) Random32();
-       err = WriteDNSQueryMessage( context->msgBuf, context->queryID, kDNSHeaderFlag_RecursionDesired, context->providerName,
-               kDNSServiceType_TXT, kDNSServiceClass_IN, &context->msgLen );
-       require_noerr( err, exit );
-       
-       // Create UDP socket.
-       
-       err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &sock );
-       require_noerr( err, exit );
-       
-       // Send DNS query.
-       
-       context->sendTicks = UpTicks();
-       err = SocketWriteAll( sock, context->msgBuf, context->msgLen, 5 );
-       require_noerr( err, exit );
-       
-       err = SocketContextCreate( sock, context, &sockCtx );
-       require_noerr( err, exit );
-       sock = kInvalidSocketRef;
-       
-       err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveCertHandler, SocketContextCancelHandler, sockCtx,
-               &context->readSource );
-       if( err ) ForgetSocketContext( &sockCtx );
-       require_noerr( err, exit );
-       
-       dispatch_resume( context->readSource );
-       
-       if( context->timeLimitSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
-                       Exit );
-       }
-       dispatch_main();
-       
-exit:
-       if( context ) free( context );
-       ForgetSocket( &sock );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     DNSCryptReceiveCertHandler
-//===========================================================================================================================
-
-static void    DNSCryptReceiveCertHandler( void *inContext )
-{
-       OSStatus                                        err;
-       struct timeval                          now;
-       const uint64_t                          nowTicks        = UpTicks();
-       SocketContext * const           sockCtx         = (SocketContext *) inContext;
-       DNSCryptContext * const         context         = (DNSCryptContext *) sockCtx->userContext;
-       const DNSHeader *                       hdr;
-       sockaddr_ip                                     fromAddr;
-       const uint8_t *                         ptr;
-       const uint8_t *                         txtPtr;
-       size_t                                          txtLen;
-       unsigned int                            answerCount, i;
-       uint8_t                                         targetName[ kDomainNameLengthMax ];
-       
-       gettimeofday( &now, NULL );
-       
-       dispatch_source_forget( &context->readSource );
-       
-       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
-               &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
-       require_noerr( err, exit );
-       check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
-       
-       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
-       FPrintF( stdout, "Source:       %##a\n",                &context->serverAddr );
-       FPrintF( stdout, "Message size: %zu\n",                 context->msgLen );
-       FPrintF( stdout, "RTT:          %llu ms\n\n",   UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
-       FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgBuf, context->msgLen );
-       
-       require_action_quiet( context->msgLen >= kDNSHeaderLength, exit, err = kSizeErr );
-       
-       hdr = (DNSHeader *) context->msgBuf;
-       require_action_quiet( DNSHeaderGetID( hdr ) == context->queryID, exit, err = kMismatchErr );
-       
-       err = DNSMessageGetAnswerSection( context->msgBuf, context->msgLen, &ptr );
-       require_noerr( err, exit );
-       
-       err = DomainNameFromString( targetName, context->providerName, NULL );
-       require_noerr( err, exit );
-       
-       answerCount = DNSHeaderGetAnswerCount( hdr );
-       for( i = 0; i < answerCount; ++i )
-       {
-               uint16_t                type;
-               uint16_t                class;
-               uint8_t                 name[ kDomainNameLengthMax ];
-               
-               err = DNSMessageExtractRecord( context->msgBuf, context->msgLen, ptr, name, &type, &class, NULL, &txtPtr, &txtLen,
-                       &ptr );
-               require_noerr( err, exit );
-               
-               if( ( type == kDNSServiceType_TXT ) && ( class == kDNSServiceClass_IN ) && DomainNameEqual( name, targetName ) )
-               {
-                       break;
-               }
-       }
-       
-       if( txtLen < ( 1 + kDNSCryptCertMinimumLength ) )
-       {
-               FPrintF( stderr, "TXT record length is too short (%u < %u)\n", txtLen, kDNSCryptCertMinimumLength + 1 );
-               err = kSizeErr;
-               goto exit;
-       }
-       if( txtPtr[ 0 ] < kDNSCryptCertMinimumLength )
-       {
-               FPrintF( stderr, "TXT record value length is too short (%u < %u)\n", txtPtr[ 0 ], kDNSCryptCertMinimumLength );
-               err = kSizeErr;
-               goto exit;
-       }
-       
-       context->certLen = txtPtr[ 0 ];
-       context->certPtr = &txtPtr[ 1 ];
-       
-       dispatch_async_f( dispatch_get_main_queue(), context, DNSCryptProceed );
-       
-exit:
-       if( err ) Exit( NULL );
-}
-
-//===========================================================================================================================
-//     DNSCryptReceiveResponseHandler
-//===========================================================================================================================
-
-static void    DNSCryptReceiveResponseHandler( void *inContext )
-{
-       OSStatus                                                err;
-       struct timeval                                  now;
-       const uint64_t                                  nowTicks        = UpTicks();
-       SocketContext * const                   sockCtx         = (SocketContext *) inContext;
-       DNSCryptContext * const                 context         = (DNSCryptContext *) sockCtx->userContext;
-       sockaddr_ip                                             fromAddr;
-       DNSCryptResponseHeader *                hdr;
-       const uint8_t *                                 end;
-       uint8_t *                                               ciphertext;
-       uint8_t *                                               plaintext;
-       const uint8_t *                                 response;
-       uint8_t                                                 nonce[ crypto_box_NONCEBYTES ];
-       
-       gettimeofday( &now, NULL );
-       
-       dispatch_source_forget( &context->readSource );
-       
-       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
-               &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
-       require_noerr( err, exit );
-       check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
-       
-       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
-       FPrintF( stdout, "Source:       %##a\n",                &context->serverAddr );
-       FPrintF( stdout, "Message size: %zu\n",                 context->msgLen );
-       FPrintF( stdout, "RTT:          %llu ms\n\n",   UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
-       
-       if( context->msgLen < sizeof( DNSCryptResponseHeader ) )
-       {
-               FPrintF( stderr, "DNSCrypt response is too short.\n" );
-               err = kSizeErr;
-               goto exit;
-       }
-       
-       hdr = (DNSCryptResponseHeader *) context->msgBuf;
-       
-       if( memcmp( hdr->resolverMagic, kDNSCryptResolverMagic, kDNSCryptResolverMagicLength ) != 0 )
-       {
-               FPrintF( stderr, "DNSCrypt response resolver magic %#H != %#H\n",
-                       hdr->resolverMagic,             kDNSCryptResolverMagicLength, INT_MAX,
-                       kDNSCryptResolverMagic, kDNSCryptResolverMagicLength, INT_MAX );
-               err = kValueErr;
-               goto exit;
-       }
-       
-       if( memcmp( hdr->clientNonce, context->clientNonce, kDNSCryptHalfNonceLength ) != 0 )
-       {
-               FPrintF( stderr, "DNSCrypt response client nonce mismatch.\n" );
-               err = kValueErr;
-               goto exit;
-       }
-       
-       memcpy( nonce, hdr->clientNonce, crypto_box_NONCEBYTES );
-       
-       ciphertext = hdr->poly1305MAC - crypto_box_BOXZEROBYTES;
-       memset( ciphertext, 0, crypto_box_BOXZEROBYTES );
-       
-       plaintext = (uint8_t *)( hdr + 1 ) - crypto_box_ZEROBYTES;
-       check( plaintext == ciphertext );
-       
-       end = context->msgBuf + context->msgLen;
-       
-       err = crypto_box_open_afternm( plaintext, ciphertext, (size_t)( end - ciphertext ), nonce, context->nmKey );
-       require_noerr( err, exit );
-       
-       response = plaintext + crypto_box_ZEROBYTES;
-       FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, response, (size_t)( end - response ) );
-       Exit( kExitReason_ReceivedResponse );
-       
-exit:
-       if( err ) Exit( NULL );
-}
-
-//===========================================================================================================================
-//     DNSCryptProceed
-//===========================================================================================================================
-
-static void    DNSCryptProceed( void *inContext )
-{
-       OSStatus                                        err;
-       DNSCryptContext * const         context = (DNSCryptContext *) inContext;
-       
-       err = DNSCryptProcessCert( context );
-       require_noerr_quiet( err, exit );
-       
-       err = DNSCryptBuildQuery( context );
-       require_noerr_quiet( err, exit );
-       
-       err = DNSCryptSendQuery( context );
-       require_noerr_quiet( err, exit );
-       
-exit:
-       if( err ) Exit( NULL );
-}
-
-//===========================================================================================================================
-//     DNSCryptProcessCert
-//===========================================================================================================================
-
-static OSStatus        DNSCryptProcessCert( DNSCryptContext *inContext )
-{
-       OSStatus                                                err;
-       const DNSCryptCert * const              cert    = (DNSCryptCert *) inContext->certPtr;
-       const uint8_t * const                   certEnd = inContext->certPtr + inContext->certLen;
-       struct timeval                                  now;
-       time_t                                                  startTimeSecs, endTimeSecs;
-       size_t                                                  signedLen;
-       uint8_t *                                               tempBuf;
-       unsigned long long                              tempLen;
-       
-       DNSCryptPrintCertificate( cert, inContext->certLen );
-       
-       if( memcmp( cert->certMagic, kDNSCryptCertMagic, kDNSCryptCertMagicLength ) != 0 )
-       {
-               FPrintF( stderr, "DNSCrypt certificate magic %#H != %#H\n",
-                       cert->certMagic,        kDNSCryptCertMagicLength, INT_MAX,
-                       kDNSCryptCertMagic, kDNSCryptCertMagicLength, INT_MAX );
-               err = kValueErr;
-               goto exit;
-       }
-       
-       startTimeSecs   = (time_t) ReadBig32( cert->startTime );
-       endTimeSecs             = (time_t) ReadBig32( cert->endTime );
-       
-       gettimeofday( &now, NULL );
-       if( now.tv_sec < startTimeSecs )
-       {
-               FPrintF( stderr, "DNSCrypt certificate start time is in the future.\n" );
-               err = kDateErr;
-               goto exit;
-       }
-       if( now.tv_sec >= endTimeSecs )
-       {
-               FPrintF( stderr, "DNSCrypt certificate has expired.\n" );
-               err = kDateErr;
-               goto exit;
-       }
-       
-       signedLen = (size_t)( certEnd - cert->signature );
-       tempBuf = (uint8_t *) malloc( signedLen );
-       require_action( tempBuf, exit, err = kNoMemoryErr );
-       err = crypto_sign_open( tempBuf, &tempLen, cert->signature, signedLen, inContext->serverPublicSignKey );
-       free( tempBuf );
-       if( err )
-       {
-               FPrintF( stderr, "DNSCrypt certificate failed verification.\n" );
-               err = kAuthenticationErr;
-               goto exit;
-       }
-       
-       memcpy( inContext->serverPublicKey,     cert->publicKey,        crypto_box_PUBLICKEYBYTES );
-       memcpy( inContext->clientMagic,         cert->clientMagic,      kDNSCryptClientMagicLength );
-       
-       err = crypto_box_beforenm( inContext->nmKey, inContext->serverPublicKey, inContext->clientSecretKey );
-       require_noerr( err, exit );
-       
-       inContext->certPtr      = NULL;
-       inContext->certLen      = 0;
-       inContext->msgLen       = 0;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSCryptBuildQuery
-//===========================================================================================================================
-
-static OSStatus        DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen );
-
-static OSStatus        DNSCryptBuildQuery( DNSCryptContext *inContext )
-{
-       OSStatus                                                err;
-       DNSCryptQueryHeader * const             hdr                     = (DNSCryptQueryHeader *) inContext->msgBuf;
-       uint8_t * const                                 queryPtr        = (uint8_t *)( hdr + 1 );
-       size_t                                                  queryLen;
-       size_t                                                  paddedQueryLen;
-       const uint8_t * const                   msgLimit        = inContext->msgBuf + sizeof( inContext->msgBuf );
-       const uint8_t *                                 padLimit;
-       uint8_t                                                 nonce[ crypto_box_NONCEBYTES ];
-       
-       check_compile_time_code( sizeof( inContext->msgBuf ) >= ( sizeof( DNSCryptQueryHeader ) + kDNSQueryMessageMaxLen ) );
-       
-       inContext->queryID = (uint16_t) Random32();
-       err = WriteDNSQueryMessage( queryPtr, inContext->queryID, kDNSHeaderFlag_RecursionDesired, inContext->qname,
-               inContext->qtype, kDNSServiceClass_IN, &queryLen );
-       require_noerr( err, exit );
-       
-       padLimit = &queryPtr[ queryLen + kDNSCryptMaxPadLength ];
-       if( padLimit > msgLimit ) padLimit = msgLimit;
-       
-       err = DNSCryptPadQuery( queryPtr, queryLen, (size_t)( padLimit - queryPtr ), &paddedQueryLen );
-       require_noerr( err, exit );
-       
-       memset( queryPtr - crypto_box_ZEROBYTES, 0, crypto_box_ZEROBYTES );
-       RandomBytes( inContext->clientNonce, kDNSCryptHalfNonceLength );
-       memcpy( nonce, inContext->clientNonce, kDNSCryptHalfNonceLength );
-       memset( &nonce[ kDNSCryptHalfNonceLength ], 0, kDNSCryptHalfNonceLength );
-       
-       err = crypto_box_afternm( queryPtr - crypto_box_ZEROBYTES, queryPtr - crypto_box_ZEROBYTES,
-               paddedQueryLen + crypto_box_ZEROBYTES, nonce, inContext->nmKey );
-       require_noerr( err, exit );
-       
-       memcpy( hdr->clientMagic,               inContext->clientMagic,         kDNSCryptClientMagicLength );
-       memcpy( hdr->clientPublicKey,   inContext->clientPublicKey,     crypto_box_PUBLICKEYBYTES );
-       memcpy( hdr->clientNonce,               nonce,                                          kDNSCryptHalfNonceLength );
-       
-       inContext->msgLen = (size_t)( &queryPtr[ paddedQueryLen ] - inContext->msgBuf );
-       
-exit:
-       return( err );
-}
-
-static OSStatus        DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen )
-{
-       OSStatus                err;
-       size_t                  paddedLen;
-       
-       require_action_quiet( ( inMsgLen + kDNSCryptMinPadLength ) <= inMaxLen, exit, err = kSizeErr );
-       
-       paddedLen = inMsgLen + kDNSCryptMinPadLength +
-               arc4random_uniform( (uint32_t)( inMaxLen - ( inMsgLen + kDNSCryptMinPadLength ) + 1 ) );
-       paddedLen += ( kDNSCryptBlockSize - ( paddedLen % kDNSCryptBlockSize ) );
-       if( paddedLen > inMaxLen ) paddedLen = inMaxLen;
-       
-       inMsgPtr[ inMsgLen ] = 0x80;
-       memset( &inMsgPtr[ inMsgLen + 1 ], 0, paddedLen - ( inMsgLen + 1 ) );
-       
-       if( outPaddedLen ) *outPaddedLen = paddedLen;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSCryptSendQuery
-//===========================================================================================================================
-
-static OSStatus        DNSCryptSendQuery( DNSCryptContext *inContext )
-{
-       OSStatus                        err;
-       SocketContext *         sockCtx;
-       SocketRef                       sock = kInvalidSocketRef;
-       
-       check( inContext->msgLen > 0 );
-       check( !inContext->readSource );
-       
-       err = UDPClientSocketOpen( AF_UNSPEC, &inContext->serverAddr, 0, -1, NULL, &sock );
-       require_noerr( err, exit );
-       
-       inContext->sendTicks = UpTicks();
-       err = SocketWriteAll( sock, inContext->msgBuf, inContext->msgLen, 5 );
-       require_noerr( err, exit );
-       
-       err = SocketContextCreate( sock, inContext, &sockCtx );
-       require_noerr( err, exit );
-       sock = kInvalidSocketRef;
-       
-       err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveResponseHandler, SocketContextCancelHandler, sockCtx,
-               &inContext->readSource );
-       if( err ) ForgetSocketContext( &sockCtx );
-       require_noerr( err, exit );
-       
-       dispatch_resume( inContext->readSource );
-       
-exit:
-       ForgetSocket( &sock );
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSCryptPrintCertificate
-//===========================================================================================================================
-
-#define kCertTimeStrBufLen             32
-
-static char *  CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] );
-
-static void    DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen )
-{
-       time_t          startTime, endTime;
-       int                     extLen;
-       char            timeBuf[ kCertTimeStrBufLen ];
-       
-       check( inLen >= kDNSCryptCertMinimumLength );
-       
-       startTime       = (time_t) ReadBig32( inCert->startTime );
-       endTime         = (time_t) ReadBig32( inCert->endTime );
-       
-       FPrintF( stdout, "DNSCrypt certificate (%zu bytes):\n", inLen );
-       FPrintF( stdout, "Cert Magic:    %#H\n", inCert->certMagic, kDNSCryptCertMagicLength, INT_MAX );
-       FPrintF( stdout, "ES Version:    %u\n", ReadBig16( inCert->esVersion ) );
-       FPrintF( stdout, "Minor Version: %u\n", ReadBig16( inCert->minorVersion ) );
-       FPrintF( stdout, "Signature:     %H\n", inCert->signature, crypto_sign_BYTES / 2, INT_MAX );
-       FPrintF( stdout, "               %H\n", &inCert->signature[ crypto_sign_BYTES / 2 ], crypto_sign_BYTES / 2, INT_MAX );
-       FPrintF( stdout, "Public Key:    %H\n", inCert->publicKey, sizeof( inCert->publicKey ), INT_MAX );
-       FPrintF( stdout, "Client Magic:  %H\n", inCert->clientMagic, kDNSCryptClientMagicLength, INT_MAX );
-       FPrintF( stdout, "Serial:        %u\n", ReadBig32( inCert->serial ) );
-       FPrintF( stdout, "Start Time:    %u (%s)\n", (uint32_t) startTime, CertTimeStr( startTime, timeBuf ) );
-       FPrintF( stdout, "End Time:      %u (%s)\n", (uint32_t) endTime, CertTimeStr( endTime, timeBuf ) );
-       
-       if( inLen > kDNSCryptCertMinimumLength )
-       {
-               extLen = (int)( inLen - kDNSCryptCertMinimumLength );
-               FPrintF( stdout, "Extensions:    %.1H\n", inCert->extensions, extLen, extLen );
-       }
-       FPrintF( stdout, "\n" );
-}
-
-static char *  CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] )
-{
-       struct tm *             tm;
-       
-       tm = localtime( &inTime );
-       if( !tm )
-       {
-               dlogassert( "localtime() returned a NULL pointer.\n" );
-               *inBuffer = '\0';
-       }
-       else
-       {
-               strftime( inBuffer, kCertTimeStrBufLen, "%a %b %d %H:%M:%S %Z %Y", tm );
-       }
-       
-       return( inBuffer );
-}
-
-#endif // DNSSDUTIL_INCLUDE_DNSCRYPT
-
-//===========================================================================================================================
-//     MDNSQueryCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       const char *                    qnameStr;                                                       // Name (QNAME) of the record being queried as a C string.
-       dispatch_source_t               readSourceV4;                                           // Read dispatch source for IPv4 socket.
-       dispatch_source_t               readSourceV6;                                           // Read dispatch source for IPv6 socket.
-       int                                             localPort;                                                      // The port number to which the sockets are bound.
-       int                                             receiveSecs;                                            // After send, the amount of time to spend receiving.
-       uint32_t                                ifIndex;                                                        // Index of the interface over which to send the query.
-       uint16_t                                qtype;                                                          // The type (QTYPE) of the record being queried.
-       Boolean                                 isQU;                                                           // True if the query is QU, i.e., requests unicast responses.
-       Boolean                                 allResponses;                                           // True if all mDNS messages received should be printed.
-       Boolean                                 printRawRData;                                          // True if RDATA should be printed as hexdumps.
-       Boolean                                 useIPv4;                                                        // True if the query should be sent via IPv4 multicast.
-       Boolean                                 useIPv6;                                                        // True if the query should be sent via IPv6 multicast.
-       char                                    ifName[ IF_NAMESIZE + 1 ];                      // Name of the interface over which to send the query.
-       uint8_t                                 qname[ kDomainNameLengthMax ];          // Buffer to hold the QNAME in DNS label format.
-       uint8_t                                 msgBuf[ kMDNSMessageSizeMax ];          // mDNS message buffer.
-       
-}      MDNSQueryContext;
-
-static void    MDNSQueryPrintPrologue( const MDNSQueryContext *inContext );
-static void    MDNSQueryReadHandler( void *inContext );
-
-static void    MDNSQueryCmd( void )
-{
-       OSStatus                                err;
-       MDNSQueryContext *              context;
-       SocketRef                               sockV4 = kInvalidSocketRef;
-       SocketRef                               sockV6 = kInvalidSocketRef;
-       ssize_t                                 n;
-       const char *                    ifname;
-       size_t                                  msgLen;
-       unsigned int                    sendCount;
-       
-       // Check command parameters.
-       
-       if( gMDNSQuery_ReceiveSecs < -1 )
-       {
-               FPrintF( stdout, "Invalid receive time value: %d seconds.\n", gMDNSQuery_ReceiveSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       context = (MDNSQueryContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->qnameStr               = gMDNSQuery_Name;
-       context->receiveSecs    = gMDNSQuery_ReceiveSecs;
-       context->isQU                   = gMDNSQuery_IsQU                 ? true : false;
-       context->allResponses   = gMDNSQuery_AllResponses ? true : false;
-       context->printRawRData  = gMDNSQuery_RawRData     ? true : false;
-       context->useIPv4                = ( gMDNSQuery_UseIPv4 || !gMDNSQuery_UseIPv6 ) ? true : false;
-       context->useIPv6                = ( gMDNSQuery_UseIPv6 || !gMDNSQuery_UseIPv4 ) ? true : false;
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       ifname = if_indextoname( context->ifIndex, context->ifName );
-       require_action( ifname, exit, err = kNameErr );
-       
-       err = RecordTypeFromArgString( gMDNSQuery_Type, &context->qtype );
-       require_noerr( err, exit );
-       
-       // Set up IPv4 socket.
-       
-       if( context->useIPv4 )
-       {
-               err = CreateMulticastSocket( GetMDNSMulticastAddrV4(),
-                       gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
-                       ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV4 );
-               require_noerr( err, exit );
-       }
-       
-       // Set up IPv6 socket.
-       
-       if( context->useIPv6 )
-       {
-               err = CreateMulticastSocket( GetMDNSMulticastAddrV6(),
-                       gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
-                       ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV6 );
-               require_noerr( err, exit );
-       }
-       
-       // Craft mDNS query message.
-       
-       check_compile_time_code( sizeof( context->msgBuf ) >= kDNSQueryMessageMaxLen );
-       err = WriteDNSQueryMessage( context->msgBuf, kDefaultMDNSMessageID, kDefaultMDNSQueryFlags, context->qnameStr,
-               context->qtype, context->isQU ? ( kDNSServiceClass_IN | kQClassUnicastResponseBit ) : kDNSServiceClass_IN, &msgLen );
-       require_noerr( err, exit );
-       
-       // Print prologue.
-       
-       MDNSQueryPrintPrologue( context );
-       
-       // Send mDNS query message.
-       
-       sendCount = 0;
-       if( IsValidSocket( sockV4 ) )
-       {
-               const struct sockaddr * const           mcastAddr4 = GetMDNSMulticastAddrV4();
-               
-               n = sendto( sockV4, context->msgBuf, msgLen, 0, mcastAddr4, SockAddrGetSize( mcastAddr4 ) );
-               err = map_socket_value_errno( sockV4, n == (ssize_t) msgLen, n );
-               if( err )
-               {
-                       FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
-                       ForgetSocket( &sockV4 );
-               }
-               else
-               {
-                       ++sendCount;
-               }
-       }
-       if( IsValidSocket( sockV6 ) )
-       {
-               const struct sockaddr * const           mcastAddr6 = GetMDNSMulticastAddrV6();
-               
-               n = sendto( sockV6, context->msgBuf, msgLen, 0, mcastAddr6, SockAddrGetSize( mcastAddr6 ) );
-               err = map_socket_value_errno( sockV6, n == (ssize_t) msgLen, n );
-               if( err )
-               {
-                       FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
-                       ForgetSocket( &sockV6 );
-               }
-               else
-               {
-                       ++sendCount;
-               }
-       }
-       require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
-       
-       // If there's no wait period after the send, then exit.
-       
-       if( context->receiveSecs == 0 ) goto exit;
-       
-       // Create dispatch read sources for socket(s).
-       
-       if( IsValidSocket( sockV4 ) )
-       {
-               SocketContext *         sockCtx;
-               
-               err = SocketContextCreate( sockV4, context, &sockCtx );
-               require_noerr( err, exit );
-               sockV4 = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
-                       &context->readSourceV4 );
-               if( err ) ForgetSocketContext( &sockCtx );
-               require_noerr( err, exit );
-               
-               dispatch_resume( context->readSourceV4 );
-       }
-       
-       if( IsValidSocket( sockV6 ) )
-       {
-               SocketContext *         sockCtx;
-               
-               err = SocketContextCreate( sockV6, context, &sockCtx );
-               require_noerr( err, exit );
-               sockV6 = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
-                       &context->readSourceV6 );
-               if( err ) ForgetSocketContext( &sockCtx );
-               require_noerr( err, exit );
-               
-               dispatch_resume( context->readSourceV6 );
-       }
-       
-       if( context->receiveSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
-                       Exit );
-       }
-       dispatch_main();
-       
-exit:
-       ForgetSocket( &sockV4 );
-       ForgetSocket( &sockV6 );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     MDNSColliderCmd
-//===========================================================================================================================
-
-static void    _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError );
-
-static void    MDNSColliderCmd( void )
-{
-       OSStatus                                        err;
-       MDNSColliderRef                         collider = NULL;
-       uint8_t *                                       rdataPtr = NULL;
-       size_t                                          rdataLen = 0;
-       const char *                            ifname;
-       uint32_t                                        ifIndex;
-       MDNSColliderProtocols           protocols;
-       uint16_t                                        type;
-       char                                            ifName[ IF_NAMESIZE + 1 ];
-       uint8_t                                         name[ kDomainNameLengthMax ];
-       
-       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       ifname = if_indextoname( ifIndex, ifName );
-       if( !ifname )
-       {
-               FPrintF( stderr, "error: Invalid interface name or index: %s\n", gInterface );
-               err = kNameErr;
-               goto exit;
-       }
-       
-       err = DomainNameFromString( name, gMDNSCollider_Name, NULL );
-       if( err )
-       {
-               FPrintF( stderr, "error: Invalid record name: %s\n", gMDNSCollider_Name );
-               goto exit;
-       }
-       
-       err = RecordTypeFromArgString( gMDNSCollider_Type, &type );
-       require_noerr_quiet( err, exit );
-       
-       if( gMDNSCollider_RecordData )
-       {
-               err = RecordDataFromArgString( gMDNSCollider_RecordData, &rdataPtr, &rdataLen );
-               require_noerr_quiet( err, exit );
-       }
-       
-       err = MDNSColliderCreate( dispatch_get_main_queue(), &collider );
-       require_noerr( err, exit );
-       
-       err = MDNSColliderSetProgram( collider, gMDNSCollider_Program );
-       if( err )
-       {
-               FPrintF( stderr, "error: Failed to set program string: '%s'\n", gMDNSCollider_Program );
-               goto exit;
-       }
-       
-       err = MDNSColliderSetRecord( collider, name, type, rdataPtr, rdataLen );
-       require_noerr( err, exit );
-       ForgetMem( &rdataPtr );
-       
-       protocols = kMDNSColliderProtocol_None;
-       if( gMDNSCollider_UseIPv4 || !gMDNSCollider_UseIPv6 ) protocols |= kMDNSColliderProtocol_IPv4;
-       if( gMDNSCollider_UseIPv6 || !gMDNSCollider_UseIPv4 ) protocols |= kMDNSColliderProtocol_IPv6;
-       MDNSColliderSetProtocols( collider, protocols );
-       MDNSColliderSetInterfaceIndex( collider, ifIndex );
-       MDNSColliderSetStopHandler( collider, _MDNSColliderCmdStopHandler, collider );
-       
-       err = MDNSColliderStart( collider );
-       require_noerr( err, exit );
-       
-       dispatch_main();
-       
-exit:
-       FreeNullSafe( rdataPtr );
-       CFReleaseNullSafe( collider );
-       if( err ) exit( 1 );
-}
-
-static void    _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError )
-{
-       MDNSColliderRef const           collider = (MDNSColliderRef) inContext;
-       
-       CFRelease( collider );
-       exit( inError ? 1 : 0 );
-}
-
-//===========================================================================================================================
-//     MDNSQueryPrintPrologue
-//===========================================================================================================================
-
-static void    MDNSQueryPrintPrologue( const MDNSQueryContext *inContext )
-{
-       const int               receiveSecs = inContext->receiveSecs;
-       
-       FPrintF( stdout, "Interface:        %d (%s)\n",         (int32_t) inContext->ifIndex, inContext->ifName );
-       FPrintF( stdout, "Name:             %s\n",                      inContext->qnameStr );
-       FPrintF( stdout, "Type:             %s (%u)\n",         RecordTypeToString( inContext->qtype ), inContext->qtype );
-       FPrintF( stdout, "Class:            IN (%s)\n",         inContext->isQU ? "QU" : "QM" );
-       FPrintF( stdout, "Local port:       %d\n",                      inContext->localPort );
-       FPrintF( stdout, "IP protocols:     %?s%?s%?s\n",
-               inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
-       FPrintF( stdout, "Receive duration: " );
-       if( receiveSecs >= 0 )  FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
-       else                                    FPrintF( stdout, "∞\n" );
-       FPrintF( stdout, "Start time:       %{du:time}\n",      NULL );
-}
-
-//===========================================================================================================================
-//     MDNSQueryReadHandler
-//===========================================================================================================================
-
-static void    MDNSQueryReadHandler( void *inContext )
-{
-       OSStatus                                                err;
-       struct timeval                                  now;
-       SocketContext * const                   sockCtx = (SocketContext *) inContext;
-       MDNSQueryContext * const                context = (MDNSQueryContext *) sockCtx->userContext;
-       size_t                                                  msgLen;
-       sockaddr_ip                                             fromAddr;
-       Boolean                                                 foundAnswer     = false;
-       
-       gettimeofday( &now, NULL );
-       
-       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &fromAddr,
-               sizeof( fromAddr ), NULL, NULL, NULL, NULL );
-       require_noerr( err, exit );
-       
-       if( !context->allResponses && ( msgLen >= kDNSHeaderLength ) )
-       {
-               const uint8_t *                         ptr;
-               const DNSHeader * const         hdr = (DNSHeader *) context->msgBuf;
-               unsigned int                            rrCount, i;
-               uint16_t                                        type, class;
-               uint8_t                                         name[ kDomainNameLengthMax ];
-               
-               err = DNSMessageGetAnswerSection( context->msgBuf, msgLen, &ptr );
-               require_noerr( err, exit );
-               
-               if( context->qname[ 0 ] == 0 )
-               {
-                       err = DomainNameAppendString( context->qname, context->qnameStr, NULL );
-                       require_noerr( err, exit );
-               }
-               
-               rrCount = DNSHeaderGetAnswerCount( hdr ) + DNSHeaderGetAuthorityCount( hdr ) + DNSHeaderGetAdditionalCount( hdr );
-               for( i = 0; i < rrCount; ++i )
-               {
-                       err = DNSMessageExtractRecord( context->msgBuf, msgLen, ptr, name, &type, &class, NULL, NULL, NULL, &ptr );
-                       require_noerr( err, exit );
-                       
-                       if( ( ( context->qtype == kDNSServiceType_ANY ) || ( type == context->qtype ) ) &&
-                               DomainNameEqual( name, context->qname ) )
-                       {
-                               foundAnswer = true;
-                               break;
-                       }
-               }
-       }
-       if( context->allResponses || foundAnswer )
-       {
-               FPrintF( stdout, "---\n" );
-               FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
-               FPrintF( stdout, "Source:       %##a\n",                &fromAddr );
-               FPrintF( stdout, "Message size: %zu\n\n%#.*{du:dnsmsg}",
-                       msgLen, context->printRawRData ? 1 : 0, context->msgBuf, msgLen );
-       }
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     PIDToUUIDCmd
-//===========================================================================================================================
-
-static void    PIDToUUIDCmd( void )
-{
-       OSStatus                                                        err;
-       int                                                                     n;
-       struct proc_uniqidentifierinfo          info;
-       
-       n = proc_pidinfo( gPIDToUUID_PID, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof( info ) );
-       require_action_quiet( n == (int) sizeof( info ), exit, err = kUnknownErr );
-       
-       FPrintF( stdout, "%#U\n", info.p_uuid );
-       err = kNoErr;
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     DNSServerCmd
-//===========================================================================================================================
-
-typedef struct DNSServerPrivate *              DNSServerRef;
-
-typedef struct
-{
-       DNSServerRef                    server;                 // Reference to the DNS server.
-       dispatch_source_t               sigIntSource;   // Dispatch SIGINT source.
-       dispatch_source_t               sigTermSource;  // Dispatch SIGTERM source.
-       const char *                    domainOverride; // If non-NULL, the server is to use this domain instead of "d.test.".
-#if( TARGET_OS_DARWIN )
-       dispatch_source_t               processMonitor; // Process monitor source for process being followed, if any.
-       pid_t                                   followPID;              // PID of process being followed, if any. (If it exits, we exit).
-       Boolean                                 addedResolver;  // True if system DNS settings contains a resolver entry for server.
-#endif
-       Boolean                                 loopbackOnly;   // True if the server should be bound to the loopback interface.
-       
-}      DNSServerCmdContext;
-
-typedef enum
-{
-       kDNSServerEvent_Started = 1,
-       kDNSServerEvent_Stopped = 2
-       
-}      DNSServerEventType;
-
-typedef void ( *DNSServerEventHandler_f )( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
-
-CFTypeID       DNSServerGetTypeID( void );
-static OSStatus
-       DNSServerCreate(
-               dispatch_queue_t                inQueue,
-               DNSServerEventHandler_f inEventHandler,
-               void *                                  inEventContext,
-               unsigned int                    inResponseDelayMs,
-               uint32_t                                inDefaultTTL,
-               int                                             inPort,
-               Boolean                                 inLoopbackOnly,
-               const char *                    inDomain,
-               Boolean                                 inBadUDPMode,
-               DNSServerRef *                  outServer );
-static void    DNSServerStart( DNSServerRef inServer );
-static void    DNSServerStop( DNSServerRef inServer );
-
-#define ForgetDNSServer( X )           ForgetCustomEx( X, DNSServerStop, CFRelease )
-
-static void    DNSServerCmdContextFree( DNSServerCmdContext *inContext );
-static void    DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
-static void    DNSServerCmdSigIntHandler( void *inContext );
-static void    DNSServerCmdSigTermHandler( void *inContext );
-#if( TARGET_OS_DARWIN )
-static void    DNSServerCmdFollowedProcessHandler( void *inContext );
-#endif
-
-ulog_define_ex( "com.apple.dnssdutil", DNSServer, kLogLevelInfo, kLogFlags_None, "DNSServer", NULL );
-#define ds_ulog( LEVEL, ... )          ulog( &log_category_from_name( DNSServer ), (LEVEL), __VA_ARGS__ )
-
-static void    DNSServerCmd( void )
-{
-       OSStatus                                        err;
-       DNSServerCmdContext *           context = NULL;
-       
-       if( gDNSServer_Foreground )
-       {
-               LogControl( "DNSServer:output=file;stdout,DNSServer:flags=time;prefix" );
-       }
-       
-       err = CheckIntegerArgument( gDNSServer_ResponseDelayMs, "response delay (ms)", 0, INT_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gDNSServer_DefaultTTL, "default TTL", 0, INT32_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gDNSServer_Port, "port number", -UINT16_MAX, UINT16_MAX );
-       require_noerr_quiet( err, exit );
-       
-       context = (DNSServerCmdContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->domainOverride = gDNSServer_DomainOverride;
-       context->loopbackOnly   = gDNSServer_LoopbackOnly ? true : false;
-       
-#if( TARGET_OS_DARWIN )
-       if( gDNSServer_FollowPID )
-       {
-               err = StringToPID( gDNSServer_FollowPID, &context->followPID );
-               if( err || ( context->followPID < 0 ) )
-               {
-                       FPrintF( stderr, "error: Invalid follow PID: %s\n", gDNSServer_FollowPID );
-                       err = kParamErr;
-                       goto exit;
-               }
-               
-               err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
-                       DNSServerCmdFollowedProcessHandler, NULL, context, &context->processMonitor );
-               require_noerr( err, exit );
-               dispatch_resume( context->processMonitor );
-       }
-       else
-       {
-               context->followPID = -1;
-       }
-#endif
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, DNSServerCmdSigIntHandler, context, &context->sigIntSource );
-       require_noerr( err, exit );
-       dispatch_resume( context->sigIntSource );
-       
-       signal( SIGTERM, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGTERM, DNSServerCmdSigTermHandler, context, &context->sigTermSource );
-       require_noerr( err, exit );
-       dispatch_resume( context->sigTermSource );
-       
-       err = DNSServerCreate( dispatch_get_main_queue(), DNSServerCmdEventHandler, context,
-               (unsigned int) gDNSServer_ResponseDelayMs, (uint32_t) gDNSServer_DefaultTTL, gDNSServer_Port, context->loopbackOnly,
-               context->domainOverride, gDNSServer_BadUDPMode ? true : false, &context->server );
-       require_noerr( err, exit );
-       
-       DNSServerStart( context->server );
-       dispatch_main();
-       
-exit:
-       FPrintF( stderr, "Failed to start DNS server: %#m\n", err );
-       if( context ) DNSServerCmdContextFree( context );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     DNSServerCmdContextFree
-//===========================================================================================================================
-
-static void    DNSServerCmdContextFree( DNSServerCmdContext *inContext )
-{
-       ForgetCF( &inContext->server );
-       dispatch_source_forget( &inContext->sigIntSource );
-       dispatch_source_forget( &inContext->sigTermSource );
-#if( TARGET_OS_DARWIN )
-       dispatch_source_forget( &inContext->processMonitor );
-#endif
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     DNSServerCmdEventHandler
-//===========================================================================================================================
-
-#if( TARGET_OS_DARWIN )
-static OSStatus        _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort );
-static OSStatus        _DNSServerCmdLoopbackResolverRemove( void );
-#endif
-
-static void    DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext )
-{
-       OSStatus                                                err;
-       DNSServerCmdContext * const             context = (DNSServerCmdContext *) inContext;
-       
-       if( inType == kDNSServerEvent_Started )
-       {
-       #if( TARGET_OS_DARWIN )
-               const int               port = (int) inEventData;
-               
-               err = _DNSServerCmdLoopbackResolverAdd( context->domainOverride ? context->domainOverride : "d.test.", port );
-               if( err )
-               {
-                       ds_ulog( kLogLevelError, "Failed to add loopback resolver to DNS configuration for \"d.test.\" domain: %#m\n",
-                               err );
-                       if( context->loopbackOnly ) ForgetDNSServer( &context->server );
-               }
-               else
-               {
-                       context->addedResolver = true;
-               }
-       #endif
-       }
-       else if( inType == kDNSServerEvent_Stopped )
-       {
-               const OSStatus          stopError = (OSStatus) inEventData;
-               
-               if( stopError ) ds_ulog( kLogLevelError, "The server stopped unexpectedly with error: %#m.\n", stopError );
-               
-               err = kNoErr;
-       #if( TARGET_OS_DARWIN )
-               if( context->addedResolver )
-               {
-                       err = _DNSServerCmdLoopbackResolverRemove();
-                       if( err )
-                       {
-                               ds_ulog( kLogLevelError, "Failed to remove loopback resolver from DNS configuration: %#m\n", err );
-                       }
-                       else
-                       {
-                               context->addedResolver = false;
-                       }
-               }
-               else if( context->loopbackOnly )
-               {
-                       err = kUnknownErr;
-               }
-       #endif
-               DNSServerCmdContextFree( context );
-               exit( ( stopError || err ) ? 1 : 0 );
-       }
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-//     _DNSServerCmdLoopbackResolverAdd
-//===========================================================================================================================
-
-static OSStatus        _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort )
-{
-       OSStatus                                err;
-       SCDynamicStoreRef               store;
-       CFPropertyListRef               plist           = NULL;
-       CFStringRef                             key                     = NULL;
-       const uint32_t                  loopbackV4      = htonl( INADDR_LOOPBACK );
-       Boolean                                 success;
-       
-       store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
-       err = map_scerror( store );
-       require_noerr( err, exit );
-       
-       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
-               "{"
-                       "%kO="
-                       "["
-                               "%s"
-                       "]"
-                       "%kO="
-                       "["
-                               "%.4a"
-                               "%.16a"
-                       "]"
-                       "%kO=%i"
-               "}",
-               kSCPropNetDNSSupplementalMatchDomains,  inDomain,
-               kSCPropNetDNSServerAddresses,                   &loopbackV4, in6addr_loopback.s6_addr,
-               kSCPropNetDNSServerPort,                                inPort );
-       require_noerr( err, exit );
-       
-       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
-               CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
-       require_action( key, exit, err = kUnknownErr );
-       
-       success = SCDynamicStoreSetValue( store, key, plist );
-       require_action( success, exit, err = kUnknownErr );
-       
-exit:
-       CFReleaseNullSafe( store );
-       CFReleaseNullSafe( plist );
-       CFReleaseNullSafe( key );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _DNSServerCmdLoopbackResolverRemove
-//===========================================================================================================================
-
-static OSStatus        _DNSServerCmdLoopbackResolverRemove( void )
-{
-       OSStatus                                err;
-       SCDynamicStoreRef               store;
-       CFStringRef                             key = NULL;
-       Boolean                                 success;
-       
-       store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
-       err = map_scerror( store );
-       require_noerr( err, exit );
-       
-       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
-               CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
-       require_action( key, exit, err = kUnknownErr );
-       
-       success = SCDynamicStoreRemoveValue( store, key );
-       require_action( success, exit, err = kUnknownErr );
-       
-exit:
-       CFReleaseNullSafe( store );
-       CFReleaseNullSafe( key );
-       return( err );
-}
-#endif
-
-//===========================================================================================================================
-//     DNSServerCmdSigIntHandler
-//===========================================================================================================================
-
-static void    _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal );
-
-static void    DNSServerCmdSigIntHandler( void *inContext )
-{
-       _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGINT );
-}
-
-//===========================================================================================================================
-//     DNSServerCmdSigTermHandler
-//===========================================================================================================================
-
-static void    DNSServerCmdSigTermHandler( void *inContext )
-{
-       _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGTERM );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-//     DNSServerCmdFollowedProcessHandler
-//===========================================================================================================================
-
-static void    DNSServerCmdFollowedProcessHandler( void *inContext )
-{
-       DNSServerCmdContext * const             context = (DNSServerCmdContext *) inContext;
-       
-       if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT ) _DNSServerCmdShutdown( context, 0 );
-}
-#endif
-
-//===========================================================================================================================
-//     _DNSServerCmdExternalExit
-//===========================================================================================================================
-
-#define SignalNumberToString( X ) (            \
-       ( (X) == SIGINT )  ? "SIGINT"  :        \
-       ( (X) == SIGTERM ) ? "SIGTERM" :        \
-                                                "???" )
-
-static void    _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal )
-{
-       dispatch_source_forget( &inContext->sigIntSource );
-       dispatch_source_forget( &inContext->sigTermSource );
-#if( TARGET_OS_DARWIN )
-       dispatch_source_forget( &inContext->processMonitor );
-       
-       if( inSignal == 0 )
-       {
-               ds_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited\n", (int64_t) inContext->followPID );
-       }
-       else
-#endif
-       {
-               ds_ulog( kLogLevelNotice, "Exiting: received signal %d (%s)\n", inSignal, SignalNumberToString( inSignal ) );
-       }
-       
-       ForgetDNSServer( &inContext->server );
-}
-
-//===========================================================================================================================
-//     DNSServerCreate
-//===========================================================================================================================
-
-#define kDDotTestDomainName            (const uint8_t *) "\x01" "d" "\x04" "test"
-
-typedef struct DNSDelayedResponse              DNSDelayedResponse;
-struct DNSDelayedResponse
-{
-       DNSDelayedResponse *            next;
-       sockaddr_ip                                     destAddr;
-       uint64_t                                        targetTicks;
-       uint8_t *                                       msgPtr;
-       size_t                                          msgLen;
-};
-
-struct DNSServerPrivate
-{
-       CFRuntimeBase                           base;                           // CF object base.
-       uint8_t *                                       domain;                         // Parent domain of server's resource records.
-       dispatch_queue_t                        queue;                          // Queue for DNS server's events.
-       dispatch_source_t                       readSourceUDPv4;        // Read source for IPv4 UDP socket.
-       dispatch_source_t                       readSourceUDPv6;        // Read source for IPv6 UDP socket.
-       dispatch_source_t                       readSourceTCPv4;        // Read source for IPv4 TCP socket.
-       dispatch_source_t                       readSourceTCPv6;        // Read source for IPv6 TCP socket.
-       SocketRef                                       sockUDPv4;
-       SocketRef                                       sockUDPv6;
-       DNSServerEventHandler_f         eventHandler;
-       void *                                          eventContext;
-       DNSDelayedResponse *            responseList;
-       dispatch_source_t                       responseTimer;
-       unsigned int                            responseDelayMs;
-       uint32_t                                        defaultTTL;
-       uint32_t                                        serial;                         // Serial number for SOA record.
-       int                                                     port;                           // Port to use for receiving and sending DNS messages.
-       OSStatus                                        stopError;
-       Boolean                                         stopped;
-       Boolean                                         loopbackOnly;
-       Boolean                                         badUDPMode;                     // True if the server runs in Bad UDP mode.
-};
-
-static void    _DNSServerUDPReadHandler( void *inContext );
-static void    _DNSServerTCPReadHandler( void *inContext );
-static void    _DNSDelayedResponseFree( DNSDelayedResponse *inResponse );
-static void    _DNSDelayedResponseFreeList( DNSDelayedResponse *inList );
-
-CF_CLASS_DEFINE( DNSServer );
-
-static OSStatus
-       DNSServerCreate(
-               dispatch_queue_t                inQueue,
-               DNSServerEventHandler_f inEventHandler,
-               void *                                  inEventContext,
-               unsigned int                    inResponseDelayMs,
-               uint32_t                                inDefaultTTL,
-               int                                             inPort,
-               Boolean                                 inLoopbackOnly,
-               const char *                    inDomain,
-               Boolean                                 inBadUDPMode,
-               DNSServerRef *                  outServer )
-{
-       OSStatus                        err;
-       DNSServerRef            obj = NULL;
-       
-       require_action_quiet( inDefaultTTL <= INT32_MAX, exit, err = kRangeErr );
-       
-       CF_OBJECT_CREATE( DNSServer, obj, err, exit );
-       
-       ReplaceDispatchQueue( &obj->queue, inQueue );
-       obj->eventHandler               = inEventHandler;
-       obj->eventContext               = inEventContext;
-       obj->responseDelayMs    = inResponseDelayMs;
-       obj->defaultTTL                 = inDefaultTTL;
-       obj->port                               = inPort;
-       obj->loopbackOnly               = inLoopbackOnly;
-       obj->badUDPMode                 = inBadUDPMode;
-       
-       if( inDomain )
-       {
-               err = StringToDomainName( inDomain, &obj->domain, NULL );
-               require_noerr_quiet( err, exit );
-       }
-       else
-       {
-               err = DomainNameDup( kDDotTestDomainName, &obj->domain, NULL );
-               require_noerr_quiet( err, exit );
-       }
-       
-       *outServer = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       CFReleaseNullSafe( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _DNSServerFinalize
-//===========================================================================================================================
-
-static void    _DNSServerFinalize( CFTypeRef inObj )
-{
-       DNSServerRef const              me = (DNSServerRef) inObj;
-       
-       check( !me->readSourceUDPv4 );
-       check( !me->readSourceUDPv6 );
-       check( !me->readSourceTCPv4 );
-       check( !me->readSourceTCPv6 );
-       check( !me->responseTimer );
-       ForgetMem( &me->domain );
-       dispatch_forget( &me->queue );
-}
-
-//===========================================================================================================================
-//     DNSServerStart
-//===========================================================================================================================
-
-static void    _DNSServerStart( void *inContext );
-static void    _DNSServerStop( void *inContext, OSStatus inError );
-
-static void    DNSServerStart( DNSServerRef me )
-{
-       CFRetain( me );
-       dispatch_async_f( me->queue, me, _DNSServerStart );
-}
-
-static void    _DNSServerStart( void *inContext )
-{
-       OSStatus                                err;
-       struct timeval                  now;
-       DNSServerRef const              me                      = (DNSServerRef) inContext;
-       SocketRef                               sock            = kInvalidSocketRef;
-       SocketContext *                 sockCtx         = NULL;
-       const uint32_t                  loopbackV4      = htonl( INADDR_LOOPBACK );
-       int                                             year, month, day;
-       
-       // Create IPv4 UDP socket.
-       // Initially, me->port is the port requested by the user. If it's 0, then the user wants any available ephemeral port.
-       // If it's negative, then the user would like a port number equal to its absolute value, but will settle for any
-       // available ephemeral port, if it's not available. The actual port number that was used will be stored in me->port and
-       // used for the remaining sockets.
-       
-       err = _ServerSocketOpenEx2( AF_INET, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &loopbackV4 : NULL,
-               me->port, &me->port, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
-       require_noerr( err, exit );
-       check( me->port > 0 );
-       
-       // Create read source for IPv4 UDP socket.
-       
-       err = SocketContextCreate( sock, me, &sockCtx );
-       require_noerr( err, exit );
-       sock = kInvalidSocketRef;
-       
-       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
-               &me->readSourceUDPv4 );
-       require_noerr( err, exit );
-       dispatch_resume( me->readSourceUDPv4 );
-       me->sockUDPv4 = sockCtx->sock;
-       sockCtx = NULL;
-       
-       // Create IPv6 UDP socket.
-       
-       err = _ServerSocketOpenEx2( AF_INET6, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &in6addr_loopback : NULL,
-               me->port, NULL, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
-       require_noerr( err, exit );
-       
-       // Create read source for IPv6 UDP socket.
-       
-       err = SocketContextCreate( sock, me, &sockCtx );
-       require_noerr( err, exit );
-       sock = kInvalidSocketRef;
-       
-       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
-               &me->readSourceUDPv6 );
-       require_noerr( err, exit );
-       dispatch_resume( me->readSourceUDPv6 );
-       me->sockUDPv6 = sockCtx->sock;
-       sockCtx = NULL;
-       
-       // Create IPv4 TCP socket.
-       
-       err = _ServerSocketOpenEx2( AF_INET, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &loopbackV4 : NULL,
-               me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
-       require_noerr( err, exit );
-       
-       // Create read source for IPv4 TCP socket.
-       
-       err = SocketContextCreate( sock, me, &sockCtx );
-       require_noerr( err, exit );
-       sock = kInvalidSocketRef;
-       
-       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
-               &me->readSourceTCPv4 );
-       require_noerr( err, exit );
-       dispatch_resume( me->readSourceTCPv4 );
-       sockCtx = NULL;
-       
-       // Create IPv6 TCP socket.
-       
-       err = _ServerSocketOpenEx2( AF_INET6, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &in6addr_loopback : NULL,
-               me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
-       require_noerr( err, exit );
-       
-       // Create read source for IPv6 TCP socket.
-       
-       err = SocketContextCreate( sock, me, &sockCtx );
-       require_noerr( err, exit );
-       sock = kInvalidSocketRef;
-       
-       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
-               &me->readSourceTCPv6 );
-       require_noerr( err, exit );
-       dispatch_resume( me->readSourceTCPv6 );
-       sockCtx = NULL;
-       
-       ds_ulog( kLogLevelInfo, "Server is using port %d.\n", me->port );
-       if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Started, (uintptr_t) me->port, me->eventContext );
-       
-       // Create the serial number for the server's SOA record in the YYYMMDDnn convention recommended by
-       // <https://tools.ietf.org/html/rfc1912#section-2.2> using the current time.
-       
-       gettimeofday( &now, NULL );
-       SecondsToYMD_HMS( ( INT64_C_safe( kDaysToUnixEpoch ) * kSecondsPerDay ) + now.tv_sec, &year, &month, &day,
-               NULL, NULL, NULL );
-       me->serial = (uint32_t)( ( year * 1000000 ) + ( month * 10000 ) + ( day * 100 ) + 1 );
-       
-exit:
-       ForgetSocket( &sock );
-       if( sockCtx ) SocketContextRelease( sockCtx );
-       if( err ) _DNSServerStop( me, err );
-}
-
-//===========================================================================================================================
-//     DNSServerStop
-//===========================================================================================================================
-
-static void    _DNSServerUserStop( void *inContext );
-static void    _DNSServerStop2( void *inContext );
-
-static void    DNSServerStop( DNSServerRef me )
-{
-       CFRetain( me );
-       dispatch_async_f( me->queue, me, _DNSServerUserStop );
-}
-
-static void    _DNSServerUserStop( void *inContext )
-{
-       DNSServerRef const              me = (DNSServerRef) inContext;
-       
-       _DNSServerStop( me, kNoErr );
-       CFRelease( me );
-}
-
-static void    _DNSServerStop( void *inContext, OSStatus inError )
-{
-       DNSServerRef const              me = (DNSServerRef) inContext;
-       
-       me->stopError = inError;
-       dispatch_source_forget( &me->readSourceUDPv4 );
-       dispatch_source_forget( &me->readSourceUDPv6 );
-       dispatch_source_forget( &me->readSourceTCPv4 );
-       dispatch_source_forget( &me->readSourceTCPv6 );
-       dispatch_source_forget( &me->responseTimer );
-       me->sockUDPv4 = kInvalidSocketRef;
-       me->sockUDPv6 = kInvalidSocketRef;
-       
-       if( me->responseList )
-       {
-               _DNSDelayedResponseFreeList( me->responseList );
-               me->responseList = NULL;
-       }
-       dispatch_async_f( me->queue, me, _DNSServerStop2 );
-}
-
-static void    _DNSServerStop2( void *inContext )
-{
-       DNSServerRef const              me = (DNSServerRef) inContext;
-       
-       if( !me->stopped )
-       {
-               me->stopped = true;
-               if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Stopped, (uintptr_t) me->stopError, me->eventContext );
-               CFRelease( me );
-       }
-       CFRelease( me );
-}
-
-//===========================================================================================================================
-//     _DNSDelayedResponseFree
-//===========================================================================================================================
-
-static void    _DNSDelayedResponseFree( DNSDelayedResponse *inResponse )
-{
-       ForgetMem( &inResponse->msgPtr );
-       free( inResponse );
-}
-
-//===========================================================================================================================
-//     _DNSDelayedResponseFreeList
-//===========================================================================================================================
-
-static void    _DNSDelayedResponseFreeList( DNSDelayedResponse *inList )
-{
-       DNSDelayedResponse *            response;
-       
-       while( ( response = inList ) != NULL )
-       {
-               inList = response->next;
-               _DNSDelayedResponseFree( response );
-       }
-}
-
-//===========================================================================================================================
-//     _DNSServerUDPReadHandler
-//===========================================================================================================================
-
-static OSStatus
-       _DNSServerAnswerQuery(
-               DNSServerRef    inServer,
-               const uint8_t * inQueryPtr,
-               size_t                  inQueryLen,
-               Boolean                 inForTCP,
-               uint8_t **              outResponsePtr,
-               size_t *                outResponseLen );
-
-#define _DNSServerAnswerQueryForUDP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
-       _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, false, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
-
-#define _DNSServerAnswerQueryForTCP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
-       _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, true, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
-
-static OSStatus
-       _DNSServerScheduleDelayedResponse(
-               DNSServerRef                    inServer,
-               const struct sockaddr * inDestAddr,
-               uint8_t *                               inMsgPtr,
-               size_t                                  inMsgLen );
-static void    _DNSServerUDPDelayedSend( void *inContext );
-
-static void    _DNSServerUDPReadHandler( void *inContext )
-{
-       OSStatus                                        err;
-       SocketContext * const           sockCtx         = (SocketContext *) inContext;
-       DNSServerRef const                      me                      = (DNSServerRef) sockCtx->userContext;
-       struct timeval                          now;
-       ssize_t                                         n;
-       sockaddr_ip                                     clientAddr;
-       socklen_t                                       clientAddrLen;
-       uint8_t *                                       responsePtr     = NULL; // malloc'd
-       size_t                                          responseLen;
-       uint8_t                                         msg[ 512 ];
-       
-       gettimeofday( &now, NULL );
-       
-       // Receive message.
-       
-       clientAddrLen = (socklen_t) sizeof( clientAddr );
-       n = recvfrom( sockCtx->sock, (char *) msg, sizeof( msg ), 0, &clientAddr.sa, &clientAddrLen );
-       err = map_socket_value_errno( sockCtx->sock, n >= 0, n );
-       require_noerr( err, exit );
-       
-       ds_ulog( kLogLevelInfo, "UDP server received %zd bytes from %##a at %{du:time}.\n", n, &clientAddr, &now );
-       
-       if( n < kDNSHeaderLength )
-       {
-               ds_ulog( kLogLevelInfo, "UDP DNS message is too small (%zd < %d).\n", n, kDNSHeaderLength );
-               goto exit;
-       }
-       
-       ds_ulog( kLogLevelInfo, "UDP received message:\n\n%1{du:dnsmsg}", msg, (size_t) n );
-       
-       // Create response.
-       
-       err = _DNSServerAnswerQueryForUDP( me, msg, (size_t) n, &responsePtr, &responseLen );
-       require_noerr_quiet( err, exit );
-       
-       // Schedule response.
-       
-       if( me->responseDelayMs > 0 )
-       {
-               err = _DNSServerScheduleDelayedResponse( me, &clientAddr.sa, responsePtr, responseLen );
-               require_noerr( err, exit );
-               responsePtr = NULL;
-       }
-       else
-       {
-               ds_ulog( kLogLevelInfo, "UDP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
-               
-               n = sendto( sockCtx->sock, (char *) responsePtr, responseLen, 0, &clientAddr.sa, clientAddrLen );
-               err = map_socket_value_errno( sockCtx->sock, n == (ssize_t) responseLen, n );
-               require_noerr( err, exit );
-       }
-       
-exit:
-       FreeNullSafe( responsePtr );
-       return;
-}
-
-static OSStatus
-       _DNSServerScheduleDelayedResponse(
-               DNSServerRef                    me,
-               const struct sockaddr * inDestAddr,
-               uint8_t *                               inMsgPtr,
-               size_t                                  inMsgLen )
-{
-       OSStatus                                        err;
-       DNSDelayedResponse *            response;
-       DNSDelayedResponse **           responsePtr;
-       DNSDelayedResponse *            newResponse;
-       uint64_t                                        targetTicks;
-       
-       targetTicks = UpTicks() + MillisecondsToUpTicks( me->responseDelayMs );
-       
-       newResponse = (DNSDelayedResponse *) calloc( 1, sizeof( *newResponse ) );
-       require_action( newResponse, exit, err = kNoMemoryErr );
-       
-       if( !me->responseList || ( targetTicks < me->responseList->targetTicks ) )
-       {
-               dispatch_source_forget( &me->responseTimer );
-               
-               err = DispatchTimerCreate( dispatch_time_milliseconds( me->responseDelayMs ), DISPATCH_TIME_FOREVER,
-                       ( (uint64_t) me->responseDelayMs ) * kNanosecondsPerMillisecond / 10, me->queue, _DNSServerUDPDelayedSend,
-                       NULL, me, &me->responseTimer );
-               require_noerr( err, exit );
-               dispatch_resume( me->responseTimer );
-       }
-       
-       SockAddrCopy( inDestAddr, &newResponse->destAddr );
-       newResponse->targetTicks        = targetTicks;
-       newResponse->msgPtr                     = inMsgPtr;
-       newResponse->msgLen                     = inMsgLen;
-       
-       for( responsePtr = &me->responseList; ( response = *responsePtr ) != NULL; responsePtr = &response->next )
-       {
-               if( newResponse->targetTicks < response->targetTicks ) break;
-       }
-       newResponse->next = response;
-       *responsePtr = newResponse;
-       newResponse = NULL;
-       err = kNoErr;
-       
-exit:
-       if( newResponse ) _DNSDelayedResponseFree( newResponse );
-       return( err );
-}
-
-static void    _DNSServerUDPDelayedSend( void *inContext )
-{
-       OSStatus                                        err;
-       DNSServerRef const                      me                      = (DNSServerRef) inContext;
-       DNSDelayedResponse *            response;
-       SocketRef                                       sock;
-       ssize_t                                         n;
-       uint64_t                                        nowTicks;
-       uint64_t                                        remainingNs;
-       DNSDelayedResponse *            freeList        = NULL;
-       
-       dispatch_source_forget( &me->responseTimer );
-       
-       nowTicks = UpTicks();
-       while( ( ( response = me->responseList ) != NULL ) && ( response->targetTicks <= nowTicks ) )
-       {
-               me->responseList = response->next;
-               
-               ds_ulog( kLogLevelInfo, "UDP sending %zu byte response (delayed):\n\n%1{du:dnsmsg}",
-                       response->msgLen, response->msgPtr, response->msgLen );
-               
-               sock = ( response->destAddr.sa.sa_family == AF_INET ) ? me->sockUDPv4 : me->sockUDPv6;
-               n = sendto( sock, (char *) response->msgPtr, response->msgLen, 0, &response->destAddr.sa,
-                       SockAddrGetSize( &response->destAddr ) );
-               err = map_socket_value_errno( sock, n == (ssize_t) response->msgLen, n );
-               check_noerr( err );
-               
-               response->next  = freeList;
-               freeList                = response;
-               nowTicks = UpTicks();
-       }
-       
-       if( response )
-       {
-               check( response->targetTicks > nowTicks );
-               remainingNs = UpTicksToNanoseconds( response->targetTicks - nowTicks );
-               if( remainingNs > INT64_MAX ) remainingNs = INT64_MAX;
-               
-               err = DispatchTimerCreate( dispatch_time( DISPATCH_TIME_NOW, (int64_t) remainingNs ), DISPATCH_TIME_FOREVER, 0,
-                       me->queue, _DNSServerUDPDelayedSend, NULL, me, &me->responseTimer );
-               require_noerr( err, exit );
-               dispatch_resume( me->responseTimer );
-       }
-       
-exit:
-       if( freeList ) _DNSDelayedResponseFreeList( freeList );
-}
-
-//===========================================================================================================================
-//     _DNSServerAnswerQuery
-//===========================================================================================================================
-
-#define kLabelPrefix_Alias                     "alias"
-#define kLabelPrefix_AliasTTL          "alias-ttl"
-#define kLabelPrefix_Count                     "count-"
-#define kLabelPrefix_Tag                       "tag-"
-#define kLabelPrefix_TTL                       "ttl-"
-#define kLabel_IPv4                                    "ipv4"
-#define kLabel_IPv6                                    "ipv6"
-#define kLabelPrefix_SRV                       "srv-"
-
-#define kMaxAliasTTLCount              ( ( kDomainLabelLengthMax - sizeof_string( kLabelPrefix_AliasTTL ) ) / 2 )
-#define kMaxParsedSRVCount             ( kDomainNameLengthMax / ( 1 + sizeof_string( kLabelPrefix_SRV ) + 5 ) )
-
-typedef struct
-{
-       uint16_t                        priority;       // Priority from SRV label.
-       uint16_t                        weight;         // Weight from SRV label.
-       uint16_t                        port;           // Port number from SRV label.
-       uint16_t                        targetLen;      // Total length of the target hostname labels that follow an SRV label.
-       const uint8_t *         targetPtr;      // Pointer to the target hostname embedded in a domain name.
-       
-}      ParsedSRV;
-
-static OSStatus
-       _DNSServerInitializeResponseMessage(
-               DataBuffer *    inDB,
-               unsigned int    inID,
-               unsigned int    inFlags,
-               const uint8_t * inQName,
-               unsigned int    inQType,
-               unsigned int    inQClass );
-static OSStatus
-       _DNSServerAnswerQueryDynamically(
-               DNSServerRef    inServer,
-               const uint8_t * inQName,
-               unsigned int    inQType,
-               unsigned int    inQClass,
-               Boolean                 inForTCP,
-               DataBuffer *    inDB );
-static Boolean
-       _DNSServerNameIsSRVName(
-               DNSServerRef            inServer,
-               const uint8_t *         inName,
-               const uint8_t **        outDomainPtr,
-               size_t *                        outDomainLen,
-               ParsedSRV                       inSRVArray[ kMaxParsedSRVCount ],
-               size_t *                        outSRVCount );
-static Boolean
-       _DNSServerNameIsHostname(
-               DNSServerRef    inServer,
-               const uint8_t * inName,
-               uint32_t *              outAliasCount,
-               uint32_t                inAliasTTLs[ kMaxAliasTTLCount ],
-               size_t *                outAliasTTLCount,
-               unsigned int *  outCount,
-               unsigned int *  outRandCount,
-               uint32_t *              outTTL,
-               Boolean *               outHasA,
-               Boolean *               outHasAAAA,
-               Boolean *               outHasSOA );
-
-static OSStatus
-       _DNSServerAnswerQuery(
-               DNSServerRef                    me,
-               const uint8_t * const   inQueryPtr,
-               const size_t                    inQueryLen,
-               Boolean                                 inForTCP,
-               uint8_t **                              outResponsePtr,
-               size_t *                                outResponseLen )
-{
-       OSStatus                                        err;
-       DataBuffer                                      dataBuf;
-       const uint8_t *                         ptr;
-       const uint8_t * const           queryEnd = &inQueryPtr[ inQueryLen ];
-       const DNSHeader *                       qhdr;
-       unsigned int                            msgID, qflags, qtype, qclass, rflags;
-       uint8_t                                         qname[ kDomainNameLengthMax ];
-       
-       DataBuffer_Init( &dataBuf, NULL, 0, kDNSMaxTCPMessageSize );
-       
-       require_action_quiet( inQueryLen >= kDNSHeaderLength, exit, err = kUnderrunErr );
-       
-       qhdr    = (const DNSHeader *) inQueryPtr;
-       msgID   = DNSHeaderGetID( qhdr );
-       qflags  = DNSHeaderGetFlags( qhdr );
-       
-       // Minimal checking of the query message's header.
-       
-       if( ( qflags & kDNSHeaderFlag_Response ) ||                                     // The message must be a query, not a response.
-               ( DNSFlagsGetOpCode( qflags ) != kDNSOpCode_Query ) ||  // OPCODE must be QUERY (standard query).
-               ( DNSHeaderGetQuestionCount( qhdr ) != 1 ) )                    // There should be a single question.
-       {
-               err = kRequestErr;
-               goto exit;
-       }
-       
-       // Get QNAME.
-       
-       ptr = (const uint8_t *) &qhdr[ 1 ];
-       err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, ptr, qname, &ptr );
-       require_noerr( err, exit );
-       
-       // Get QTYPE and QCLASS.
-       
-       require_action_quiet( ( queryEnd - ptr ) >= 4, exit, err = kUnderrunErr );
-       qtype   = DNSQuestionFixedFieldsGetType( (const DNSQuestionFixedFields *) ptr );
-       qclass  = DNSQuestionFixedFieldsGetClass( (const DNSQuestionFixedFields *) ptr );
-       ptr += 4;
-       
-       // Create a tentative response message.
-       
-       rflags = kDNSHeaderFlag_Response;
-       if( qflags & kDNSHeaderFlag_RecursionDesired ) rflags |= kDNSHeaderFlag_RecursionDesired;
-       DNSFlagsSetOpCode( rflags, kDNSOpCode_Query );
-       
-       if( me->badUDPMode && !inForTCP ) msgID = (uint16_t)( msgID + 1 );
-       err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
-       require_noerr( err, exit );
-       
-       err = _DNSServerAnswerQueryDynamically( me, qname, qtype, qclass, inForTCP, &dataBuf );
-       if( err )
-       {
-               DNSFlagsSetRCode( rflags, kDNSRCode_ServerFailure );
-               err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
-               require_noerr( err, exit );
-       }
-       
-       err = DataBuffer_Detach( &dataBuf, outResponsePtr, outResponseLen );
-       require_noerr( err, exit );
-       
-exit:
-       DataBuffer_Free( &dataBuf );
-       return( err );
-}
-
-static OSStatus
-       _DNSServerInitializeResponseMessage(
-               DataBuffer *    inDB,
-               unsigned int    inID,
-               unsigned int    inFlags,
-               const uint8_t * inQName,
-               unsigned int    inQType,
-               unsigned int    inQClass )
-{
-       OSStatus                err;
-       DNSHeader               header;
-       
-       DataBuffer_Reset( inDB );
-       
-       memset( &header, 0, sizeof( header ) );
-       DNSHeaderSetID( &header, inID );
-       DNSHeaderSetFlags( &header, inFlags );
-       DNSHeaderSetQuestionCount( &header, 1 );
-       
-       err = DataBuffer_Append( inDB, &header, sizeof( header ) );
-       require_noerr( err, exit );
-       
-       err = _DataBuffer_AppendDNSQuestion( inDB, inQName, DomainNameLength( inQName ), (uint16_t) inQType,
-               (uint16_t) inQClass );
-       require_noerr( err, exit );
-       
-exit:
-       return( err );
-}
-
-static OSStatus
-       _DNSServerAnswerQueryDynamically(
-               DNSServerRef                    me,
-               const uint8_t * const   inQName,
-               const unsigned int              inQType,
-               const unsigned int              inQClass,
-               const Boolean                   inForTCP,
-               DataBuffer * const              inDB )
-{
-       OSStatus                                        err;
-       DNSHeader *                                     hdr;
-       unsigned int                            flags, rcode;
-       uint32_t                                        aliasCount, i;
-       uint32_t                                        aliasTTLs[ kMaxAliasTTLCount ];
-       size_t                                          aliasTTLCount;
-       unsigned int                            addrCount, randCount;
-       uint32_t                                        ttl;
-       ParsedSRV                                       srvArray[ kMaxParsedSRVCount ];
-       size_t                                          srvCount;
-       const uint8_t *                         srvDomainPtr;
-       size_t                                          srvDomainLen;
-       unsigned int                            answerCount;
-       Boolean                                         notImplemented, truncated;
-       Boolean                                         useAliasTTLs, nameExists, nameHasA, nameHasAAAA, nameHasSRV, nameHasSOA;
-       uint8_t                                         namePtr[ 2 ];
-       DNSRecordFixedFields            fields;
-       
-       answerCount     = 0;
-       truncated       = false;
-       nameExists      = false;
-       require_action_quiet( inQClass == kDNSServiceClass_IN, done, notImplemented = true );
-       
-       notImplemented  = false;
-       aliasCount              = 0;
-       nameHasA                = false;
-       nameHasAAAA             = false;
-       nameHasSOA              = false;
-       useAliasTTLs    = false;
-       nameHasSRV              = false;
-       srvDomainLen    = 0;
-       srvCount                = 0;
-       
-       if( _DNSServerNameIsHostname( me, inQName, &aliasCount, aliasTTLs, &aliasTTLCount, &addrCount, &randCount, &ttl,
-               &nameHasA, &nameHasAAAA, &nameHasSOA ) )
-       {
-               check( !( ( aliasCount > 0 ) && ( aliasTTLCount > 0 ) ) );
-               check( ( addrCount >= 1 ) && ( addrCount <= 255 ) );
-               check( ( randCount == 0 ) || ( ( randCount >= addrCount ) && ( randCount <= 255 ) ) );
-               check( nameHasA || nameHasAAAA );
-               
-               if( aliasTTLCount > 0 )
-               {
-                       aliasCount              = (uint32_t) aliasTTLCount;
-                       useAliasTTLs    = true;
-               }
-               nameExists = true;
-       }
-       else if( _DNSServerNameIsSRVName( me, inQName, &srvDomainPtr, &srvDomainLen, srvArray, &srvCount ) )
-       {
-               nameHasSRV = true;
-               nameExists = true;
-       }
-       require_quiet( nameExists, done );
-       
-       if( aliasCount > 0 )
-       {
-               size_t                          nameOffset;
-               uint8_t                         rdataLabel[ 1 + kDomainLabelLengthMax + 1 ];
-               
-               // If aliasCount is non-zero, then the first label of QNAME is either "alias" or "alias-<N>". superPtr is a name
-               // compression pointer to the second label of QNAME, i.e., the immediate superdomain name of QNAME. It's used for
-               // the RDATA of CNAME records whose canonical name ends with the superdomain name. It may also be used to construct
-               // CNAME record names, when the offset to the previous CNAME's RDATA doesn't fit in a compression pointer.
-               
-               const uint8_t           superPtr[ 2 ] = { 0xC0, (uint8_t)( kDNSHeaderLength + 1 + inQName[ 0 ] ) };
-               
-               // The name of the first CNAME record is equal to QNAME, so nameOffset is set to offset of QNAME.
-               
-               nameOffset = kDNSHeaderLength;
-               
-               for( i = aliasCount; i >= 1; --i )
-               {
-                       size_t                  nameLen;
-                       size_t                  rdataLen;
-                       uint32_t                j;
-                       uint32_t                aliasTTL;
-                       uint8_t                 nameLabel[ 1 + kDomainLabelLengthMax ];
-                       
-                       if( nameOffset <= kDNSCompressionOffsetMax )
-                       {
-                               WriteDNSCompressionPtr( namePtr, nameOffset );
-                               nameLen = sizeof( namePtr );
-                       }
-                       else
-                       {
-                               memcpy( nameLabel, rdataLabel, 1 + rdataLabel[ 0 ] );
-                               nameLen = 1 + nameLabel[ 0 ] + sizeof( superPtr );
-                       }
-                       
-                       if( i >= 2 )
-                       {
-                               char *                          dst = (char *) &rdataLabel[ 1 ];
-                               char * const            lim = (char *) &rdataLabel[ countof( rdataLabel ) ];
-                               
-                               if( useAliasTTLs )
-                               {
-                                       err = SNPrintF_Add( &dst, lim, kLabelPrefix_AliasTTL );
-                                       require_noerr( err, exit );
-                                       
-                                       for( j = aliasCount - ( i - 1 ); j < aliasCount; ++j )
-                                       {
-                                               err = SNPrintF_Add( &dst, lim, "-%u", aliasTTLs[ j ] );
-                                               require_noerr( err, exit );
-                                       }
-                               }
-                               else
-                               {
-                                       err = SNPrintF_Add( &dst, lim, kLabelPrefix_Alias "%?{end}-%u", i == 2, i - 1 );
-                                       require_noerr( err, exit );
-                               }
-                               rdataLabel[ 0 ] = (uint8_t)( dst - (char *) &rdataLabel[ 1 ] );
-                               rdataLen                = 1 + rdataLabel[ 0 ] + sizeof( superPtr );
-                       }
-                       else
-                       {
-                               rdataLen = sizeof( superPtr );
-                       }
-                       
-                       if( !inForTCP )
-                       {
-                               size_t          recordLen = nameLen + sizeof( fields ) + rdataLen;
-                               
-                               if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
-                               {
-                                       truncated = true;
-                                       goto done;
-                               }
-                       }
-                       ++answerCount;
-                       
-                       // Set CNAME record's NAME.
-                       
-                       if( nameOffset <= kDNSCompressionOffsetMax )
-                       {
-                               err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
-                               require_noerr( err, exit );
-                       }
-                       else
-                       {
-                               err = DataBuffer_Append( inDB, nameLabel, 1 + nameLabel[ 0 ] );
-                               require_noerr( err, exit );
-                               
-                               err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
-                               require_noerr( err, exit );
-                       }
-                       
-                       // Set CNAME record's TYPE, CLASS, TTL, and RDLENGTH.
-                       
-                       aliasTTL = useAliasTTLs ? aliasTTLs[ aliasCount - i ] : me->defaultTTL;
-                       DNSRecordFixedFieldsSet( &fields, kDNSServiceType_CNAME, kDNSServiceClass_IN, aliasTTL, (uint16_t) rdataLen );
-                       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
-                       require_noerr( err, exit );
-                       
-                       // Save offset of CNAME record's RDATA, which may be used for the name of the next CNAME record.
-                       
-                       nameOffset = DataBuffer_GetLen( inDB );
-                       
-                       // Set CNAME record's RDATA.
-                       
-                       if( i >= 2 )
-                       {
-                               err = DataBuffer_Append( inDB, rdataLabel, 1 + rdataLabel[ 0 ] );
-                               require_noerr( err, exit );
-                       }
-                       err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
-                       require_noerr( err, exit );
-               }
-               
-               namePtr[ 0 ] = superPtr[ 0 ];
-               namePtr[ 1 ] = superPtr[ 1 ];
-       }
-       else
-       {
-               // There are no aliases, so initialize the name compression pointer to point to QNAME.
-               
-               WriteDNSCompressionPtr( namePtr, kDNSHeaderLength );
-       }
-       
-       if( ( inQType == kDNSServiceType_A ) || ( inQType == kDNSServiceType_AAAA ) )
-       {
-               uint8_t *               lsb;                                    // Pointer to the least significant byte of record data.
-               size_t                  recordLen;                              // Length of the entire record.
-               size_t                  rdataLen;                               // Length of record's RDATA.
-               uint8_t                 rdata[ 16 ];                    // A buffer that's big enough for either A or AAAA RDATA.
-               uint8_t                 randIntegers[ 255 ];    // Array for random integers in [1, 255].
-               const int               useBadAddrs = ( me->badUDPMode && !inForTCP ) ? true : false;
-               
-               if( inQType == kDNSServiceType_A )
-               {
-                       const uint32_t          baseAddrV4 = useBadAddrs ? kDNSServerBadBaseAddrV4 : kDNSServerBaseAddrV4;
-                       
-                       require_quiet( nameHasA, done );
-                       
-                       rdataLen = 4;
-                       WriteBig32( rdata, baseAddrV4 );
-                       lsb = &rdata[ 3 ];
-               }
-               else
-               {
-                       const uint8_t * const           baseAddrV6 = useBadAddrs ? kDNSServerBadBaseAddrV6 : kDNSServerBaseAddrV6;
-                       
-                       require_quiet( nameHasAAAA, done );
-                       
-                       rdataLen = 16;
-                       memcpy( rdata, baseAddrV6, 16 );
-                       lsb = &rdata[ 15 ];
-               }
-               
-               if( randCount > 0 )
-               {
-                       // Populate the array with all integers between 1 and <randCount>, inclusive.
-                       
-                       for( i = 0; i < randCount; ++i ) randIntegers[ i ] = (uint8_t)( i + 1 );
-                       
-                       // Prevent dubious static analyzer warning.
-                       // Note: _DNSServerNameIsHostname() already enforces randCount >= addrCount. Also, this require_fatal() check
-                       // needs to be placed right before the next for-loop. Any earlier, and the static analyzer warning will persist
-                       // for some reason.
-                       
-                       require_fatal( addrCount <= randCount, "Invalid Count label values: addrCount %u > randCount %u",
-                               addrCount, randCount );
-                       
-                       // Create a contiguous subarray starting at index 0 that contains <addrCount> randomly chosen integers between
-                       // 1 and <randCount>, inclusive.
-                       // Loop invariant 1: Array elements with indexes in [0, i - 1] have been randomly chosen.
-                       // Loop invariant 2: Array elements with indexes in [i, randCount - 1] are candidates for being chosen.
-                       
-                       for( i = 0; i < addrCount; ++i )
-                       {
-                               uint8_t                 tmp;
-                               uint32_t                j;
-                               
-                               j = RandomRange( i, randCount - 1 );
-                               if( i != j )
-                               {
-                                       tmp = randIntegers[ i ];
-                                       randIntegers[ i ] = randIntegers[ j ];
-                                       randIntegers[ j ] = tmp;
-                               }
-                       }
-               }
-               
-               recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
-               for( i = 0; i < addrCount; ++i )
-               {
-                       if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
-                       {
-                               truncated = true;
-                               goto done;
-                       }
-                       
-                       // Set record NAME.
-                       
-                       err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
-                       require_noerr( err, exit );
-                       
-                       // Set record TYPE, CLASS, TTL, and RDLENGTH.
-                       
-                       DNSRecordFixedFieldsSet( &fields, (uint16_t) inQType, kDNSServiceClass_IN, ttl, (uint16_t) rdataLen );
-                       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
-                       require_noerr( err, exit );
-                       
-                       // Set record RDATA.
-                       
-                       *lsb = ( randCount > 0 ) ? randIntegers[ i ] : ( *lsb + 1 );
-                       
-                       err = DataBuffer_Append( inDB, rdata, rdataLen );
-                       require_noerr( err, exit );
-                       
-                       ++answerCount;
-               }
-       }
-       else if( inQType == kDNSServiceType_SRV )
-       {
-               require_quiet( nameHasSRV, done );
-               
-               DNSRecordFixedFieldsSet( &fields, kDNSServiceType_SRV, kDNSServiceClass_IN, me->defaultTTL, 0 );
-               
-               for( i = 0; i < srvCount; ++i )
-               {
-                       SRVRecordDataFixedFields                fieldsSRV;
-                       size_t                                                  rdataLen;
-                       size_t                                                  recordLen;
-                       const ParsedSRV * const                 srv = &srvArray[ i ];
-                       
-                       rdataLen  = sizeof( fieldsSRV ) + srvDomainLen + srv->targetLen + 1;
-                       recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
-                       
-                       if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
-                       {
-                               truncated = true;
-                               goto done;
-                       }
-                       
-                       // Append record NAME.
-                       
-                       err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
-                       require_noerr( err, exit );
-                       
-                       // Append record TYPE, CLASS, TTL, and RDLENGTH.
-                       
-                       WriteBig16( fields.rdlength, rdataLen );
-                       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
-                       require_noerr( err, exit );
-                       
-                       // Append SRV RDATA.
-                       
-                       SRVRecordDataFixedFieldsSet( &fieldsSRV, srv->priority, srv->weight, srv->port );
-                       
-                       err = DataBuffer_Append( inDB, &fieldsSRV, sizeof( fieldsSRV ) );
-                       require_noerr( err, exit );
-                       
-                       if( srv->targetLen > 0 )
-                       {
-                               err = DataBuffer_Append( inDB, srv->targetPtr, srv->targetLen );
-                               require_noerr( err, exit );
-                       }
-                       
-                       if( srvDomainLen > 0 )
-                       {
-                               err = DataBuffer_Append( inDB, srvDomainPtr, srvDomainLen );
-                               require_noerr( err, exit );
-                       }
-                       
-                       err = DataBuffer_Append( inDB, "", 1 ); // Append root label.
-                       require_noerr( err, exit );
-                       
-                       ++answerCount;
-               }
-       }
-       else if( inQType == kDNSServiceType_SOA )
-       {
-               size_t          nameLen, recordLen;
-               
-               require_quiet( nameHasSOA, done );
-               
-               nameLen = DomainNameLength( me->domain );
-               if( !inForTCP )
-               {
-                       err = AppendSOARecord( NULL, me->domain, nameLen, 0, 0, 0, kRootLabel, kRootLabel, 0, 0, 0, 0, 0, &recordLen );
-                       require_noerr( err, exit );
-                       
-                       if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
-                       {
-                               truncated = true;
-                               goto done;
-                       }
-               }
-               
-               err = AppendSOARecord( inDB, me->domain, nameLen, kDNSServiceType_SOA, kDNSServiceClass_IN, me->defaultTTL,
-                       kRootLabel, kRootLabel, me->serial, 1 * kSecondsPerDay, 2 * kSecondsPerHour, 1000 * kSecondsPerHour,
-                       me->defaultTTL, NULL );
-               require_noerr( err, exit );
-               
-               ++answerCount;
-       }
-       
-done:
-       hdr = (DNSHeader *) DataBuffer_GetPtr( inDB );
-       flags = DNSHeaderGetFlags( hdr );
-       if( notImplemented )
-       {
-               rcode = kDNSRCode_NotImplemented;
-       }
-       else
-       {
-               flags |= kDNSHeaderFlag_AuthAnswer;
-               if( truncated ) flags |= kDNSHeaderFlag_Truncation;
-               rcode = nameExists ? kDNSRCode_NoError : kDNSRCode_NXDomain;
-       }
-       DNSFlagsSetRCode( flags, rcode );
-       DNSHeaderSetFlags( hdr, flags );
-       DNSHeaderSetAnswerCount( hdr, answerCount );
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-static Boolean
-       _DNSServerNameIsHostname(
-               DNSServerRef    me,
-               const uint8_t * inName,
-               uint32_t *              outAliasCount,
-               uint32_t                inAliasTTLs[ kMaxAliasTTLCount ],
-               size_t *                outAliasTTLCount,
-               unsigned int *  outCount,
-               unsigned int *  outRandCount,
-               uint32_t *              outTTL,
-               Boolean *               outHasA,
-               Boolean *               outHasAAAA,
-               Boolean *               outHasSOA )
-{
-       OSStatus                        err;
-       const uint8_t *         label;
-    const uint8_t *            nextLabel;
-       uint32_t                        aliasCount              = 0;    // Arg from Alias label. Valid values are in [2, 2^31 - 1].
-       unsigned int            count                   = 0;    // First arg from Count label. Valid values are in [1, 255].
-       unsigned int            randCount               = 0;    // Second arg from Count label. Valid values are in [count, 255].
-       int32_t                         ttl                             = -1;   // Arg from TTL label. Valid values are in [0, 2^31 - 1].
-       size_t                          aliasTTLCount   = 0;    // Count of TTL args from Alias-TTL label.
-       int                                     hasTagLabel             = false;
-       int                                     hasIPv4Label    = false;
-       int                                     hasIPv6Label    = false;
-       int                                     isNameValid             = false;
-       
-       for( label = inName; label[ 0 ]; label = nextLabel )
-       {
-               uint32_t                arg;
-               
-               nextLabel = &label[ 1 + label[ 0 ] ];
-               
-               // Check if the first label is a valid alias TTL sequence label.
-               
-               if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_AliasTTL ) == 0 ) )
-               {
-                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_AliasTTL ) ];
-                       const char * const              end = (const char *) nextLabel;
-                       const char *                    next;
-                       
-                       check( label[ 0 ] <= kDomainLabelLengthMax );
-                       
-                       while( ptr < end )
-                       {
-                               if( *ptr != '-' ) break;
-                               ++ptr;
-                               err = DecimalTextToUInt32( ptr, end, &arg, &next );
-                               if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
-                               inAliasTTLs[ aliasTTLCount++ ] = arg;
-                               ptr = next;
-                       }
-                       if( ( aliasTTLCount == 0 ) || ( ptr != end ) ) break;
-               }
-               
-               // Check if the first label is a valid alias label.
-               
-               else if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Alias ) == 0 ) )
-               {
-                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Alias ) ];
-                       const char * const              end = (const char *) nextLabel;
-                       
-                       if( ptr < end )
-                       {
-                               if( *ptr++ != '-' ) break;
-                               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
-                               if( err || ( arg < 2 ) || ( arg > INT32_MAX ) ) break;  // Alias count must be in [2, 2^31 - 1].
-                               aliasCount = arg;
-                               if( ptr != end ) break;
-                       }
-                       else
-                       {
-                               aliasCount = 1;
-                       }
-               }
-               
-               // Check if this label is a valid count label.
-               
-               else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Count ) == 0  )
-               {
-                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Count ) ];
-                       const char * const              end = (const char *) nextLabel;
-                       
-                       if( count > 0 ) break;  // Count cannot be specified more than once.
-                       
-                       err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
-                       if( err || ( arg < 1 ) || ( arg > 255 ) ) break;        // Count must be in [1, 255].
-                       count = (unsigned int) arg;
-                       
-                       if( ptr < end )
-                       {
-                               if( *ptr++ != '-' ) break;
-                               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
-                               if( err || ( arg < (uint32_t) count ) || ( arg > 255 ) ) break; // Rand count must be in [count, 255].
-                               randCount = (unsigned int) arg;
-                               if( ptr != end ) break;
-                       }
-               }
-               
-               // Check if this label is a valid TTL label.
-               
-               else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_TTL ) == 0  )
-               {
-                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_TTL ) ];
-                       const char * const              end = (const char *) nextLabel;
-                       
-                       if( ttl >= 0 ) break;   // TTL cannot be specified more than once.
-                       
-                       err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
-                       if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
-                       ttl = (int32_t) arg;
-                       if( ptr != end ) break;
-               }
-               
-               // Check if this label is a valid IPv4 label.
-               
-               else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv4 ) == 0 )
-               {
-                       if( hasIPv4Label || hasIPv6Label ) break;       // Valid names have at most one IPv4 or IPv6 label.
-                       hasIPv4Label = true;
-               }
-               
-               // Check if this label is a valid IPv6 label.
-               
-               else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv6 ) == 0 )
-               {
-                       if( hasIPv4Label || hasIPv6Label ) break;       // Valid names have at most one IPv4 or IPv6 label.
-                       hasIPv6Label = true;
-               }
-               
-               // Check if this label is a valid tag label.
-               
-               else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Tag ) == 0  )
-               {
-                       hasTagLabel = true;
-               }
-               
-               // If this and the remaining labels are equal to "d.test.", then the name exists. Otherwise, this label is invalid.
-               // In both cases, there are no more labels to check.
-               
-               else
-               {
-                       if( DomainNameEqual( label, me->domain ) ) isNameValid = true;
-                       break;
-               }
-       }
-       require_quiet( isNameValid, exit );
-       
-       if( outAliasCount )             *outAliasCount          = aliasCount;
-       if( outAliasTTLCount )  *outAliasTTLCount       = aliasTTLCount;
-       if( outCount )                  *outCount                       = ( count > 0 ) ? count : 1;
-       if( outRandCount )              *outRandCount           = randCount;
-       if( outTTL )                    *outTTL                         = ( ttl >= 0 ) ? ( (uint32_t) ttl ) : me->defaultTTL;
-       if( outHasA )                   *outHasA                        = ( hasIPv4Label || !hasIPv6Label ) ? true : false;
-       if( outHasAAAA )                *outHasAAAA                     = ( hasIPv6Label || !hasIPv4Label ) ? true : false;
-       if( outHasSOA )
-       {
-               *outHasSOA = ( !count && ( ttl < 0 ) && !hasIPv4Label && !hasIPv6Label && !hasTagLabel ) ? true : false;
-       }
-       
-exit:
-       return( isNameValid ? true : false );
-}
-
-static Boolean
-       _DNSServerNameIsSRVName(
-               DNSServerRef            me,
-               const uint8_t *         inName,
-               const uint8_t **        outDomainPtr,
-               size_t *                        outDomainLen,
-               ParsedSRV                       inSRVArray[ kMaxParsedSRVCount ],
-               size_t *                        outSRVCount )
-{
-       OSStatus                        err;
-       const uint8_t *         label;
-       const uint8_t *         domainPtr;
-       size_t                          domainLen;
-       size_t                          srvCount;
-       uint32_t                        arg;
-       int                                     isNameValid = false;
-       
-       label = inName;
-       
-       // Ensure that first label, i.e, the service label, begins with a '_' character.
-       
-       require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
-       label = NextLabel( label );
-       
-       // Ensure that the second label, i.e., the proto label, begins with a '_' character (usually _tcp or _udp).
-       
-       require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
-       label = NextLabel( label );
-       
-       // Parse the domain name, if any.
-       
-       domainPtr = label;
-       while( *label )
-       {
-               if( DomainNameEqual( label, me->domain ) ||
-                       ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
-               label = NextLabel( label );
-       }
-       require_quiet( *label, exit );
-       
-       domainLen = (size_t)( label - domainPtr );
-       
-       // Parse SRV labels, if any.
-       
-       srvCount = 0;
-       while( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 )
-       {
-               const uint8_t * const   nextLabel       = NextLabel( label );
-               const char *                    ptr                     = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_SRV ) ];
-               const char * const              end                     = (const char *) nextLabel;
-               const uint8_t *                 target;
-               unsigned int                    priority, weight, port;
-               
-               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
-               require_quiet( !err && ( arg <= UINT16_MAX ), exit );
-               priority = (unsigned int) arg;
-               
-               require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
-               ++ptr;
-               
-               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
-               require_quiet( !err && ( arg <= UINT16_MAX ), exit );
-               weight = (unsigned int) arg;
-               
-               require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
-               ++ptr;
-               
-               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
-               require_quiet( !err && ( arg <= UINT16_MAX ), exit );
-               port = (unsigned int) arg;
-               
-               require_quiet( ptr == end, exit );
-               
-               target = nextLabel;
-               for( label = nextLabel; *label; label = NextLabel( label ) )
-               {
-                       if( DomainNameEqual( label, me->domain ) ||
-                               ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
-               }
-               require_quiet( *label, exit );
-               
-               if( inSRVArray )
-               {
-                       inSRVArray[ srvCount ].priority         = (uint16_t) priority;
-                       inSRVArray[ srvCount ].weight           = (uint16_t) weight;
-                       inSRVArray[ srvCount ].port                     = (uint16_t) port;
-                       inSRVArray[ srvCount ].targetPtr        = target;
-                       inSRVArray[ srvCount ].targetLen        = (uint16_t)( label - target );
-               }
-               ++srvCount;
-       }
-       require_quiet( DomainNameEqual( label, me->domain ), exit );
-       isNameValid = true;
-       
-       if( outDomainPtr )      *outDomainPtr   = domainPtr;
-       if( outDomainLen )      *outDomainLen   = domainLen;
-       if( outSRVCount )       *outSRVCount    = srvCount;
-       
-exit:
-       return( isNameValid ? true : false );
-}
-
-//===========================================================================================================================
-//     _DNSServerTCPReadHandler
-//===========================================================================================================================
-
-typedef struct
-{
-       DNSServerRef                    server;                 // Reference to DNS server object.
-       sockaddr_ip                             clientAddr;             // Client's address.
-       dispatch_source_t               readSource;             // Dispatch read source for client socket.
-       dispatch_source_t               writeSource;    // Dispatch write source for client socket.
-       size_t                                  offset;                 // Offset into receive buffer.
-       void *                                  msgPtr;                 // Pointer to dynamically allocated message buffer.
-       size_t                                  msgLen;                 // Length of message buffer.
-       Boolean                                 readSuspended;  // True if the read source is currently suspended.
-       Boolean                                 writeSuspended; // True if the write source is currently suspended.
-       Boolean                                 receivedLength; // True if receiving DNS message as opposed to the message length.
-       uint8_t                                 lenBuf[ 2 ];    // Buffer for two-octet message length field.
-       iovec_t                                 iov[ 2 ];               // IO vector for writing response message.
-       iovec_t *                               iovPtr;                 // Vector pointer for SocketWriteData().
-       int                                             iovCount;               // Vector count for SocketWriteData().
-       
-}      TCPConnectionContext;
-
-static void    TCPConnectionStop( TCPConnectionContext *inContext );
-static void    TCPConnectionContextFree( TCPConnectionContext *inContext );
-static void    TCPConnectionReadHandler( void *inContext );
-static void    TCPConnectionWriteHandler( void *inContext );
-
-#define        TCPConnectionForget( X )                ForgetCustomEx( X, TCPConnectionStop, TCPConnectionContextFree )
-
-static void    _DNSServerTCPReadHandler( void *inContext )
-{
-       OSStatus                                        err;
-       SocketContext * const           sockCtx         = (SocketContext *) inContext;
-       DNSServerRef const                      me                      = (DNSServerRef) sockCtx->userContext;
-       TCPConnectionContext *          connection;
-       socklen_t                                       clientAddrLen;
-       SocketRef                                       newSock         = kInvalidSocketRef;
-       SocketContext *                         newSockCtx      = NULL;
-       
-       connection = (TCPConnectionContext *) calloc( 1, sizeof( *connection ) );
-       require_action( connection, exit, err = kNoMemoryErr );
-       
-       CFRetain( me );
-       connection->server = me;
-       
-       clientAddrLen = (socklen_t) sizeof( connection->clientAddr );
-       newSock = accept( sockCtx->sock, &connection->clientAddr.sa, &clientAddrLen );
-       err = map_socket_creation_errno( newSock );
-       require_noerr( err, exit );
-       
-       err = SocketContextCreate( newSock, connection, &newSockCtx );
-       require_noerr( err, exit );
-       newSock = kInvalidSocketRef;
-       
-       err = DispatchReadSourceCreate( newSockCtx->sock, me->queue, TCPConnectionReadHandler, SocketContextCancelHandler,
-               newSockCtx, &connection->readSource );
-       require_noerr( err, exit );
-       SocketContextRetain( newSockCtx );
-       dispatch_resume( connection->readSource );
-       
-       err = DispatchWriteSourceCreate( newSockCtx->sock, me->queue, TCPConnectionWriteHandler, SocketContextCancelHandler,
-               newSockCtx, &connection->writeSource );
-       require_noerr( err, exit );
-       SocketContextRetain( newSockCtx );
-       connection->writeSuspended = true;
-       connection = NULL;
-       
-exit:
-       ForgetSocket( &newSock );
-       SocketContextRelease( newSockCtx );
-       TCPConnectionForget( &connection );
-}
-
-//===========================================================================================================================
-//     TCPConnectionStop
-//===========================================================================================================================
-
-static void    TCPConnectionStop( TCPConnectionContext *inContext )
-{
-       dispatch_source_forget_ex( &inContext->readSource, &inContext->readSuspended );
-       dispatch_source_forget_ex( &inContext->writeSource, &inContext->writeSuspended );
-}
-
-//===========================================================================================================================
-//     TCPConnectionContextFree
-//===========================================================================================================================
-
-static void    TCPConnectionContextFree( TCPConnectionContext *inContext )
-{
-       check( !inContext->readSource );
-       check( !inContext->writeSource );
-       ForgetCF( &inContext->server );
-       ForgetMem( &inContext->msgPtr );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     TCPConnectionReadHandler
-//===========================================================================================================================
-
-static void    TCPConnectionReadHandler( void *inContext )
-{
-       OSStatus                                        err;
-       SocketContext * const           sockCtx         = (SocketContext *) inContext;
-       TCPConnectionContext *          connection      = (TCPConnectionContext *) sockCtx->userContext;
-       struct timeval                          now;
-       uint8_t *                                       responsePtr     = NULL; // malloc'd
-       size_t                                          responseLen;
-       
-       // Receive message length.
-       
-       if( !connection->receivedLength )
-       {
-               err = SocketReadData( sockCtx->sock, connection->lenBuf, sizeof( connection->lenBuf ), &connection->offset );
-               if( err == EWOULDBLOCK ) goto exit;
-               require_noerr( err, exit );
-               
-               connection->offset = 0;
-               connection->msgLen = ReadBig16( connection->lenBuf );
-               connection->msgPtr = malloc( connection->msgLen );
-               require_action( connection->msgPtr, exit, err = kNoMemoryErr );
-               connection->receivedLength = true;
-       }
-       
-       // Receive message.
-       
-       err = SocketReadData( sockCtx->sock, connection->msgPtr, connection->msgLen, &connection->offset );
-       if( err == EWOULDBLOCK ) goto exit;
-       require_noerr( err, exit );
-       
-       gettimeofday( &now, NULL );
-       dispatch_suspend( connection->readSource );
-       connection->readSuspended = true;
-       
-       ds_ulog( kLogLevelInfo, "TCP server received %zu bytes from %##a at %{du:time}.\n",
-               connection->msgLen, &connection->clientAddr, &now );
-       
-       if( connection->msgLen < kDNSHeaderLength )
-       {
-               ds_ulog( kLogLevelInfo, "TCP DNS message is too small (%zu < %d).\n", connection->msgLen, kDNSHeaderLength );
-               goto exit;
-       }
-       
-       ds_ulog( kLogLevelInfo, "TCP received message:\n\n%1{du:dnsmsg}", connection->msgPtr, connection->msgLen );
-       
-       // Create response.
-       
-       err = _DNSServerAnswerQueryForTCP( connection->server, connection->msgPtr, connection->msgLen, &responsePtr,
-               &responseLen );
-       require_noerr_quiet( err, exit );
-       
-       // Send response.
-       
-       ds_ulog( kLogLevelInfo, "TCP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
-       
-       free( connection->msgPtr );
-       connection->msgPtr = responsePtr;
-       connection->msgLen = responseLen;
-       responsePtr = NULL;
-       
-       check( connection->msgLen <= UINT16_MAX );
-       WriteBig16( connection->lenBuf, connection->msgLen );
-       connection->iov[ 0 ].iov_base   = connection->lenBuf;
-       connection->iov[ 0 ].iov_len    = sizeof( connection->lenBuf );
-       connection->iov[ 1 ].iov_base   = connection->msgPtr;
-       connection->iov[ 1 ].iov_len    = connection->msgLen;
-       
-       connection->iovPtr              = connection->iov;
-       connection->iovCount    = 2;
-       
-       check( connection->writeSuspended );
-       dispatch_resume( connection->writeSource );
-       connection->writeSuspended = false;
-       
-exit:
-       FreeNullSafe( responsePtr );
-       if( err && ( err != EWOULDBLOCK ) ) TCPConnectionForget( &connection );
-}
-
-//===========================================================================================================================
-//     TCPConnectionWriteHandler
-//===========================================================================================================================
-
-static void    TCPConnectionWriteHandler( void *inContext )
-{
-       OSStatus                                        err;
-       SocketContext * const           sockCtx         = (SocketContext *) inContext;
-       TCPConnectionContext *          connection      = (TCPConnectionContext *) sockCtx->userContext;
-       
-       err = SocketWriteData( sockCtx->sock, &connection->iovPtr, &connection->iovCount );
-       if( err == EWOULDBLOCK ) goto exit;
-       check_noerr( err );
-       
-       TCPConnectionForget( &connection );
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     MDNSReplierCmd
-//===========================================================================================================================
-
-typedef struct
-{
-       uint8_t *                               hostname;                       // Used as the base name for hostnames and service names.
-       uint8_t *                               serviceLabel;           // Label containing the base service name.
-       unsigned int                    maxInstanceCount;       // Maximum number of service instances and hostnames.
-       uint64_t *                              bitmaps;                        // Array of 64-bit bitmaps for keeping track of needed responses.
-       size_t                                  bitmapCount;            // Number of 64-bit bitmaps.
-       dispatch_source_t               readSourceV4;           // Read dispatch source for IPv4 socket.
-       dispatch_source_t               readSourceV6;           // Read dispatch source for IPv6 socket.
-       uint32_t                                ifIndex;                        // Index of the interface to run on.
-       unsigned int                    recordCountA;           // Number of A records per hostname.
-       unsigned int                    recordCountAAAA;        // Number of AAAA records per hostname.
-       unsigned int                    maxDropCount;           // If > 0, the drop rates apply to only the first <maxDropCount> responses.
-       double                                  ucastDropRate;          // Probability of dropping a unicast response.
-       double                                  mcastDropRate;          // Probability of dropping a multicast query or response.
-       uint8_t *                               dropCounters;           // If maxDropCount > 0, array of <maxInstanceCount> response drop counters.
-       Boolean                                 noAdditionals;          // True if responses are to not include additional records.
-       Boolean                                 useIPv4;                        // True if the replier is to use IPv4.
-       Boolean                                 useIPv6;                        // True if the replier is to use IPv6.
-       uint8_t                                 msgBuf[ kMDNSMessageSizeMax ];  // Buffer for received mDNS message.
-#if( TARGET_OS_DARWIN )
-       dispatch_source_t               processMonitor;         // Process monitor source for process being followed, if any.
-       pid_t                                   followPID;                      // PID of process being followed, if any. (If it exits, we exit).
-#endif
-       
-}      MDNSReplierContext;
-
-typedef struct MRResourceRecord                MRResourceRecord;
-struct MRResourceRecord
-{
-       MRResourceRecord *              next;           // Next item in list.
-       uint8_t *                               name;           // Resource record name.
-       uint16_t                                type;           // Resource record type.
-       uint16_t                                class;          // Resource record class.
-       uint32_t                                ttl;            // Resource record TTL.
-       uint16_t                                rdlength;       // Resource record data length.
-       uint8_t *                               rdata;          // Resource record data.
-       const uint8_t *                 target;         // For SRV records, pointer to target in RDATA.
-};
-
-typedef struct MRNameOffsetItem                MRNameOffsetItem;
-struct MRNameOffsetItem
-{
-       MRNameOffsetItem *      next;           // Next item in list.
-       uint16_t                        offset;         // Offset of domain name in response message.
-       uint8_t                         name[ 1 ];      // Variable-length array for domain name.
-};
-
-#if( TARGET_OS_DARWIN )
-static void            _MDNSReplierFollowedProcessHandler( void *inContext );
-#endif
-static void            _MDNSReplierReadHandler( void *inContext );
-static OSStatus
-       _MDNSReplierAnswerQuery(
-               MDNSReplierContext *    inContext,
-               const uint8_t *                 inQueryPtr,
-               size_t                                  inQueryLen,
-               sockaddr_ip *                   inSender,
-               SocketRef                               inSock,
-               unsigned int                    inIndex );
-static OSStatus
-       _MDNSReplierAnswerListAdd(
-               MDNSReplierContext *    inContext,
-               MRResourceRecord **             inAnswerList,
-               unsigned int                    inIndex,
-               const uint8_t *                 inName,
-               unsigned int                    inType,
-               unsigned int                    inClass );
-static void
-       _MDNSReplierAnswerListRemovePTR(
-               MRResourceRecord **     inAnswerListPtr,
-               const uint8_t *         inName,
-               const uint8_t *         inRData );
-static OSStatus
-       _MDNSReplierSendOrDropResponse(
-               MDNSReplierContext *    inContext,
-               MRResourceRecord *              inAnswerList,
-               sockaddr_ip *                   inQuerier,
-               SocketRef                               inSock,
-               unsigned int                    inIndex,
-               Boolean                                 inUnicast );
-static OSStatus
-       _MDNSReplierCreateResponse(
-               MDNSReplierContext *    inContext,
-               MRResourceRecord *              inAnswerList,
-               unsigned int                    inIndex,
-               uint8_t **                              outResponsePtr,
-               size_t *                                outResponseLen );
-static OSStatus
-       _MDNSReplierAppendNameToResponse(
-               DataBuffer *            inResponse,
-               const uint8_t *         inName,
-               MRNameOffsetItem **     inNameOffsetListPtr );
-static Boolean
-       _MDNSReplierServiceTypeMatch(
-               const MDNSReplierContext *      inContext,
-               const uint8_t *                         inName,
-               unsigned int *                          outTXTSize,
-               unsigned int *                          outCount );
-static Boolean
-       _MDNSReplierServiceInstanceNameMatch(
-               const MDNSReplierContext *      inContext,
-               const uint8_t *                         inName,
-               unsigned int *                          outIndex,
-               unsigned int *                          outTXTSize,
-               unsigned int *                          outCount );
-static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName );
-static Boolean
-       _MDNSReplierHostnameMatch(
-               const MDNSReplierContext *      inContext,
-               const uint8_t *                         inName,
-               unsigned int *                          outIndex );
-static OSStatus        _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT );
-static OSStatus
-       _MRResourceRecordCreate(
-               uint8_t *                       inName,
-               uint16_t                        inType,
-               uint16_t                        inClass,
-               uint32_t                        inTTL,
-               uint16_t                        inRDLength,
-               uint8_t *                       inRData,
-               MRResourceRecord **     outRecord );
-static void            _MRResourceRecordFree( MRResourceRecord *inRecord );
-static void            _MRResourceRecordFreeList( MRResourceRecord *inList );
-static OSStatus        _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem );
-static void            _MRNameOffsetItemFree( MRNameOffsetItem *inItem );
-static void            _MRNameOffsetItemFreeList( MRNameOffsetItem *inList );
-
-ulog_define_ex( "com.apple.dnssdutil", MDNSReplier, kLogLevelInfo, kLogFlags_None, "MDNSReplier", NULL );
-#define mr_ulog( LEVEL, ... )          ulog( &log_category_from_name( MDNSReplier ), (LEVEL), __VA_ARGS__ )
-
-static void    MDNSReplierCmd( void )
-{
-       OSStatus                                        err;
-       MDNSReplierContext *            context;
-       SocketRef                                       sockV4  = kInvalidSocketRef;
-       SocketRef                                       sockV6  = kInvalidSocketRef;
-       const char *                            ifname;
-       size_t                                          len;
-       uint8_t                                         name[ 1 + kDomainLabelLengthMax + 1 ];
-       char                                            ifnameBuf[ IF_NAMESIZE + 1 ];
-       
-       err = CheckIntegerArgument( gMDNSReplier_MaxInstanceCount, "max instance count", 1, UINT16_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSReplier_RecordCountA, "A record count", 0, 255 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSReplier_RecordCountAAAA, "AAAA record count", 0, 255 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckDoubleArgument( gMDNSReplier_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckDoubleArgument( gMDNSReplier_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSReplier_MaxDropCount, "drop count", 0, 255 );
-       require_noerr_quiet( err, exit );
-       
-       if( gMDNSReplier_Foreground )
-       {
-               LogControl( "MDNSReplier:output=file;stdout,MDNSReplier:flags=time;prefix" );
-       }
-       
-       context = (MDNSReplierContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->maxInstanceCount       = (unsigned int) gMDNSReplier_MaxInstanceCount;
-       context->recordCountA           = (unsigned int) gMDNSReplier_RecordCountA;
-       context->recordCountAAAA        = (unsigned int) gMDNSReplier_RecordCountAAAA;
-       context->maxDropCount           = (unsigned int) gMDNSReplier_MaxDropCount;
-       context->ucastDropRate          = gMDNSReplier_UnicastDropRate;
-       context->mcastDropRate          = gMDNSReplier_MulticastDropRate;
-       context->noAdditionals          = gMDNSReplier_NoAdditionals ? true : false;
-       context->useIPv4                        = ( gMDNSReplier_UseIPv4 || !gMDNSReplier_UseIPv6 ) ? true : false;
-       context->useIPv6                        = ( gMDNSReplier_UseIPv6 || !gMDNSReplier_UseIPv4 ) ? true : false;
-       context->bitmapCount            = ( context->maxInstanceCount + 63 ) / 64;
-       
-#if( TARGET_OS_DARWIN )
-       if( gMDNSReplier_FollowPID )
-       {
-               err = StringToPID( gMDNSReplier_FollowPID, &context->followPID );
-               if( err || ( context->followPID < 0 ) )
-               {
-                       FPrintF( stderr, "error: Invalid follow PID: %s\n", gMDNSReplier_FollowPID );
-                       goto exit;
-               }
-               
-               err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
-                       _MDNSReplierFollowedProcessHandler, NULL, context, &context->processMonitor );
-               require_noerr( err, exit );
-               dispatch_resume( context->processMonitor );
-       }
-       else
-       {
-               context->followPID = -1;
-       }
-#endif
-       
-       if( context->maxDropCount > 0 )
-       {
-               context->dropCounters = (uint8_t *) calloc( context->maxInstanceCount, sizeof( *context->dropCounters ) );
-               require_action( context->dropCounters, exit, err = kNoMemoryErr );
-       }
-       
-       context->bitmaps = (uint64_t *) calloc( context->bitmapCount, sizeof( *context->bitmaps ) );
-       require_action( context->bitmaps, exit, err = kNoMemoryErr );
-       
-       // Create the base hostname label.
-       
-       len = strlen( gMDNSReplier_Hostname );
-       if( context->maxInstanceCount > 1 )
-       {
-               unsigned int            maxInstanceCount, digitCount;
-               
-               // When there's more than one instance, extra bytes are needed to append " (<instance index>)" or
-               // "-<instance index>" to the base hostname.
-               
-               maxInstanceCount = context->maxInstanceCount;
-               for( digitCount = 0; maxInstanceCount > 0; ++digitCount ) maxInstanceCount /= 10;
-               len += ( 3 + digitCount );
-       }
-       
-       if( len <= kDomainLabelLengthMax )
-       {
-               uint8_t *               dst = &name[ 1 ];
-               uint8_t *               lim = &name[ countof( name ) ];
-               
-               SNPrintF_Add( (char **) &dst, (char *) lim, "%s", gMDNSReplier_Hostname );
-               name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
-               
-               err = DomainNameDupLower( name, &context->hostname, NULL );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               FPrintF( stderr, "error: Base name \"%s\" is too long for max instance count of %u.\n",
-                       gMDNSReplier_Hostname, context->maxInstanceCount );
-               goto exit;
-       }
-       
-       // Create the service label.
-       
-       len = strlen( gMDNSReplier_ServiceTypeTag ) + 3;        // We need three extra bytes for the service type prefix "_t-".
-       if( len <= kDomainLabelLengthMax )
-       {
-               uint8_t *               dst = &name[ 1 ];
-               uint8_t *               lim = &name[ countof( name ) ];
-               
-               SNPrintF_Add( (char **) &dst, (char *) lim, "_t-%s", gMDNSReplier_ServiceTypeTag );
-               name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
-               
-               err = DomainNameDupLower( name, &context->serviceLabel, NULL );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               FPrintF( stderr, "error: Service type tag is too long.\n" );
-               goto exit;
-       }
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
-       require_noerr_quiet( err, exit );
-       
-       ifname = if_indextoname( context->ifIndex, ifnameBuf );
-       require_action( ifname, exit, err = kNameErr );
-       
-       // Set up IPv4 socket.
-       
-       if( context->useIPv4 )
-       {
-               err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV4 );
-               require_noerr( err, exit );
-       }
-       
-       // Set up IPv6 socket.
-       
-       if( context->useIPv6 )
-       {
-               err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV6 );
-               require_noerr( err, exit );
-       }
-       
-       // Create dispatch read sources for socket(s).
-       
-       if( IsValidSocket( sockV4 ) )
-       {
-               SocketContext *         sockCtx;
-               
-               err = SocketContextCreate( sockV4, context, &sockCtx );
-               require_noerr( err, exit );
-               sockV4 = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
-                       &context->readSourceV4 );
-               if( err ) ForgetSocketContext( &sockCtx );
-               require_noerr( err, exit );
-               
-               dispatch_resume( context->readSourceV4 );
-       }
-       
-       if( IsValidSocket( sockV6 ) )
-       {
-               SocketContext *         sockCtx;
-               
-               err = SocketContextCreate( sockV6, context, &sockCtx );
-               require_noerr( err, exit );
-               sockV6 = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
-                       &context->readSourceV6 );
-               if( err ) ForgetSocketContext( &sockCtx );
-               require_noerr( err, exit );
-               
-               dispatch_resume( context->readSourceV6 );
-       }
-       
-       dispatch_main();
-       
-exit:
-       ForgetSocket( &sockV4 );
-       ForgetSocket( &sockV6 );
-       exit( 1 );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-//     _MDNSReplierFollowedProcessHandler
-//===========================================================================================================================
-
-static void    _MDNSReplierFollowedProcessHandler( void *inContext )
-{
-       MDNSReplierContext * const              context = (MDNSReplierContext *) inContext;
-       
-       if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT )
-       {
-               mr_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited.\n", (int64_t) context->followPID );
-               exit( 0 );
-       }
-}
-#endif
-
-//===========================================================================================================================
-//     _MDNSReplierReadHandler
-//===========================================================================================================================
-
-#define ShouldDrop( P )                ( ( (P) > 0.0 ) && ( ( (P) >= 1.0 ) || RandomlyTrue( P ) ) )
-
-static void    _MDNSReplierReadHandler( void *inContext )
-{
-       OSStatus                                                err;
-       SocketContext * const                   sockCtx = (SocketContext *) inContext;
-       MDNSReplierContext * const              context = (MDNSReplierContext *) sockCtx->userContext;
-       size_t                                                  msgLen;
-       sockaddr_ip                                             sender;
-       const DNSHeader *                               hdr;
-       unsigned int                                    flags, questionCount, i, j;
-       const uint8_t *                                 ptr;
-       int                                                             drop, isMetaQuery;
-       
-       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &sender, sizeof( sender ),
-               NULL, NULL, NULL, NULL );
-       require_noerr( err, exit );
-       
-       if( msgLen < kDNSHeaderLength )
-       {
-               mr_ulog( kLogLevelInfo, "Message is too small (%zu < %d).\n", msgLen, kDNSHeaderLength );
-               goto exit;
-       }
-       
-       // Perform header field checks.
-       // The message ID and most flag bits are silently ignored (see <https://tools.ietf.org/html/rfc6762#section-18>).
-       
-       hdr = (DNSHeader *) context->msgBuf;
-       flags = DNSHeaderGetFlags( hdr );
-       require_quiet( ( flags & kDNSHeaderFlag_Response ) == 0, exit );                // Reject responses.
-       require_quiet( DNSFlagsGetOpCode( flags ) == kDNSOpCode_Query, exit );  // Reject opcodes other than standard query.
-       require_quiet( DNSFlagsGetRCode( flags )  == kDNSRCode_NoError, exit ); // Reject non-zero rcodes.
-       
-       drop = ( !context->maxDropCount && ShouldDrop( context->mcastDropRate ) ) ? true : false;
-       
-       mr_ulog( kLogLevelInfo, "Received %zu byte message from %##a%?s:\n\n%#1{du:dnsmsg}",
-               msgLen, &sender, drop, " (dropping)", context->msgBuf, msgLen );
-       
-       // Based on the QNAMEs in the query message, determine from which sets of records we may possibly need answers.
-       
-       questionCount = DNSHeaderGetQuestionCount( hdr );
-       require_quiet( questionCount > 0, exit );
-       
-       memset( context->bitmaps, 0, context->bitmapCount * sizeof_element( context->bitmaps ) );
-       
-       isMetaQuery = false;
-       ptr = (const uint8_t *) &hdr[ 1 ];
-       for( i = 0; i < questionCount; ++i )
-       {
-               unsigned int            count, index;
-               uint16_t                        qtype, qclass;
-               uint8_t                         qname[ kDomainNameLengthMax ];
-               
-               err = DNSMessageExtractQuestion( context->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
-               require_noerr_quiet( err, exit );
-               
-               if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
-               
-               if( _MDNSReplierHostnameMatch( context, qname, &index ) ||
-                       _MDNSReplierServiceInstanceNameMatch( context, qname, &index, NULL, NULL ) )
-               {
-                       if( ( index >= 1 ) && ( index <= context->maxInstanceCount ) )
-                       {
-                               context->bitmaps[ ( index - 1 ) / 64 ] |= ( UINT64_C( 1 ) << ( ( index - 1 ) % 64 ) );
-                       }
-               }
-               else if( _MDNSReplierServiceTypeMatch( context, qname, NULL, &count ) )
-               {
-                       if( ( count >= 1 ) && ( count <= context->maxInstanceCount ) )
-                       {
-                               for( j = 0; j < (unsigned int) context->bitmapCount; ++j )
-                               {
-                                       if( count < 64 )
-                                       {
-                                               context->bitmaps[ j ] |= ( ( UINT64_C( 1 ) << count ) - 1 );
-                                               break;
-                                       }
-                                       else
-                                       {
-                                               context->bitmaps[ j ] = ~UINT64_C( 0 );
-                                               count -= 64;
-                                       }
-                               }
-                       }
-               }
-               else if( _MDNSReplierAboutRecordNameMatch( context, qname ) )
-               {
-                       isMetaQuery = true;
-               }
-       }
-       
-       // Attempt to answer the query message using selected record sets.
-       
-       if( isMetaQuery )
-       {
-               err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock, 0 );
-               check_noerr( err );
-       }
-       if( drop ) goto exit;
-       
-       for( i = 0; i < context->bitmapCount; ++i )
-       {
-               for( j = 0; ( context->bitmaps[ i ] != 0 ) && ( j < 64 ); ++j )
-               {
-                       const uint64_t          bitmask = UINT64_C( 1 ) << j;
-                       
-                       if( context->bitmaps[ i ] & bitmask )
-                       {
-                               context->bitmaps[ i ] &= ~bitmask;
-                               
-                               err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock,
-                                       ( i * 64 ) + j + 1 );
-                               check_noerr( err );
-                       }
-               }
-       }
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     _MDNSReplierAnswerQuery
-//===========================================================================================================================
-
-static OSStatus
-       _MDNSReplierAnswerQuery(
-               MDNSReplierContext *    inContext,
-               const uint8_t *                 inQueryPtr,
-               size_t                                  inQueryLen,
-               sockaddr_ip *                   inSender,
-               SocketRef                               inSock,
-               unsigned int                    inIndex )
-{
-       OSStatus                                err;
-       const DNSHeader *               hdr;
-       const uint8_t *                 ptr;
-       unsigned int                    questionCount, answerCount, i;
-       MRResourceRecord *              ucastAnswerList = NULL;
-       MRResourceRecord *              mcastAnswerList = NULL;
-       
-       require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
-       
-       // Get answers for questions.
-       
-       check( inQueryLen >= kDNSHeaderLength );
-       hdr = (const DNSHeader *) inQueryPtr;
-       questionCount = DNSHeaderGetQuestionCount( hdr );
-       
-       ptr = (const uint8_t *) &hdr[ 1 ];
-       for( i = 0; i < questionCount; ++i )
-       {
-               MRResourceRecord **             answerListPtr;
-               uint16_t                                qtype, qclass;
-               uint8_t                                 qname[ kDomainNameLengthMax ];
-               
-               err = DNSMessageExtractQuestion( inQueryPtr, inQueryLen, ptr, qname, &qtype, &qclass, &ptr );
-               require_noerr_quiet( err, exit );
-               
-               if( qclass & kQClassUnicastResponseBit )
-               {
-                       qclass &= ~kQClassUnicastResponseBit;
-                       answerListPtr = &ucastAnswerList;
-               }
-               else
-               {
-                       answerListPtr = &mcastAnswerList;
-               }
-               
-               err = _MDNSReplierAnswerListAdd( inContext, answerListPtr, inIndex, qname, qtype, qclass );
-               require_noerr( err, exit );
-       }
-       require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
-       
-       // Suppress known answers.
-       // Records in the Answer section of the query message are known answers, so remove them from the answer lists.
-       // See <https://tools.ietf.org/html/rfc6762#section-7.1>.
-       
-       answerCount = DNSHeaderGetAnswerCount( hdr );
-       for( i = 0; i < answerCount; ++i )
-       {
-               const uint8_t *         rdataPtr;
-               const uint8_t *         recordPtr;
-               uint16_t                        type, class;
-               uint8_t                         name[ kDomainNameLengthMax ];
-               uint8_t                         instance[ kDomainNameLengthMax ];
-               
-               recordPtr = ptr;
-               err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, ptr, NULL, &type, &class, NULL, NULL, NULL, &ptr );
-               require_noerr_quiet( err, exit );
-               
-               if( ( type != kDNSServiceType_PTR ) || ( class != kDNSServiceClass_IN ) ) continue;
-               
-               err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, recordPtr, name, NULL, NULL, NULL, &rdataPtr, NULL, NULL );
-               require_noerr( err, exit );
-               
-               err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, rdataPtr, instance, NULL );
-               require_noerr_quiet( err, exit );
-               
-               if( ucastAnswerList ) _MDNSReplierAnswerListRemovePTR( &ucastAnswerList, name, instance );
-               if( mcastAnswerList ) _MDNSReplierAnswerListRemovePTR( &mcastAnswerList, name, instance );
-       }
-       require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
-       
-       // Send or drop responses.
-       
-       if( ucastAnswerList )
-       {
-               err = _MDNSReplierSendOrDropResponse( inContext, ucastAnswerList, inSender, inSock, inIndex, true );
-               require_noerr( err, exit );
-       }
-       
-       if( mcastAnswerList )
-       {
-               err = _MDNSReplierSendOrDropResponse( inContext, mcastAnswerList, inSender, inSock, inIndex, false );
-               require_noerr( err, exit );
-       }
-       err = kNoErr;
-       
-exit:
-       _MRResourceRecordFreeList( ucastAnswerList );
-       _MRResourceRecordFreeList( mcastAnswerList );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierAnswerListAdd
-//===========================================================================================================================
-
-static OSStatus
-       _MDNSReplierAnswerListAdd(
-               MDNSReplierContext *    inContext,
-               MRResourceRecord **             inAnswerList,
-               unsigned int                    inIndex,
-               const uint8_t *                 inName,
-               unsigned int                    inType,
-               unsigned int                    inClass )
-{
-       OSStatus                                        err;
-       uint8_t *                                       recordName      = NULL;
-       uint8_t *                                       rdataPtr        = NULL;
-       size_t                                          rdataLen;
-       MRResourceRecord *                      answer;
-       MRResourceRecord **                     answerPtr;
-       const uint8_t * const           hostname        = inContext->hostname;
-       unsigned int                            i;
-       uint32_t                                        index;
-       unsigned int                            count, txtSize;
-       
-       require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
-       require_action_quiet( inClass == kDNSServiceClass_IN, exit, err = kNoErr );
-       
-       for( answerPtr = inAnswerList; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
-       {
-               if( ( answer->type == inType ) && DomainNameEqual( answer->name, inName ) )
-               {
-                       err = kNoErr;
-                       goto exit;
-               }
-       }
-       
-       // Index 0 is reserved for answering queries about the mdnsreplier, while all other index values up to the maximum
-       // instance count are for answering queries about service instances.
-       
-       if( inIndex == 0 )
-       {
-               if( _MDNSReplierAboutRecordNameMatch( inContext, inName ) )
-               {
-                       int             listHasTXT = false;
-                       
-                       if( inType == kDNSServiceType_ANY )
-                       {
-                               for( answer = *inAnswerList; answer; answer = answer->next )
-                               {
-                                       if( ( answer->type == kDNSServiceType_TXT ) && DomainNameEqual( answer->name, inName ) )
-                                       {
-                                               listHasTXT = true;
-                                               break;
-                                       }
-                               }
-                       }
-                       
-                       if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
-                       {
-                               err = DomainNameDupLower( inName, &recordName, NULL );
-                               require_noerr( err, exit );
-                               
-                               err = CreateTXTRecordDataFromString( "ready=yes", ',', &rdataPtr, &rdataLen );
-                               require_noerr( err, exit );
-                               
-                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
-                                       (uint16_t) rdataLen, rdataPtr, &answer );
-                               require_noerr( err, exit );
-                               recordName      = NULL;
-                               rdataPtr        = NULL;
-                               
-                               *answerPtr = answer;
-                       }
-                       else if( inType == kDNSServiceType_NSEC )
-                       {
-                               err = DomainNameDupLower( inName, &recordName, NULL );
-                               require_noerr( err, exit );
-                               
-                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_TXT );
-                               require_noerr( err, exit );
-                               
-                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
-                                       (uint16_t) rdataLen, rdataPtr, &answer );
-                               require_noerr( err, exit );
-                               recordName      = NULL;
-                               rdataPtr        = NULL;
-                               
-                               *answerPtr = answer;
-                       }
-               }
-       }
-       else if( _MDNSReplierHostnameMatch( inContext, inName, &index ) && ( index == inIndex ) )
-       {
-               int             listHasA        = false;
-               int             listHasAAAA     = false;
-               
-               if( inType == kDNSServiceType_ANY )
-               {
-                       for( answer = *inAnswerList; answer; answer = answer->next )
-                       {
-                               if( answer->type == kDNSServiceType_A )
-                               {
-                                       if( !listHasA && DomainNameEqual( answer->name, inName ) ) listHasA = true;
-                               }
-                               else if( answer->type == kDNSServiceType_AAAA )
-                               {
-                                       if( !listHasAAAA && DomainNameEqual( answer->name, inName ) ) listHasAAAA = true;
-                               }
-                               if( listHasA && listHasAAAA ) break;
-                       }
-               }
-               
-               if( ( inType == kDNSServiceType_A ) || ( ( inType == kDNSServiceType_ANY ) && !listHasA ) )
-               {
-                       for( i = 1; i <= inContext->recordCountA; ++i )
-                       {
-                               err = DomainNameDupLower( inName, &recordName, NULL );
-                               require_noerr( err, exit );
-                               
-                               rdataLen = 4;
-                               rdataPtr = (uint8_t *) malloc( rdataLen );
-                               require_action( rdataPtr, exit, err = kNoMemoryErr );
-                               
-                               rdataPtr[ 0 ] = 0;
-                               WriteBig16( &rdataPtr[ 1 ], inIndex );
-                               rdataPtr[ 3 ] = (uint8_t) i;
-                               
-                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_A, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
-                                       (uint16_t) rdataLen, rdataPtr, &answer );
-                               require_noerr( err, exit );
-                               recordName      = NULL;
-                               rdataPtr        = NULL;
-                               
-                               *answerPtr = answer;
-                                answerPtr = &answer->next;
-                       }
-               }
-               
-               if( ( inType == kDNSServiceType_AAAA ) || ( ( inType == kDNSServiceType_ANY ) && !listHasAAAA ) )
-               {
-                       for( i = 1; i <= inContext->recordCountAAAA; ++i )
-                       {
-                               err = DomainNameDupLower( inName, &recordName, NULL );
-                               require_noerr( err, exit );
-                               
-                               rdataLen = 16;
-                               rdataPtr = (uint8_t *) memdup( kMDNSReplierBaseAddrV6, rdataLen );
-                               require_action( rdataPtr, exit, err = kNoMemoryErr );
-                               
-                               WriteBig16( &rdataPtr[ 12 ], inIndex );
-                               rdataPtr[ 15 ] = (uint8_t) i;
-                               
-                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_AAAA, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
-                                       (uint16_t) rdataLen, rdataPtr, &answer );
-                               require_noerr( err, exit );
-                               recordName      = NULL;
-                               rdataPtr        = NULL;
-                               
-                               *answerPtr = answer;
-                                answerPtr = &answer->next;
-                       }
-               }
-               else if( inType == kDNSServiceType_NSEC )
-               {
-                       err = DomainNameDupLower( inName, &recordName, NULL );
-                       require_noerr( err, exit );
-                       
-                       if( ( inContext->recordCountA > 0 ) && ( inContext->recordCountAAAA > 0 ) )
-                       {
-                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_A, kDNSServiceType_AAAA );
-                               require_noerr( err, exit );
-                       }
-                       else if( inContext->recordCountA > 0 )
-                       {
-                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_A );
-                               require_noerr( err, exit );
-                       }
-                       else if( inContext->recordCountAAAA > 0 )
-                       {
-                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_AAAA );
-                               require_noerr( err, exit );
-                       }
-                       else
-                       {
-                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 0 );
-                               require_noerr( err, exit );
-                       }
-                       
-                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
-                               (uint16_t) rdataLen, rdataPtr, &answer );
-                       require_noerr( err, exit );
-                       recordName      = NULL;
-                       rdataPtr        = NULL;
-                       
-                       *answerPtr = answer;
-               }
-       }
-       else if( _MDNSReplierServiceTypeMatch( inContext, inName, NULL, &count ) && ( count >= inIndex ) )
-       {
-               int             listHasPTR = false;
-               
-               if( inType == kDNSServiceType_ANY )
-               {
-                       for( answer = *inAnswerList; answer; answer = answer->next )
-                       {
-                               if( ( answer->type == kDNSServiceType_PTR ) && DomainNameEqual( answer->name, inName ) )
-                               {
-                                       listHasPTR = true;
-                                       break;
-                               }
-                       }
-               }
-               
-               if( ( inType == kDNSServiceType_PTR ) || ( ( inType == kDNSServiceType_ANY ) && !listHasPTR ) )
-               {
-                       size_t                          recordNameLen;
-                       uint8_t *                       ptr;
-                       uint8_t *                       lim;
-                       
-                       err = DomainNameDupLower( inName, &recordName, &recordNameLen );
-                       require_noerr( err, exit );
-                       
-                       rdataLen = 1 + hostname[ 0 ] + 10 + recordNameLen;
-                       rdataPtr = (uint8_t *) malloc( rdataLen );
-                       require_action( rdataPtr, exit, err = kNoMemoryErr );
-                       
-                       lim = &rdataPtr[ rdataLen ];
-                       
-                       ptr = &rdataPtr[ 1 ];
-                       memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
-                       ptr += hostname[ 0 ];
-                       if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, " (%u)", inIndex );
-                       rdataPtr[ 0 ] = (uint8_t)( ptr - &rdataPtr[ 1 ] );
-                       
-                       check( (size_t)( lim - ptr ) >= recordNameLen );
-                       memcpy( ptr, recordName, recordNameLen );
-                       ptr += recordNameLen;
-                       
-                       rdataLen = (size_t)( ptr - rdataPtr );
-                       
-                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_PTR, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
-                               (uint16_t) rdataLen, rdataPtr, &answer );
-                       require_noerr( err, exit );
-                       recordName      = NULL;
-                       rdataPtr        = NULL;
-                       
-                       *answerPtr = answer;
-               }
-       }
-       else if( _MDNSReplierServiceInstanceNameMatch( inContext, inName, &index, &txtSize, &count ) &&
-               ( index == inIndex ) && ( count >= inIndex ) )
-       {
-               int             listHasSRV = false;
-               int             listHasTXT = false;
-               
-               if( inType == kDNSServiceType_ANY )
-               {
-                       for( answer = *inAnswerList; answer; answer = answer->next )
-                       {
-                               if( answer->type == kDNSServiceType_SRV )
-                               {
-                                       if( !listHasSRV && DomainNameEqual( answer->name, inName ) ) listHasSRV = true;
-                               }
-                               else if( answer->type == kDNSServiceType_TXT )
-                               {
-                                       if( !listHasTXT && DomainNameEqual( answer->name, inName ) ) listHasTXT = true;
-                               }
-                               if( listHasSRV && listHasTXT ) break;
-                       }
-               }
-               
-               if( ( inType == kDNSServiceType_SRV ) || ( ( inType == kDNSServiceType_ANY ) && !listHasSRV ) )
-               {
-                       SRVRecordDataFixedFields *              fields;
-                       uint8_t *                                               ptr;
-                       uint8_t *                                               lim;
-                       uint8_t *                                               targetPtr;
-                       
-                       err = DomainNameDupLower( inName, &recordName, NULL );
-                       require_noerr( err, exit );
-                       
-                       rdataLen = sizeof( SRVRecordDataFixedFields ) + 1 + hostname[ 0 ] + 10 + kLocalNameLen;
-                       rdataPtr = (uint8_t *) malloc( rdataLen );
-                       require_action( rdataPtr, exit, err = kNoMemoryErr );
-                       
-                       lim = &rdataPtr[ rdataLen ];
-                       
-                       fields = (SRVRecordDataFixedFields *) rdataPtr;
-                       SRVRecordDataFixedFieldsSet( fields, 0, 0, (uint16_t)( kMDNSReplierPortBase + txtSize ) );
-                       
-                       targetPtr = (uint8_t *) &fields[ 1 ];
-                       
-                       ptr = &targetPtr[ 1 ];
-                       memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
-                       ptr += hostname[ 0 ];
-                       if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, "-%u", inIndex );
-                       targetPtr[ 0 ] = (uint8_t)( ptr - &targetPtr[ 1 ] );
-                       
-                       check( (size_t)( lim - ptr ) >= kLocalNameLen );
-                       memcpy( ptr, kLocalName, kLocalNameLen );
-                       ptr += kLocalNameLen;
-                       
-                       rdataLen = (size_t)( ptr - rdataPtr );
-                       
-                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_SRV, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
-                               (uint16_t) rdataLen, rdataPtr, &answer );
-                       require_noerr( err, exit );
-                       recordName      = NULL;
-                       rdataPtr        = NULL;
-                       
-                       *answerPtr = answer;
-                        answerPtr = &answer->next;
-               }
-               
-               if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
-               {
-                       err = DomainNameDupLower( inName, &recordName, NULL );
-                       require_noerr( err, exit );
-                       
-                       rdataLen = txtSize;
-                       err = _MDNSReplierCreateTXTRecord( inName, rdataLen, &rdataPtr );
-                       require_noerr( err, exit );
-                       
-                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
-                               (uint16_t) rdataLen, rdataPtr, &answer );
-                       require_noerr( err, exit );
-                       recordName      = NULL;
-                       rdataPtr        = NULL;
-                       
-                       *answerPtr = answer;
-               }
-               else if( inType == kDNSServiceType_NSEC )
-               {
-                       err = DomainNameDupLower( inName, &recordName, NULL );
-                       require_noerr( err, exit );
-                       
-                       err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_TXT, kDNSServiceType_SRV );
-                       require_noerr( err, exit );
-                       
-                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
-                               (uint16_t) rdataLen, rdataPtr, &answer );
-                       require_noerr( err, exit );
-                       recordName      = NULL;
-                       rdataPtr        = NULL;
-                       
-                       *answerPtr = answer;
-               }
-       }
-       err = kNoErr;
-       
-exit:
-       FreeNullSafe( recordName );
-       FreeNullSafe( rdataPtr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierAnswerListRemovePTR
-//===========================================================================================================================
-
-static void
-       _MDNSReplierAnswerListRemovePTR(
-               MRResourceRecord **     inAnswerListPtr,
-               const uint8_t *         inName,
-               const uint8_t *         inRData )
-{
-       MRResourceRecord *              answer;
-       MRResourceRecord **             answerPtr;
-       
-       for( answerPtr = inAnswerListPtr; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
-       {
-               if( ( answer->type == kDNSServiceType_PTR ) && ( answer->class == kDNSServiceClass_IN ) &&
-                       DomainNameEqual( answer->name, inName ) && DomainNameEqual( answer->rdata, inRData ) ) break;
-       }
-       if( answer )
-       {
-               *answerPtr = answer->next;
-               _MRResourceRecordFree( answer );
-       }
-}
-
-//===========================================================================================================================
-//     _MDNSReplierSendOrDropResponse
-//===========================================================================================================================
-
-static OSStatus
-       _MDNSReplierSendOrDropResponse(
-               MDNSReplierContext *    inContext,
-               MRResourceRecord *              inAnswerList,
-               sockaddr_ip *                   inQuerier,
-               SocketRef                               inSock,
-               unsigned int                    inIndex,
-               Boolean                                 inUnicast )
-{
-       OSStatus                                        err;
-       uint8_t *                                       responsePtr     = NULL;
-       size_t                                          responseLen;
-       const struct sockaddr *         destAddr;
-       ssize_t                                         n;
-       const double                            dropRate        = inUnicast ? inContext->ucastDropRate : inContext->mcastDropRate;
-       int                                                     drop;
-       
-       check( inIndex <= inContext->maxInstanceCount );
-       
-       // If maxDropCount > 0, then the drop rates apply only to the first maxDropCount responses. Otherwise, all messages are
-       // subject to their respective drop rate. Also, responses to queries about mDNS replier itself (indicated by index 0),
-       // as opposed to those for service instance records, are never dropped.
-       
-       drop = false;
-       if( inIndex > 0 )
-       {
-               if( inContext->maxDropCount > 0 )
-               {
-                       uint8_t * const         dropCount = &inContext->dropCounters[ inIndex - 1 ];
-                       
-                       if( *dropCount < inContext->maxDropCount )
-                       {
-                               if( ShouldDrop( dropRate ) ) drop = true;
-                               *dropCount += 1;
-                       }
-               }
-               else if( ShouldDrop( dropRate ) )
-               {
-                       drop = true;
-               }
-       }
-       
-       err = _MDNSReplierCreateResponse( inContext, inAnswerList, inIndex, &responsePtr, &responseLen );
-       require_noerr( err, exit );
-       
-       if( inUnicast )
-       {
-               destAddr = &inQuerier->sa;
-       }
-       else
-       {
-               destAddr = ( inQuerier->sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
-       }
-       
-       mr_ulog( kLogLevelInfo, "%s %zu byte response to %##a:\n\n%#1{du:dnsmsg}",
-               drop ? "Dropping" : "Sending", responseLen, destAddr, responsePtr, responseLen );
-       
-       if( !drop )
-       {
-               n = sendto( inSock, (char *) responsePtr, responseLen, 0, destAddr, SockAddrGetSize( destAddr ) );
-               err = map_socket_value_errno( inSock, n == (ssize_t) responseLen, n );
-               require_noerr( err, exit );
-       }
-       
-exit:
-       FreeNullSafe( responsePtr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierCreateResponse
-//===========================================================================================================================
-
-static OSStatus
-       _MDNSReplierCreateResponse(
-               MDNSReplierContext *    inContext,
-               MRResourceRecord *              inAnswerList,
-               unsigned int                    inIndex,
-               uint8_t **                              outResponsePtr,
-               size_t *                                outResponseLen )
-{
-       OSStatus                                err;
-       DataBuffer                              responseDB;
-       DNSHeader                               hdr;
-       MRResourceRecord *              answer;
-       uint8_t *                               responsePtr;
-       size_t                                  responseLen, len;
-       unsigned int                    answerCount, recordCount;
-       MRNameOffsetItem *              nameOffsetList = NULL;
-       
-       DataBuffer_Init( &responseDB, NULL, 0, SIZE_MAX );
-       
-       // The current answers in the answer list will make up the response's Answer Record Section.
-       
-       answerCount = 0;
-       for( answer = inAnswerList; answer; answer = answer->next ) { ++answerCount; }
-       
-       // Unless configured not to, add any additional answers to the answer list for the Additional Record Section.
-       
-       if( !inContext->noAdditionals )
-       {
-               for( answer = inAnswerList; answer; answer = answer->next )
-               {
-                       switch( answer->type )
-                       {
-                               case kDNSServiceType_PTR:
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_SRV,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_TXT,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       break;
-                               
-                               case kDNSServiceType_SRV:
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_A,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_AAAA,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       break;
-                               
-                               case kDNSServiceType_TXT:
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       break;
-                               
-                               case kDNSServiceType_A:
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_AAAA,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       break;
-                               
-                               case kDNSServiceType_AAAA:
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_A,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       
-                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
-                                               answer->class );
-                                       require_noerr( err, exit );
-                                       break;
-                               
-                               default:
-                                       break;
-                       }
-               }
-       }
-       
-       // Append a provisional header to the response message.
-       
-       memset( &hdr, 0, sizeof( hdr ) );
-       DNSHeaderSetFlags( &hdr, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
-       
-       err = DataBuffer_Append( &responseDB, &hdr, sizeof( hdr ) );
-       require_noerr( err, exit );
-       
-       // Append answers to response message.
-       
-       responseLen = DataBuffer_GetLen( &responseDB );
-       recordCount = 0;
-       for( answer = inAnswerList; answer; answer = answer->next )
-       {
-               DNSRecordFixedFields            fields;
-               unsigned int                            class;
-               
-               // Append record NAME.
-               
-               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->name, &nameOffsetList );
-               require_noerr( err, exit );
-               
-               // Append record TYPE, CLASS, TTL, and provisional RDLENGTH.
-               
-               class = answer->class;
-               if( ( answer->type == kDNSServiceType_SRV ) || ( answer->type == kDNSServiceType_TXT )  ||
-                       ( answer->type == kDNSServiceType_A )   || ( answer->type == kDNSServiceType_AAAA ) ||
-                       ( answer->type == kDNSServiceType_NSEC ) )
-               {
-                       class |= kRRClassCacheFlushBit;
-               }
-               
-               DNSRecordFixedFieldsSet( &fields, answer->type, (uint16_t) class, answer->ttl, (uint16_t) answer->rdlength );
-               err = DataBuffer_Append( &responseDB, &fields, sizeof( fields ) );
-               require_noerr( err, exit );
-               
-               // Append record RDATA.
-               // The RDATA of PTR, SRV, and NSEC records contain domain names, which are subject to name compression.
-               
-               if( ( answer->type == kDNSServiceType_PTR ) || ( answer->type == kDNSServiceType_SRV ) ||
-                       ( answer->type == kDNSServiceType_NSEC ) )
-               {
-                       size_t                          rdlength;
-                       uint8_t *                       rdLengthPtr;
-                       const size_t            rdLengthOffset  = DataBuffer_GetLen( &responseDB ) - 2;
-                       const size_t            rdataOffset             = DataBuffer_GetLen( &responseDB );
-                       
-                       if( answer->type == kDNSServiceType_PTR )
-                       {
-                               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
-                               require_noerr( err, exit );
-                       }
-                       else if( answer->type == kDNSServiceType_SRV )
-                       {
-                               require_fatal( answer->target == &answer->rdata[ 6 ], "Bad SRV record target pointer." );
-                               
-                               err = DataBuffer_Append( &responseDB, answer->rdata, (size_t)( answer->target - answer->rdata ) );
-                               require_noerr( err, exit );
-                               
-                               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->target, &nameOffsetList );
-                               require_noerr( err, exit );
-                       }
-                       else
-                       {
-                               const size_t            nameLen = DomainNameLength( answer->rdata );
-                               
-                               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
-                               require_noerr( err, exit );
-                               
-                               require_fatal( answer->rdlength > nameLen, "Bad NSEC record data length." );
-                               
-                               err = DataBuffer_Append( &responseDB, &answer->rdata[ nameLen ], answer->rdlength - nameLen );
-                               require_noerr( err, exit );
-                       }
-                       
-                       // Set the actual RDLENGTH, which may be less than the original due to name compression.
-                       
-                       rdlength = DataBuffer_GetLen( &responseDB ) - rdataOffset;
-                       check( rdlength <= UINT16_MAX );
-                       
-                       rdLengthPtr = DataBuffer_GetPtr( &responseDB ) + rdLengthOffset;
-                       WriteBig16( rdLengthPtr, rdlength );
-               }
-               else
-               {
-                       err = DataBuffer_Append( &responseDB, answer->rdata, answer->rdlength );
-                       require_noerr( err, exit );
-               }
-               
-               if( DataBuffer_GetLen( &responseDB ) > kMDNSMessageSizeMax ) break;
-               responseLen = DataBuffer_GetLen( &responseDB );
-               ++recordCount;
-       }
-       
-       // Set the response header's Answer and Additional record counts.
-       // Note: recordCount may be less than answerCount if including all answerCount records would cause the size of the
-       // response message to exceed the maximum mDNS message size.
-       
-       if( recordCount <= answerCount )
-       {
-               DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount );
-       }
-       else
-       {
-               DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), answerCount );
-               DNSHeaderSetAdditionalCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount - answerCount );
-       }
-       
-       err = DataBuffer_Detach( &responseDB, &responsePtr, &len );
-       require_noerr( err, exit );
-       
-       if( outResponsePtr ) *outResponsePtr = responsePtr;
-       if( outResponseLen ) *outResponseLen = responseLen;
-       
-exit:
-       _MRNameOffsetItemFreeList( nameOffsetList );
-       DataBuffer_Free( &responseDB );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierAppendNameToResponse
-//===========================================================================================================================
-
-static OSStatus
-       _MDNSReplierAppendNameToResponse(
-               DataBuffer *            inResponse,
-               const uint8_t *         inName,
-               MRNameOffsetItem **     inNameOffsetListPtr )
-{
-       OSStatus                                err;
-       const uint8_t *                 subname;
-       const uint8_t *                 limit;
-       size_t                                  nameOffset;
-       MRNameOffsetItem *              item;
-       uint8_t                                 compressionPtr[ 2 ];
-       
-       nameOffset = DataBuffer_GetLen( inResponse );
-       
-       // Find the name's longest subname (more accurately, its longest sub-FQDN) in the name compression list.
-       
-       for( subname = inName; subname[ 0 ] != 0; subname += ( 1 + subname[ 0 ] ) )
-       {
-               for( item = *inNameOffsetListPtr; item; item = item->next )
-               {
-                       if( DomainNameEqual( item->name, subname ) ) break;
-               }
-               
-               // If an item was found for this subname, then append a name compression pointer and we're done. Otherwise, append
-               // the subname's first label.
-               
-               if( item )
-               {
-                       WriteDNSCompressionPtr( compressionPtr, item->offset );
-                       
-                       err = DataBuffer_Append( inResponse, compressionPtr, sizeof( compressionPtr ) );
-                       require_noerr( err, exit );
-                       break;
-               }
-               else
-               {
-                       err = DataBuffer_Append( inResponse, subname, 1 + subname[ 0 ] );
-                       require_noerr( err, exit );
-               }
-       }
-               
-       // If we made it to the root label, then no subname was able to be compressed. All of the name's labels up to the root
-       // label were appended to the response message, so a root label is needed to terminate the complete name.
-       
-       if( subname[ 0 ] == 0 )
-       {
-               err = DataBuffer_Append( inResponse, "", 1 );
-               require_noerr( err, exit );
-       }
-       
-       // Add subnames that weren't able to be compressed and their offsets to the name compression list.
-       
-       limit = subname;
-       for( subname = inName; subname < limit; subname += ( 1 + subname[ 0 ] ) )
-       {
-               const size_t            subnameOffset = nameOffset + (size_t)( subname - inName );
-               
-               if( subnameOffset > kDNSCompressionOffsetMax ) break;
-               
-               err = _MRNameOffsetItemCreate( subname, (uint16_t) subnameOffset, &item );
-               require_noerr( err, exit );
-               
-               item->next = *inNameOffsetListPtr;
-               *inNameOffsetListPtr = item;
-       }
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierServiceTypeMatch
-//===========================================================================================================================
-
-static Boolean
-       _MDNSReplierServiceTypeMatch(
-               const MDNSReplierContext *      inContext,
-               const uint8_t *                         inName,
-               unsigned int *                          outTXTSize,
-               unsigned int *                          outCount )
-{
-       OSStatus                                        err;
-       const char *                            ptr;
-       const char *                            end;
-       uint32_t                                        txtSize, count;
-       const uint8_t * const           serviceLabel    = inContext->serviceLabel;
-       int                                                     nameMatches             = false;
-       
-       require_quiet( inName[ 0 ] >= serviceLabel[ 0 ], exit );
-       if( memicmp( &inName[ 1 ], &serviceLabel[ 1 ], serviceLabel[ 0 ] ) != 0 ) goto exit;
-       
-       ptr = (const char *) &inName[ 1 + serviceLabel[ 0 ] ];
-       end = (const char *) &inName[ 1 + inName[ 0 ] ];
-       
-       require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
-       ++ptr;
-       
-       err = DecimalTextToUInt32( ptr, end, &txtSize, &ptr );
-       require_noerr_quiet( err, exit );
-       require_quiet( txtSize <= UINT16_MAX, exit );
-       
-       require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
-       ++ptr;
-       
-       err = DecimalTextToUInt32( ptr, end, &count, &ptr );
-       require_noerr_quiet( err, exit );
-       require_quiet( count <= UINT16_MAX, exit );
-       require_quiet( ptr == end, exit );
-       
-       if( !DomainNameEqual( (const uint8_t *) ptr, (const uint8_t *) "\x04" "_tcp" "\x05" "local" ) ) goto exit;
-       nameMatches = true;
-       
-       if( outTXTSize )        *outTXTSize     = txtSize;
-       if( outCount )          *outCount       = count;
-       
-exit:
-       return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierServiceInstanceNameMatch
-//===========================================================================================================================
-
-static Boolean
-       _MDNSReplierServiceInstanceNameMatch(
-               const MDNSReplierContext *      inContext,
-               const uint8_t *                         inName,
-               unsigned int *                          outIndex,
-               unsigned int *                          outTXTSize,
-               unsigned int *                          outCount )
-{
-       OSStatus                                        err;
-       const uint8_t *                         ptr;
-       const uint8_t *                         end;
-       uint32_t                                        index;
-       unsigned int                            txtSize, count;
-       const uint8_t * const           hostname        = inContext->hostname;
-       int                                                     nameMatches     = false;
-       
-       require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
-       if( memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
-       
-       ptr = &inName[ 1 + hostname[ 0 ] ];
-       end = &inName[ 1 + inName[ 0 ] ];
-       if( ptr < end )
-       {
-               require_quiet( ( end - ptr ) >= 2, exit );
-               require_quiet( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ), exit );
-               ptr += 2;
-               
-        err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
-               require_noerr_quiet( err, exit );
-               require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
-               
-               require_quiet( ( ( end - ptr ) == 1 ) && ( *ptr == ')' ), exit );
-               ++ptr;
-       }
-       else
-       {
-               index = 1;
-       }
-       
-       if( !_MDNSReplierServiceTypeMatch( inContext, ptr, &txtSize, &count ) ) goto exit;
-       nameMatches = true;
-       
-       if( outIndex )          *outIndex       = index;
-       if( outTXTSize )        *outTXTSize     = txtSize;
-       if( outCount )          *outCount       = count;
-       
-exit:
-       return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierAboutRecordNameMatch
-//===========================================================================================================================
-
-static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName )
-{
-       const uint8_t *                         subname;
-       const uint8_t * const           hostname        = inContext->hostname;
-       int                                                     nameMatches     = false;
-       
-       if( strnicmpx( &inName[ 1 ], inName[ 0 ], "about" ) != 0 ) goto exit;
-       subname = NextLabel( inName );
-       
-       if( !MemIEqual( &subname[ 1 ], subname[ 0 ], &hostname[ 1 ], hostname[ 0 ] ) ) goto exit;
-       subname = NextLabel( subname );
-       
-       if( !DomainNameEqual( subname, kLocalName ) ) goto exit;
-       nameMatches = true;
-       
-exit:
-       return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierHostnameMatch
-//===========================================================================================================================
-
-static Boolean
-       _MDNSReplierHostnameMatch(
-               const MDNSReplierContext *      inContext,
-               const uint8_t *                         inName,
-               unsigned int *                          outIndex )
-{
-       OSStatus                                        err;
-       const uint8_t *                         ptr;
-       const uint8_t *                         end;
-       uint32_t                                        index;
-       const uint8_t * const           hostname        = inContext->hostname;
-       int                                                     nameMatches     = false;
-       
-       require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
-       if( memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
-       
-       ptr = &inName[ 1 + hostname[ 0 ] ];
-       end = &inName[ 1 + inName[ 0 ] ];
-       if( ptr < end )
-       {
-               require_quiet( *ptr == '-', exit );
-               ++ptr;
-               
-               err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
-               require_noerr_quiet( err, exit );
-               require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
-               require_quiet( ptr == end, exit );
-       }
-       else
-       {
-               index = 1;
-       }
-       
-       if( !DomainNameEqual( ptr, kLocalName ) ) goto exit;
-       nameMatches = true;
-       
-       if( outIndex ) *outIndex = index;
-       
-exit:
-       return( nameMatches ? true : false );
-}
-
-//===========================================================================================================================
-//     _MDNSReplierCreateTXTRecord
-//===========================================================================================================================
-
-static OSStatus        _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT )
-{
-       OSStatus                err;
-       uint8_t *               txt;
-       uint8_t *               ptr;
-       size_t                  i, wholeCount, remCount;
-       uint32_t                hash;
-       int                             n;
-       uint8_t                 txtStr[ 16 ];
-       
-       require_action_quiet( inSize > 0, exit, err = kSizeErr );
-       
-       txt = (uint8_t *) malloc( inSize );
-       require_action( txt, exit, err = kNoMemoryErr );
-       
-       hash = FNV1( inRecordName, DomainNameLength( inRecordName ) );
-       
-       txtStr[ 0 ] = 15;
-       n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
-       check( n == 15 );
-       
-       ptr = txt;
-       wholeCount = inSize / 16;
-       for( i = 0; i < wholeCount; ++i )
-       {
-               memcpy( ptr, txtStr, 16 );
-               ptr += 16;
-       }
-       
-       remCount = inSize % 16;
-       if( remCount > 0 )
-       {
-               txtStr[ 0 ] = (uint8_t)( remCount - 1 );
-               memcpy( ptr, txtStr, remCount );
-               ptr += remCount;
-       }
-       check( ptr == &txt[ inSize ] );
-       
-       *outTXT = txt;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MRResourceRecordCreate
-//===========================================================================================================================
-
-static OSStatus
-       _MRResourceRecordCreate(
-               uint8_t *                       inName,
-               uint16_t                        inType,
-               uint16_t                        inClass,
-               uint32_t                        inTTL,
-               uint16_t                        inRDLength,
-               uint8_t *                       inRData,
-               MRResourceRecord **     outRecord )
-{
-       OSStatus                                err;
-       MRResourceRecord *              obj;
-       
-       obj = (MRResourceRecord *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name               = inName;
-       obj->type               = inType;
-       obj->class              = inClass;
-       obj->ttl                = inTTL;
-       obj->rdlength   = inRDLength;
-       obj->rdata              = inRData;
-       
-       if( inType == kDNSServiceType_SRV )
-       {
-               require_action_quiet( obj->rdlength > sizeof( SRVRecordDataFixedFields ), exit, err = kMalformedErr );
-               obj->target = obj->rdata + sizeof( SRVRecordDataFixedFields );
-       }
-       
-       *outRecord = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       FreeNullSafe( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MRResourceRecordFree
-//===========================================================================================================================
-
-static void    _MRResourceRecordFree( MRResourceRecord *inRecord )
-{
-       ForgetMem( &inRecord->name );
-       ForgetMem( &inRecord->rdata );
-       free( inRecord );
-}
-
-//===========================================================================================================================
-//     _MRResourceRecordFreeList
-//===========================================================================================================================
-
-static void    _MRResourceRecordFreeList( MRResourceRecord *inList )
-{
-       MRResourceRecord *              record;
-       
-       while( ( record = inList ) != NULL )
-       {
-               inList = record->next;
-               _MRResourceRecordFree( record );
-       }
-}
-
-//===========================================================================================================================
-//     _MRNameOffsetItemCreate
-//===========================================================================================================================
-
-static OSStatus        _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem )
-{
-       OSStatus                                err;
-       MRNameOffsetItem *              obj;
-       size_t                                  nameLen;
-       
-       require_action_quiet( inOffset <= kDNSCompressionOffsetMax, exit, err = kSizeErr );
-       
-       nameLen = DomainNameLength( inName );
-       obj = (MRNameOffsetItem *) calloc( 1, offsetof( MRNameOffsetItem, name ) + nameLen );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->offset = inOffset;
-       memcpy( obj->name, inName, nameLen );
-       
-       *outItem = obj;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MRNameOffsetItemFree
-//===========================================================================================================================
-
-static void    _MRNameOffsetItemFree( MRNameOffsetItem *inItem )
-{
-       free( inItem );
-}
-
-//===========================================================================================================================
-//     _MRNameOffsetItemFreeList
-//===========================================================================================================================
-
-static void    _MRNameOffsetItemFreeList( MRNameOffsetItem *inList )
-{
-       MRNameOffsetItem *              item;
-       
-       while( ( item = inList ) != NULL )
-       {
-               inList = item->next;
-               _MRNameOffsetItemFree( item );
-       }
-}
-
-//===========================================================================================================================
-//     GAIPerfCmd
-//===========================================================================================================================
-
-#define kGAIPerfGAITimeLimitMs         500     // Allow at most 500 ms for a DNSServiceGetAddrInfo() operation to complete.
-#define kGAIPerfStandardTTL                    ( 1 * kSecondsPerHour )
-
-typedef struct GAITesterPrivate *              GAITesterRef;
-typedef struct GAITestCase                             GAITestCase;
-
-typedef struct
-{
-       const char *            name;                           // Domain name that was resolved.
-       uint64_t                        connectionTimeUs;       // Time in microseconds that it took to create a DNS-SD connection.
-       uint64_t                        firstTimeUs;            // Time in microseconds that it took to get the first address result.
-       uint64_t                        timeUs;                         // Time in microseconds that it took to get all expected address results.
-       OSStatus                        error;
-       
-}      GAITestItemResult;
-
-typedef void ( *GAITesterStopHandler_f )( void *inContext, OSStatus inError );
-typedef void
-       ( *GAITesterResultsHandler_f )(
-               const char *                            inCaseTitle,
-               NanoTime64                                      inCaseStartTime,
-               NanoTime64                                      inCaseEndTime,
-               const GAITestItemResult *       inResultArray,
-               size_t                                          inResultCount,
-               void *                                          inContext );
-
-typedef unsigned int           GAITestAddrType;
-#define kGAITestAddrType_None          0
-#define kGAITestAddrType_IPv4          ( 1U << 0 )
-#define kGAITestAddrType_IPv6          ( 1U << 1 )
-#define kGAITestAddrType_Both          ( kGAITestAddrType_IPv4 | kGAITestAddrType_IPv6 )
-
-#define GAITestAddrTypeIsValid( X ) \
-       ( ( (X) & kGAITestAddrType_Both ) && ( ( (X) & ~kGAITestAddrType_Both ) == 0 ) )
-
-typedef struct
-{
-       GAITesterRef                    tester;                         // GAI tester object.
-       CFMutableArrayRef               testCaseResults;        // Array of test case results.
-       unsigned int                    callDelayMs;            // Amount of time to wait before calling DNSServiceGetAddrInfo().
-       unsigned int                    serverDelayMs;          // Amount of additional time to have server delay its responses.
-       unsigned int                    defaultIterCount;       // Default test case iteration count.
-       dispatch_source_t               sigIntSource;           // Dispatch source for SIGINT.
-       dispatch_source_t               sigTermSource;          // Dispatch source for SIGTERM.
-       char *                                  outputFilePath;         // File to write test results to. If NULL, then write to stdout.
-       OutputFormatType                outputFormat;           // Format of test results output.
-       Boolean                                 appendNewline;          // True if a newline character should be appended to JSON output.
-       Boolean                                 skipPathEval;           // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
-       Boolean                                 badUDPMode;                     // True if the test DNS server is to run in Bad UDP mode.
-       Boolean                                 testFailed;                     // True if at least one test case iteration failed.
-       
-}      GAIPerfContext;
-
-static void            GAIPerfContextFree( GAIPerfContext *inContext );
-static OSStatus        GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext );
-static OSStatus        GAIPerfAddBasicTestCases( GAIPerfContext *inContext );
-static void            GAIPerfTesterStopHandler( void *inContext, OSStatus inError );
-static void
-       GAIPerfResultsHandler(
-               const char *                            inCaseTitle,
-               NanoTime64                                      inCaseStartTime,
-               NanoTime64                                      inCaseEndTime,
-               const GAITestItemResult *       inResultArray,
-               size_t                                          inResultCount,
-               void *                                          inContext );
-static void            GAIPerfSignalHandler( void *inContext );
-
-CFTypeID               GAITesterGetTypeID( void );
-static OSStatus
-       GAITesterCreate(
-               dispatch_queue_t        inQueue,
-               int                                     inCallDelayMs,
-               int                                     inServerDelayMs,
-               int                                     inServerDefaultTTL,
-               Boolean                         inSkipPathEvaluation,
-               Boolean                         inBadUDPMode,
-               GAITesterRef *          outTester );
-static void            GAITesterStart( GAITesterRef inTester );
-static void            GAITesterStop( GAITesterRef inTester );
-static OSStatus        GAITesterAddTestCase( GAITesterRef inTester, GAITestCase *inCase );
-static void
-       GAITesterSetStopHandler(
-               GAITesterRef                    inTester,
-               GAITesterStopHandler_f  inEventHandler,
-               void *                                  inEventContext );
-static void
-       GAITesterSetResultsHandler(
-               GAITesterRef                            inTester,
-               GAITesterResultsHandler_f       inResultsHandler,
-               void *                                          inResultsContext );
-
-static OSStatus        GAITestCaseCreate( const char *inTitle, GAITestCase **outCase );
-static void            GAITestCaseFree( GAITestCase *inCase );
-static OSStatus
-       GAITestCaseAddItem(
-               GAITestCase *   inCase,
-               unsigned int    inAliasCount,
-               unsigned int    inAddressCount,
-               int                             inTTL,
-               GAITestAddrType inHasAddrs,
-               GAITestAddrType inWantAddrs,
-               unsigned int    inTimeLimitMs,
-               unsigned int    inItemCount );
-static OSStatus
-       GAITestCaseAddLocalHostItem(
-               GAITestCase *   inCase,
-               GAITestAddrType inWantAddrs,
-               unsigned int    inTimeLimitMs,
-               unsigned int    inItemCount );
-
-static void    GAIPerfCmd( void )
-{
-       OSStatus                                err;
-       GAIPerfContext *                context = NULL;
-       
-       err = CheckRootUser();
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gGAIPerf_CallDelayMs, "call delay (ms)", 0, INT_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gGAIPerf_ServerDelayMs, "server delay (ms)", 0, INT_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gGAIPerf_IterationCount, "iteration count", 1, INT_MAX );
-       require_noerr_quiet( err, exit );
-       
-       context = (GAIPerfContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->testCaseResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-       require_action( context->testCaseResults, exit, err = kNoMemoryErr );
-       
-       context->callDelayMs            = (unsigned int) gGAIPerf_CallDelayMs;
-       context->serverDelayMs          = (unsigned int) gGAIPerf_ServerDelayMs;
-       context->defaultIterCount       = (unsigned int) gGAIPerf_IterationCount;
-       context->appendNewline          = gGAIPerf_OutputAppendNewline  ? true : false;
-       context->skipPathEval           = gGAIPerf_SkipPathEvalulation  ? true : false;
-       context->badUDPMode                     = gGAIPerf_BadUDPMode                   ? true : false;
-       
-       if( gGAIPerf_OutputFilePath )
-       {
-               context->outputFilePath = strdup( gGAIPerf_OutputFilePath );
-               require_action( context->outputFilePath, exit, err = kNoMemoryErr );
-       }
-       
-       context->outputFormat = (OutputFormatType) CLIArgToValue( "format", gGAIPerf_OutputFormat, &err,
-               kOutputFormatStr_JSON,          kOutputFormatType_JSON,
-               kOutputFormatStr_XML,           kOutputFormatType_XML,
-               kOutputFormatStr_Binary,        kOutputFormatType_Binary,
-               NULL );
-       require_noerr_quiet( err, exit );
-       
-       err = GAITesterCreate( dispatch_get_main_queue(), (int) context->callDelayMs, (int) context->serverDelayMs,
-               kGAIPerfStandardTTL, context->skipPathEval, context->badUDPMode, &context->tester );
-       require_noerr( err, exit );
-       
-       check( gGAIPerf_TestSuite );
-       if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Basic ) == 0 )
-       {
-               err = GAIPerfAddBasicTestCases( context );
-               require_noerr( err, exit );
-       }
-       else if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Advanced ) == 0 )
-       {
-               err = GAIPerfAddAdvancedTestCases( context );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               FPrintF( stderr, "error: Invalid test suite name: %s.\n", gGAIPerf_TestSuite );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       GAITesterSetStopHandler( context->tester, GAIPerfTesterStopHandler, context );
-       GAITesterSetResultsHandler( context->tester, GAIPerfResultsHandler, context );
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, GAIPerfSignalHandler, context, &context->sigIntSource );
-       require_noerr( err, exit );
-       dispatch_resume( context->sigIntSource );
-       
-       signal( SIGTERM, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGTERM, GAIPerfSignalHandler, context, &context->sigTermSource );
-       require_noerr( err, exit );
-       dispatch_resume( context->sigTermSource );
-       
-       GAITesterStart( context->tester );
-       dispatch_main();
-       
-exit:
-       if( context ) GAIPerfContextFree( context );
-       exit( 1 );
-}
-
-//===========================================================================================================================
-//     GAIPerfContextFree
-//===========================================================================================================================
-
-static void    GAIPerfContextFree( GAIPerfContext *inContext )
-{
-       ForgetCF( &inContext->tester );
-       ForgetCF( &inContext->testCaseResults );
-       ForgetMem( &inContext->outputFilePath );
-       dispatch_source_forget( &inContext->sigIntSource );
-       dispatch_source_forget( &inContext->sigTermSource );
-       free( inContext );
-}
-
-//===========================================================================================================================
-//     GAIPerfAddAdvancedTestCases
-//===========================================================================================================================
-
-#define kTestCaseTitleBufferSize               128
-
-static void
-       _GAIPerfWriteTestCaseTitle(
-               char                    inBuffer[ kTestCaseTitleBufferSize ],
-               unsigned int    inCNAMERecordCount,
-               unsigned int    inARecordCount,
-               unsigned int    inAAAARecordCount,
-               GAITestAddrType inRequested,
-               unsigned int    inIterationCount,
-               Boolean                 inIterationsAreUnique );
-static void
-       _GAIPerfWriteLocalHostTestCaseTitle(
-               char                    inBuffer[ kTestCaseTitleBufferSize ],
-               GAITestAddrType inRequested,
-               unsigned int    inIterationCount );
-
-#define kGAIPerfAdvancedTestSuite_MaxAliasCount                4
-#define kGAIPerfAdvancedTestSuite_MaxAddrCount         8
-
-static OSStatus        GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext )
-{
-       OSStatus                        err;
-       unsigned int            aliasCount, addressCount, i;
-       GAITestCase *           testCase = NULL;
-       char                            title[ kTestCaseTitleBufferSize ];
-       
-       aliasCount = 0;
-       while( aliasCount <= kGAIPerfAdvancedTestSuite_MaxAliasCount )
-       {
-               for( addressCount = 1; addressCount <= kGAIPerfAdvancedTestSuite_MaxAddrCount; addressCount *= 2 )
-               {
-                       // Add a test case to resolve a domain name with
-                       //
-                       //     <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
-                       //
-                       // to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which
-                       // requires server queries.
-                       
-                       _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
-                               inContext->defaultIterCount, true );
-                       
-                       err = GAITestCaseCreate( title, &testCase );
-                       require_noerr( err, exit );
-                       
-                       for( i = 0; i < inContext->defaultIterCount; ++i )
-                       {
-                               err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
-                                       kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs, 1 );
-                               require_noerr( err, exit );
-                       }
-                       
-                       err = GAITesterAddTestCase( inContext->tester, testCase );
-                       require_noerr( err, exit );
-                       testCase = NULL;
-                       
-                       // Add a test case to resolve a domain name with
-                       //
-                       //     <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
-                       //
-                       // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique domain name, which requires a server
-                       // query. The subsequent iterations resolve the same domain name as the preliminary iteration, which should
-                       // ideally require no server queries, i.e., the results should come from the cache.
-                       
-                       _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
-                               inContext->defaultIterCount, false );
-                       
-                       err = GAITestCaseCreate( title, &testCase );
-                       require_noerr( err, exit );
-                       
-                       err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
-                               kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs, inContext->defaultIterCount + 1 );
-                       require_noerr( err, exit );
-                       
-                       err = GAITesterAddTestCase( inContext->tester, testCase );
-                       require_noerr( err, exit );
-                       testCase = NULL;
-               }
-               
-               aliasCount = ( aliasCount == 0 ) ? 1 : ( 2 * aliasCount );
-       }
-       
-       // Finally, add a test case to resolve localhost to its IPv4 and IPv6 addresses.
-       
-       _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
-       
-       err = GAITestCaseCreate( title, &testCase );
-       require_noerr( err, exit );
-       
-       err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs,
-               inContext->defaultIterCount );
-       require_noerr( err, exit );
-       
-       err = GAITesterAddTestCase( inContext->tester, testCase );
-       require_noerr( err, exit );
-       testCase = NULL;
-       
-exit:
-       if( testCase ) GAITestCaseFree( testCase );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _GAIPerfWriteTestCaseTitle
-//===========================================================================================================================
-
-#define GAITestAddrTypeToRequestKeyValue( X ) (                                \
-       ( (X) == kGAITestAddrType_Both ) ? "ipv4\\,ipv6"        :       \
-       ( (X) == kGAITestAddrType_IPv4 ) ? "ipv4"                       :       \
-       ( (X) == kGAITestAddrType_IPv6 ) ? "ipv6"                       :       \
-                                                                          "" )
-
-static void
-       _GAIPerfWriteTestCaseTitle(
-               char                    inBuffer[ kTestCaseTitleBufferSize ],
-               unsigned int    inCNAMERecordCount,
-               unsigned int    inARecordCount,
-               unsigned int    inAAAARecordCount,
-               GAITestAddrType inRequested,
-               unsigned int    inIterationCount,
-               Boolean                 inIterationsAreUnique )
-{
-       SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=dynamic,cname=%u,a=%u,aaaa=%u,req=%s,iterations=%u%?s",
-               inCNAMERecordCount, inARecordCount, inAAAARecordCount, GAITestAddrTypeToRequestKeyValue( inRequested ),
-               inIterationCount, inIterationsAreUnique, ",unique" );
-}
-
-//===========================================================================================================================
-//     _GAIPerfWriteLocalHostTestCaseTitle
-//===========================================================================================================================
-
-static void
-       _GAIPerfWriteLocalHostTestCaseTitle(
-               char                    inBuffer[ kTestCaseTitleBufferSize ],
-               GAITestAddrType inRequested,
-               unsigned int    inIterationCount )
-{
-       SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=localhost,req=%s,iterations=%u",
-               GAITestAddrTypeToRequestKeyValue( inRequested ), inIterationCount );
-}
-
-//===========================================================================================================================
-//     GAIPerfAddBasicTestCases
-//===========================================================================================================================
-
-#define kGAIPerfBasicTestSuite_AliasCount              2
-#define kGAIPerfBasicTestSuite_AddrCount               4
-
-static OSStatus        GAIPerfAddBasicTestCases( GAIPerfContext *inContext )
-{
-       OSStatus                        err;
-       GAITestCase *           testCase = NULL;
-       char                            title[ kTestCaseTitleBufferSize ];
-       unsigned int            i;
-       
-       // Test Case #1:
-       // Resolve a domain name with
-       //
-       //     2 CNAME records, 4 A records, and 4 AAAA records
-       //
-       // to its IPv4 and IPv6 addresses. Each of the iterations resolves a unique domain name, which requires server
-       // queries.
-       
-       _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
-               kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
-               inContext->defaultIterCount, true );
-       
-       err = GAITestCaseCreate( title, &testCase );
-       require_noerr( err, exit );
-       
-       for( i = 0; i < inContext->defaultIterCount; ++i )
-       {
-               err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
-                       kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs, 1 );
-               require_noerr( err, exit );
-       }
-       
-       err = GAITesterAddTestCase( inContext->tester, testCase );
-       require_noerr( err, exit );
-       testCase = NULL;
-       
-       // Test Case #2:
-       // Resolve a domain name with
-       //
-       //     2 CNAME records, 4 A records, and 4 AAAA records
-       //
-       // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which
-       // requires server queries. Each of the subsequent iterations resolves the same domain name as the preliminary
-       // iteration, which should ideally require no additional server queries, i.e., the results should come from the cache.
-       
-       _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
-               kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
-               inContext->defaultIterCount, false );
-       
-       err = GAITestCaseCreate( title, &testCase );
-       require_noerr( err, exit );
-       
-       err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
-               kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs,
-               inContext->defaultIterCount + 1 );
-       require_noerr( err, exit );
-       
-       err = GAITesterAddTestCase( inContext->tester, testCase );
-       require_noerr( err, exit );
-       testCase = NULL;
-       
-       // Test Case #3:
-       // Each iteration resolves localhost to its IPv4 and IPv6 addresses.
-       
-       _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
-       
-       err = GAITestCaseCreate( title, &testCase );
-       require_noerr( err, exit );
-       
-       err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, kGAIPerfGAITimeLimitMs,
-               inContext->defaultIterCount );
-       require_noerr( err, exit );
-       
-       err = GAITesterAddTestCase( inContext->tester, testCase );
-       require_noerr( err, exit );
-       testCase = NULL;
-       
-exit:
-       if( testCase ) GAITestCaseFree( testCase );
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAIPerfTesterStopHandler
-//===========================================================================================================================
-
-#define kGAIPerfResultsKey_Info                                CFSTR( "info" )
-#define kGAIPerfResultsKey_TestCases           CFSTR( "testCases" )
-#define kGAIPerfResultsKey_Success                     CFSTR( "success" )
-
-#define kGAIPerfInfoKey_CallDelay                      CFSTR( "callDelayMs" )
-#define kGAIPerfInfoKey_ServerDelay                    CFSTR( "serverDelayMs" )
-#define kGAIPerfInfoKey_SkippedPathEval                CFSTR( "skippedPathEval" )
-#define kGAIPerfInfoKey_UsedBadUDPMode         CFSTR( "usedBadUPDMode" )
-
-static void    GAIPerfTesterStopHandler( void *inContext, OSStatus inError )
-{
-       OSStatus                                        err;
-       GAIPerfContext * const          context = (GAIPerfContext *) inContext;
-       CFPropertyListRef                       plist;
-       int                                                     exitCode;
-       
-       err = inError;
-       require_noerr_quiet( err, exit );
-       
-       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
-               "{"
-                       "%kO="                  // info
-                       "{"
-                               "%kO=%lli"      // callDelayMs
-                               "%kO=%lli"      // serverDelayMs
-                               "%kO=%b"        // skippedPathEval
-                               "%kO=%b"        // usedBadUPDMode
-                       "}"
-                       "%kO=%O"                // testCases
-                       "%kO=%b"                // success
-               "}",
-               kGAIPerfResultsKey_Info,
-               kGAIPerfInfoKey_CallDelay,                      (int64_t) context->callDelayMs,
-               kGAIPerfInfoKey_ServerDelay,            (int64_t) context->serverDelayMs,
-               kGAIPerfInfoKey_SkippedPathEval,        context->skipPathEval,
-               kGAIPerfInfoKey_UsedBadUDPMode,         context->badUDPMode,
-               kGAIPerfResultsKey_TestCases,           context->testCaseResults,
-               kGAIPerfResultsKey_Success,                     !context->testFailed );
-       require_noerr( err, exit );
-       
-       err = OutputPropertyList( plist, context->outputFormat, context->appendNewline, context->outputFilePath );
-       CFRelease( plist );
-       require_noerr( err, exit );
-       
-exit:
-       exitCode = err ? 1 : ( context->testFailed ? 2 : 0 );
-       GAIPerfContextFree( context );
-       exit( exitCode );
-}
-
-//===========================================================================================================================
-//     GAIPerfResultsHandler
-//===========================================================================================================================
-
-// Keys for test case dictionary
-
-#define kGAIPerfTestCaseKey_Title                              CFSTR( "title" )
-#define kGAIPerfTestCaseKey_StartTime                  CFSTR( "startTime" )
-#define kGAIPerfTestCaseKey_EndTime                            CFSTR( "endTime" )
-#define kGAIPerfTestCaseKey_Results                            CFSTR( "results" )
-#define kGAIPerfTestCaseKey_FirstStats                 CFSTR( "firstStats" )
-#define kGAIPerfTestCaseKey_ConnectionStats            CFSTR( "connectionStats" )
-#define kGAIPerfTestCaseKey_Stats                              CFSTR( "stats" )
-
-// Keys for test case results array entry dictionaries
-
-#define kGAIPerfTestCaseResultKey_Name                                 CFSTR( "name" )
-#define kGAIPerfTestCaseResultKey_ConnectionTime               CFSTR( "connectionTimeUs" )
-#define kGAIPerfTestCaseResultKey_FirstTime                            CFSTR( "firstTimeUs" )
-#define kGAIPerfTestCaseResultKey_Time                                 CFSTR( "timeUs" )
-
-// Keys for test case stats dictionaries
-
-#define kGAIPerfTestCaseStatsKey_Count         CFSTR( "count" )
-#define kGAIPerfTestCaseStatsKey_Min           CFSTR( "min" )
-#define kGAIPerfTestCaseStatsKey_Max           CFSTR( "max" )
-#define kGAIPerfTestCaseStatsKey_Mean          CFSTR( "mean" )
-#define kGAIPerfTestCaseStatsKey_StdDev                CFSTR( "sd" )
-
-typedef struct
-{
-       double          min;
-       double          max;
-       double          mean;
-       double          stdDev;
-       
-}      GAIPerfStats;
-
-#define GAIPerfStatsInit( X ) \
-       do { (X)->min = DBL_MAX; (X)->max = DBL_MIN; (X)->mean = 0.0; (X)->stdDev = 0.0; } while( 0 )
-
-static void
-       GAIPerfResultsHandler(
-               const char *                            inCaseTitle,
-               NanoTime64                                      inCaseStartTime,
-               NanoTime64                                      inCaseEndTime,
-               const GAITestItemResult *       inResultArray,
-               size_t                                          inResultCount,
-               void *                                          inContext )
-{
-       OSStatus                                                err;
-       GAIPerfContext * const                  context = (GAIPerfContext *) inContext;
-       int                                                             namesAreDynamic, namesAreUnique;
-       const char *                                    ptr;
-       size_t                                                  count, startIndex;
-       CFMutableArrayRef                               results = NULL;
-       GAIPerfStats                                    stats, firstStats, connStats;
-       double                                                  sum, firstSum, connSum;
-       size_t                                                  keyValueLen, i;
-       char                                                    keyValue[ 16 ]; // Size must be at least strlen( "name=dynamic" ) + 1 bytes.
-       char                                                    startTimeStr[ 32 ];
-       char                                                    endTimeStr[ 32 ];
-       const GAITestItemResult *               result;
-       
-       // If this test case resolves the same "d.test." name in each iteration (title contains the "name=dynamic" key-value
-       // pair, but not the "unique" key), then don't count the first iteration, whose purpose is to populate the cache with
-       // the domain name's CNAME, A, and AAAA records.
-       
-       namesAreDynamic = false;
-       namesAreUnique  = false;
-       ptr = inCaseTitle;
-       while( ParseQuotedEscapedString( ptr, NULL, ",", keyValue, sizeof( keyValue ), &keyValueLen, NULL, &ptr ) )
-       {
-               if( strnicmpx( keyValue, keyValueLen, "name=dynamic" ) == 0 )
-               {
-                       namesAreDynamic = true;
-               }
-               else if( strnicmpx( keyValue, keyValueLen, "unique" ) == 0 )
-               {
-                       namesAreUnique = true;
-               }
-               if( namesAreDynamic && namesAreUnique ) break;
-       }
-       
-       startIndex = ( ( inResultCount > 0 ) && namesAreDynamic && !namesAreUnique ) ? 1 : 0;
-       results = CFArrayCreateMutable( NULL, (CFIndex)( inResultCount - startIndex ), &kCFTypeArrayCallBacks );
-       require_action( results, exit, err = kNoMemoryErr );
-       
-       GAIPerfStatsInit( &stats );
-       GAIPerfStatsInit( &firstStats );
-       GAIPerfStatsInit( &connStats );
-       
-       sum                     = 0.0;
-       firstSum        = 0.0;
-       connSum         = 0.0;
-       count           = 0;
-       for( i = startIndex; i < inResultCount; ++i )
-       {
-               double          value;
-               
-               result = &inResultArray[ i ];
-               
-               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, results,
-                       "{"
-                               "%kO=%s"        // name
-                               "%kO=%lli"      // connectionTimeUs
-                               "%kO=%lli"      // firstTimeUs
-                               "%kO=%lli"      // timeUs
-                               "%kO=%lli"      // error
-                       "}",
-                       kGAIPerfTestCaseResultKey_Name,                         result->name,
-                       kGAIPerfTestCaseResultKey_ConnectionTime,       (int64_t) result->connectionTimeUs,
-                       kGAIPerfTestCaseResultKey_FirstTime,            (int64_t) result->firstTimeUs,
-                       kGAIPerfTestCaseResultKey_Time,                         (int64_t) result->timeUs,
-                       CFSTR( "error" ),                                                       (int64_t) result->error );
-               require_noerr( err, exit );
-               
-               if( !result->error )
-               {
-                       value = (double) result->timeUs;
-                       if( value < stats.min ) stats.min = value;
-                       if( value > stats.max ) stats.max = value;
-                       sum += value;
-                       
-                       value = (double) result->firstTimeUs;
-                       if( value < firstStats.min ) firstStats.min = value;
-                       if( value > firstStats.max ) firstStats.max = value;
-                       firstSum += value;
-                       
-                       value = (double) result->connectionTimeUs;
-                       if( value < connStats.min ) connStats.min = value;
-                       if( value > connStats.max ) connStats.max = value;
-                       connSum += value;
-                       
-                       ++count;
-               }
-               else
-               {
-                       context->testFailed = true;
-               }
-       }
-       
-       if( count > 0 )
-       {
-               stats.mean              = sum      / count;
-               firstStats.mean = firstSum / count;
-               connStats.mean  = connSum  / count;
-               
-               sum                     = 0.0;
-               firstSum        = 0.0;
-               connSum         = 0.0;
-               for( i = startIndex; i < inResultCount; ++i )
-               {
-                       double          diff;
-                       
-                       result = &inResultArray[ i ];
-                       if( result->error ) continue;
-                       
-                       diff             = stats.mean - (double) result->timeUs;
-                       sum                     += ( diff * diff );
-                       
-                       diff             = firstStats.mean - (double) result->firstTimeUs;
-                       firstSum        += ( diff * diff );
-                       
-                       diff             = connStats.mean - (double) result->connectionTimeUs;
-                       connSum         += ( diff * diff );
-               }
-               stats.stdDev            = sqrt( sum      / count );
-               firstStats.stdDev       = sqrt( firstSum / count );
-               connStats.stdDev        = sqrt( connSum  / count );
-       }
-       
-       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->testCaseResults,
-               "{"
-                       "%kO=%s"
-                       "%kO=%s"
-                       "%kO=%s"
-                       "%kO=%O"
-                       "%kO="
-                       "{"
-                               "%kO=%lli"
-                               "%kO=%f"
-                               "%kO=%f"
-                               "%kO=%f"
-                               "%kO=%f"
-                       "}"
-                       "%kO="
-                       "{"
-                               "%kO=%lli"
-                               "%kO=%f"
-                               "%kO=%f"
-                               "%kO=%f"
-                               "%kO=%f"
-                       "}"
-                       "%kO="
-                       "{"
-                               "%kO=%lli"
-                               "%kO=%f"
-                               "%kO=%f"
-                               "%kO=%f"
-                               "%kO=%f"
-                       "}"
-               "}",
-               kGAIPerfTestCaseKey_Title,                      inCaseTitle,
-               kGAIPerfTestCaseKey_StartTime,          _NanoTime64ToDateString( inCaseStartTime, startTimeStr, sizeof( startTimeStr ) ),
-               kGAIPerfTestCaseKey_EndTime,            _NanoTime64ToDateString( inCaseEndTime, endTimeStr, sizeof( endTimeStr ) ),
-               kGAIPerfTestCaseKey_Results,            results,
-               kGAIPerfTestCaseKey_Stats,
-               kGAIPerfTestCaseStatsKey_Count,         (int64_t) count,
-               kGAIPerfTestCaseStatsKey_Min,           stats.min,
-               kGAIPerfTestCaseStatsKey_Max,           stats.max,
-               kGAIPerfTestCaseStatsKey_Mean,          stats.mean,
-               kGAIPerfTestCaseStatsKey_StdDev,        stats.stdDev,
-               kGAIPerfTestCaseKey_FirstStats,
-               kGAIPerfTestCaseStatsKey_Count,         (int64_t) count,
-               kGAIPerfTestCaseStatsKey_Min,           firstStats.min,
-               kGAIPerfTestCaseStatsKey_Max,           firstStats.max,
-               kGAIPerfTestCaseStatsKey_Mean,          firstStats.mean,
-               kGAIPerfTestCaseStatsKey_StdDev,        firstStats.stdDev,
-               kGAIPerfTestCaseKey_ConnectionStats,
-               kGAIPerfTestCaseStatsKey_Count,         (int64_t) count,
-               kGAIPerfTestCaseStatsKey_Min,           connStats.min,
-               kGAIPerfTestCaseStatsKey_Max,           connStats.max,
-               kGAIPerfTestCaseStatsKey_Mean,          connStats.mean,
-               kGAIPerfTestCaseStatsKey_StdDev,        connStats.stdDev );
-       require_noerr( err, exit );
-       
-exit:
-       CFReleaseNullSafe( results );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     GAIPerfSignalHandler
-//===========================================================================================================================
-
-static void    GAIPerfSignalHandler( void *inContext )
-{
-       GAIPerfContext * const          context = (GAIPerfContext *) inContext;
-       
-       if( !context->tester ) exit( 1 );
-       GAITesterStop( context->tester );
-       context->tester = NULL;
-}
-
-//===========================================================================================================================
-//     GAITesterCreate
-//===========================================================================================================================
-
-// A character set of lower-case alphabet characters and digits and a string length of six allows for 36^6 = 2,176,782,336
-// possible strings to use in the Tag label.
-
-#define kGAITesterTagStringLen         6
-
-typedef struct GAITestItem             GAITestItem;
-struct GAITestItem
-{
-       GAITestItem *           next;                           // Next test item in list.
-       char *                          name;                           // Domain name to resolve.
-       uint64_t                        connectionTimeUs;       // Time in microseconds that it took to create a DNS-SD connection.
-       uint64_t                        firstTimeUs;            // Time in microseconds that it took to get the first address result.
-       uint64_t                        timeUs;                         // Time in microseconds that it took to get all expected address results.
-       unsigned int            addressCount;           // Address count of the domain name, i.e., the Count label argument.
-       OSStatus                        error;                          // Current status/error.
-       unsigned int            timeLimitMs;            // Time limit in milliseconds for the test item's completion.
-       Boolean                         hasV4;                          // True if the domain name has one or more IPv4 addresses.
-       Boolean                         hasV6;                          // True if the domain name has one or more IPv6 addresses.
-       Boolean                         wantV4;                         // True if DNSServiceGetAddrInfo() should be called to get IPv4 addresses.
-       Boolean                         wantV6;                         // True if DNSServiceGetAddrInfo() should be called to get IPv6 addresses.
-};
-
-struct GAITestCase
-{
-       GAITestCase *           next;           // Next test case in list.
-       GAITestItem *           itemList;       // List of test items.
-       char *                          title;          // Title of the test case.
-};
-
-struct GAITesterPrivate
-{
-       CFRuntimeBase                                   base;                           // CF object base.
-       dispatch_queue_t                                queue;                          // Serial work queue.
-       DNSServiceRef                                   connection;                     // Reference to the shared DNS-SD connection.
-       DNSServiceRef                                   getAddrInfo;            // Reference to the current DNSServiceGetAddrInfo operation.
-       GAITestCase *                                   caseList;                       // List of test cases.
-       GAITestCase *                                   currentCase;            // Pointer to the current test case.
-       GAITestItem *                                   currentItem;            // Pointer to the current test item.
-       NanoTime64                                              caseStartTime;          // Start time of current test case in Unix time as nanoseconds.
-       NanoTime64                                              caseEndTime;            // End time of current test case in Unix time as nanoseconds.
-       int                                                             callDelayMs;            // Amount of time to wait before calling DNSServiceGetAddrInfo().
-       Boolean                                                 skipPathEval;           // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
-       Boolean                                                 stopped;                        // True if the tester has been stopped.
-       Boolean                                                 badUDPMode;                     // True if the test DNS server is to run in Bad UDP mode.
-       dispatch_source_t                               timer;                          // Timer for enforcing a test item's time limit.
-       pcap_t *                                                pcap;                           // Captures traffic between mDNSResponder and test DNS server.
-       pid_t                                                   serverPID;                      // PID of the test DNS server.
-       int                                                             serverDelayMs;          // Additional time to have the server delay its responses by.
-       int                                                             serverDefaultTTL;       // Default TTL for the server's records.
-       GAITesterStopHandler_f                  stopHandler;            // User's stop handler.
-       void *                                                  stopContext;            // User's event handler context.
-       GAITesterResultsHandler_f               resultsHandler;         // User's results handler.
-       void *                                                  resultsContext;         // User's results handler context.
-       
-       // Variables for current test item.
-       
-       uint64_t                                                bitmapV4;               // Bitmap of IPv4 results that have yet to be received.
-       uint64_t                                                bitmapV6;               // Bitmap of IPv6 results that have yet to be received.
-       uint64_t                                                startTicks;             // Start ticks of DNSServiceGetAddrInfo().
-       uint64_t                                                connTicks;              // Ticks when the connection was created.
-       uint64_t                                                firstTicks;             // Ticks when the first DNSServiceGetAddrInfo result was received.
-       uint64_t                                                endTicks;               // Ticks when the last DNSServiceGetAddrInfo result was received.
-       Boolean                                                 gotFirstResult; // True if the first result has been received.
-};
-
-CF_CLASS_DEFINE( GAITester );
-
-static void            _GAITesterStartNextTest( GAITesterRef inTester );
-static OSStatus        _GAITesterCreatePacketCapture( pcap_t **outPCap );
-static void            _GAITesterFirstGAITimeout( void *inContext );
-static void            _GAITesterTimeout( void *inContext );
-static void DNSSD_API
-       _GAITesterFirstGAICallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static void DNSSD_API
-       _GAITesterGetAddrInfoCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static void            _GAITesterCompleteCurrentTest( GAITesterRef inTester, OSStatus inError );
-
-#define ForgetPacketCapture( X )               ForgetCustom( X, pcap_close )
-
-static OSStatus
-       GAITestItemCreate(
-               const char *    inName,
-               unsigned int    inAddressCount,
-               GAITestAddrType inHasAddrs,
-               GAITestAddrType inWantAddrs,
-               unsigned int    inTimeLimitMs,
-               GAITestItem **  outItem );
-static OSStatus        GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem );
-static void            GAITestItemFree( GAITestItem *inItem );
-
-static OSStatus
-       GAITesterCreate(
-               dispatch_queue_t        inQueue,
-               int                                     inCallDelayMs,
-               int                                     inServerDelayMs,
-               int                                     inServerDefaultTTL,
-               Boolean                         inSkipPathEvaluation,
-               Boolean                         inBadUDPMode,
-               GAITesterRef *          outTester )
-{
-       OSStatus                        err;
-       GAITesterRef            obj = NULL;
-       
-       CF_OBJECT_CREATE( GAITester, obj, err, exit );
-       
-       ReplaceDispatchQueue( &obj->queue, inQueue );
-       obj->callDelayMs                = inCallDelayMs;
-       obj->serverPID                  = -1;
-       obj->serverDelayMs              = inServerDelayMs;
-       obj->serverDefaultTTL   = inServerDefaultTTL;
-       obj->skipPathEval               = inSkipPathEvaluation;
-       obj->badUDPMode                 = inBadUDPMode;
-       
-       *outTester = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       CFReleaseNullSafe( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _GAITesterFinalize
-//===========================================================================================================================
-
-static void    _GAITesterFinalize( CFTypeRef inObj )
-{
-       GAITesterRef const              me = (GAITesterRef) inObj;
-       GAITestCase *                   testCase;
-       
-       check( !me->getAddrInfo );
-       check( !me->connection );
-       check( !me->timer );
-       dispatch_forget( &me->queue );
-       while( ( testCase = me->caseList ) != NULL )
-       {
-               me->caseList = testCase->next;
-               GAITestCaseFree( testCase );
-       }
-}
-
-//===========================================================================================================================
-//     GAITesterStart
-//===========================================================================================================================
-
-static void    _GAITesterStart( void *inContext );
-static void    _GAITesterStop( GAITesterRef me, OSStatus inError );
-
-static void    GAITesterStart( GAITesterRef me )
-{
-       CFRetain( me );
-       dispatch_async_f( me->queue, me, _GAITesterStart );
-}
-
-#define kGAITesterFirstGAITimeoutSecs          4
-
-static void    _GAITesterStart( void *inContext )
-{
-       OSStatus                                err;
-       GAITesterRef const              me = (GAITesterRef) inContext;
-       DNSServiceFlags                 flags;
-       char                                    name[ 64 ];
-       char                                    tag[ kGAITesterTagStringLen + 1 ];
-       
-       err = SpawnCommand( &me->serverPID, "dnssdutil server --loopback --follow %lld%?s%?d%?s%?d%?s",
-               (int64_t) getpid(),
-               me->serverDefaultTTL >= 0,      " --defaultTTL ",
-               me->serverDefaultTTL >= 0,      me->serverDefaultTTL,
-               me->serverDelayMs    >= 0,      " --responseDelay ",
-               me->serverDelayMs    >= 0,      me->serverDelayMs,
-               me->badUDPMode,                         " --badUDPMode" );
-       require_noerr_quiet( err, exit );
-       
-       SNPrintF( name, sizeof( name ), "tag-gaitester-probe-%s.ipv4.d.test",
-               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
-       
-       flags = 0;
-       if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
-       
-       err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, kDNSServiceProtocol_IPv4, name,
-               _GAITesterFirstGAICallback, me );
-       require_noerr( err, exit );
-       
-       err = DNSServiceSetDispatchQueue( me->getAddrInfo, me->queue );
-       require_noerr( err, exit );
-       
-       err = DispatchTimerOneShotCreate( dispatch_time_seconds( kGAITesterFirstGAITimeoutSecs ),
-               UINT64_C_safe( kGAITesterFirstGAITimeoutSecs ) * kNanosecondsPerSecond / 10, me->queue,
-               _GAITesterFirstGAITimeout, me, &me->timer );
-       require_noerr( err, exit );
-       dispatch_resume( me->timer );
-       
-exit:
-       if( err ) _GAITesterStop( me, err );
-}
-
-//===========================================================================================================================
-//     GAITesterStop
-//===========================================================================================================================
-
-static void    _GAITesterUserStop( void *inContext );
-
-static void    GAITesterStop( GAITesterRef me )
-{
-       CFRetain( me );
-       dispatch_async_f( me->queue, me, _GAITesterUserStop );
-}
-
-static void    _GAITesterUserStop( void *inContext )
-{
-       GAITesterRef const              me = (GAITesterRef) inContext;
-       
-       _GAITesterStop( me, kCanceledErr );
-       CFRelease( me );
-}
-
-static void    _GAITesterStop( GAITesterRef me, OSStatus inError )
-{
-       OSStatus                err;
-       
-       ForgetPacketCapture( &me->pcap );
-       dispatch_source_forget( &me->timer );
-       DNSServiceForget( &me->getAddrInfo );
-       DNSServiceForget( &me->connection );
-       if( me->serverPID != -1 )
-       {
-               err = kill( me->serverPID, SIGTERM );
-               err = map_global_noerr_errno( err );
-               check_noerr( err );
-               me->serverPID = -1;
-       }
-       
-       if( !me->stopped )
-       {
-               me->stopped = true;
-               if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
-               CFRelease( me );
-       }
-}
-
-//===========================================================================================================================
-//     GAITesterAddTestCase
-//===========================================================================================================================
-
-static OSStatus        GAITesterAddTestCase( GAITesterRef me, GAITestCase *inCase )
-{
-       OSStatus                        err;
-       GAITestCase **          ptr;
-       
-       require_action_quiet( inCase->itemList, exit, err = kCountErr );
-       
-       for( ptr = &me->caseList; *ptr; ptr = &( *ptr )->next ) {}
-       *ptr = inCase;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAITesterSetStopHandler
-//===========================================================================================================================
-
-static void    GAITesterSetStopHandler( GAITesterRef me, GAITesterStopHandler_f inStopHandler, void *inStopContext )
-{
-       me->stopHandler = inStopHandler;
-       me->stopContext = inStopContext;
-}
-
-//===========================================================================================================================
-//     GAITesterSetResultsHandler
-//===========================================================================================================================
-
-static void    GAITesterSetResultsHandler( GAITesterRef me, GAITesterResultsHandler_f inResultsHandler, void *inResultsContext )
-{
-       me->resultsHandler = inResultsHandler;
-       me->resultsContext = inResultsContext;
-}
-
-//===========================================================================================================================
-//     _GAITesterStartNextTest
-//===========================================================================================================================
-
-static void    _GAITesterStartNextTest( GAITesterRef me )
-{
-       OSStatus                                err;
-       GAITestItem *                   item;
-       DNSServiceFlags                 flags;
-       DNSServiceProtocol              protocols;
-       int                                             done = false;
-       
-       if( me->currentItem ) me->currentItem = me->currentItem->next;
-       
-       if( !me->currentItem )
-       {
-               if( me->currentCase )
-               {
-                       // No more test items means that the current test case has completed.
-                       
-                       me->caseEndTime = NanoTimeGetCurrent();
-                       
-                       if( me->resultsHandler )
-                       {
-                               size_t                                  resultCount, i;
-                               GAITestItemResult *             resultArray;
-                               
-                               resultCount     = 0;
-                               for( item = me->currentCase->itemList; item; item = item->next ) ++resultCount;
-                               check( resultCount > 0 );
-                               
-                               resultArray = (GAITestItemResult *) calloc( resultCount, sizeof( *resultArray ) );
-                               require_action( resultArray, exit, err = kNoMemoryErr );
-                               
-                               item = me->currentCase->itemList;
-                               for( i = 0; i < resultCount; ++i )
-                               {
-                                       resultArray[ i ].name                           = item->name;
-                                       resultArray[ i ].connectionTimeUs       = item->connectionTimeUs;
-                                       resultArray[ i ].firstTimeUs            = item->firstTimeUs;
-                                       resultArray[ i ].timeUs                         = item->timeUs;
-                                       resultArray[ i ].error                          = item->error;
-                                       item = item->next;
-                               }
-                               me->resultsHandler( me->currentCase->title, me->caseStartTime, me->caseEndTime, resultArray, resultCount,
-                                       me->resultsContext );
-                               ForgetMem( &resultArray );
-                       }
-                       
-                       me->currentCase = me->currentCase->next;
-                       if( !me->currentCase )
-                       {
-                               done = true;
-                               err = kNoErr;
-                               goto exit;
-                       }
-               }
-               else
-               {
-                       me->currentCase = me->caseList;
-               }
-               require_action_quiet( me->currentCase->itemList, exit, err = kInternalErr );
-               me->currentItem = me->currentCase->itemList;
-       }
-       
-       item = me->currentItem;
-       check( ( item->addressCount >= 1 ) && ( item->addressCount <= 64 ) );
-       
-       if(      !item->wantV4 )                        me->bitmapV4 = 0;
-       else if( !item->hasV4 )                         me->bitmapV4 = 1;
-       else if(  item->addressCount < 64 )     me->bitmapV4 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
-       else                                                            me->bitmapV4 =  ~UINT64_C( 0 );
-       
-       if(      !item->wantV6 )                        me->bitmapV6 = 0;
-       else if( !item->hasV6 )                         me->bitmapV6 = 1;
-       else if(  item->addressCount < 64 )     me->bitmapV6 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
-       else                                                            me->bitmapV6 =  ~UINT64_C( 0 );
-       check( ( me->bitmapV4 != 0 ) || ( me->bitmapV6 != 0 ) );
-       me->gotFirstResult = false;
-       
-       // Perform preliminary tasks if this is the start of a new test case.
-       
-       if( item == me->currentCase->itemList )
-       {
-               // Flush mDNSResponder's cache.
-               
-               err = systemf( NULL, "killall -HUP mDNSResponder" );
-               require_noerr( err, exit );
-               sleep( 1 );
-               
-               me->caseStartTime       = NanoTimeGetCurrent();
-               me->caseEndTime         = kNanoTime_Invalid;
-       }
-       
-       // Start a packet capture.
-       
-       check( !me->pcap );
-       err = _GAITesterCreatePacketCapture( &me->pcap );
-       require_noerr( err, exit );
-       
-       // Start timer for test item's time limit.
-       
-       check( !me->timer );
-       if( item->timeLimitMs > 0 )
-       {
-               unsigned int            timeLimitMs;
-               
-               timeLimitMs = item->timeLimitMs;
-               if( me->callDelayMs   > 0 ) timeLimitMs += (unsigned int) me->callDelayMs;
-               if( me->serverDelayMs > 0 ) timeLimitMs += (unsigned int) me->serverDelayMs;
-               
-               err = DispatchTimerCreate( dispatch_time_milliseconds( timeLimitMs ), DISPATCH_TIME_FOREVER,
-                       ( (uint64_t) timeLimitMs ) * kNanosecondsPerMillisecond / 10,
-                       me->queue, _GAITesterTimeout, NULL, me, &me->timer );
-               require_noerr( err, exit );
-               dispatch_resume( me->timer );
-       }
-       
-       // Call DNSServiceGetAddrInfo().
-       
-       if( me->callDelayMs > 0 ) usleep( ( (useconds_t) me->callDelayMs ) * kMicrosecondsPerMillisecond );
-       
-       flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
-       if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
-       
-       protocols = 0;
-       if( item->wantV4 ) protocols |= kDNSServiceProtocol_IPv4;
-       if( item->wantV6 ) protocols |= kDNSServiceProtocol_IPv6;
-       
-       me->startTicks = UpTicks();
-       
-       check( !me->connection );
-       err = DNSServiceCreateConnection( &me->connection );
-       require_noerr( err, exit );
-       
-       err = DNSServiceSetDispatchQueue( me->connection, me->queue );
-       require_noerr( err, exit );
-       
-       me->connTicks = UpTicks();
-       
-       check( !me->getAddrInfo );
-       me->getAddrInfo = me->connection;
-       err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, protocols, item->name,
-               _GAITesterGetAddrInfoCallback, me );
-       require_noerr( err, exit );
-       
-exit:
-       if( err || done ) _GAITesterStop( me, err );
-}
-
-//===========================================================================================================================
-//     _GAITesterCreatePacketCapture
-//===========================================================================================================================
-
-static OSStatus        _GAITesterCreatePacketCapture( pcap_t **outPCap )
-{
-       OSStatus                                err;
-       pcap_t *                                pcap;
-       struct bpf_program              program;
-       char                                    errBuf[ PCAP_ERRBUF_SIZE ];
-       
-       pcap = pcap_create( "lo0", errBuf );
-       require_action_string( pcap, exit, err = kUnknownErr, errBuf );
-       
-       err = pcap_set_buffer_size( pcap, 512 * kBytesPerKiloByte );
-       require_noerr_action( err, exit, err = kUnknownErr );
-       
-       err = pcap_set_snaplen( pcap, 512 );
-       require_noerr_action( err, exit, err = kUnknownErr );
-       
-       err = pcap_set_immediate_mode( pcap, 0 );
-       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-       
-       err = pcap_activate( pcap );
-       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-       
-       err = pcap_setdirection( pcap, PCAP_D_INOUT );
-       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-       
-       err = pcap_setnonblock( pcap, 1, errBuf );
-       require_noerr_action_string( err, exit, err = kUnknownErr, errBuf );
-       
-       err = pcap_compile( pcap, &program, "udp port 53", 1, PCAP_NETMASK_UNKNOWN );
-       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-       
-       err = pcap_setfilter( pcap, &program );
-       pcap_freecode( &program );
-       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
-       
-       *outPCap = pcap;
-       pcap = NULL;
-       
-exit:
-       if( pcap ) pcap_close( pcap );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _GAITesterFirstGAITimeout
-//===========================================================================================================================
-
-static void    _GAITesterFirstGAITimeout( void *inContext )
-{
-       GAITesterRef const              me = (GAITesterRef) inContext;
-       
-       _GAITesterStop( me, kNoResourcesErr );
-}
-
-//===========================================================================================================================
-//     _GAITesterTimeout
-//===========================================================================================================================
-
-static void    _GAITesterTimeout( void *inContext )
-{
-       GAITesterRef const              me = (GAITesterRef) inContext;
-       
-       _GAITesterCompleteCurrentTest( me, kTimeoutErr );
-}
-
-//===========================================================================================================================
-//     _GAITesterFirstGAICallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _GAITesterFirstGAICallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       GAITesterRef const              me = (GAITesterRef) inContext;
-       
-       Unused( inSDRef );
-       Unused( inInterfaceIndex );
-       Unused( inHostname );
-       Unused( inSockAddr );
-       Unused( inTTL );
-       
-       if( ( inFlags & kDNSServiceFlagsAdd ) && !inError )
-       {
-               dispatch_source_forget( &me->timer );
-               DNSServiceForget( &me->getAddrInfo );
-               
-               _GAITesterStartNextTest( me );
-       }
-}
-
-//===========================================================================================================================
-//     _GAITesterGetAddrInfoCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _GAITesterGetAddrInfoCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       OSStatus                                                err;
-       GAITesterRef const                              me              = (GAITesterRef) inContext;
-       GAITestItem * const                             item    = me->currentItem;
-       const sockaddr_ip * const               sip             = (const sockaddr_ip *) inSockAddr;
-       uint64_t                                                nowTicks;
-       uint64_t *                                              bitmapPtr;
-       uint64_t                                                bitmask;
-       int                                                             hasAddr;
-       
-       Unused( inSDRef );
-       Unused( inInterfaceIndex );
-       Unused( inHostname );
-       Unused( inTTL );
-       
-       nowTicks = UpTicks();
-       
-       require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
-       
-       // Check if we were expecting an IP address result of this type.
-       
-       if( sip->sa.sa_family == AF_INET )
-       {
-               bitmapPtr       = &me->bitmapV4;
-               hasAddr         = item->hasV4;
-       }
-       else if( sip->sa.sa_family == AF_INET6 )
-       {
-               bitmapPtr       = &me->bitmapV6;
-               hasAddr         = item->hasV6;
-       }
-       else
-       {
-               err = kTypeErr;
-               goto exit;
-       }
-       
-       bitmask = 0;
-       if( hasAddr )
-       {
-               uint32_t                addrOffset;
-               
-               require_noerr_action_quiet( inError, exit, err = inError );
-               
-               if( sip->sa.sa_family == AF_INET )
-               {
-                       const uint32_t          addrV4 = ntohl( sip->v4.sin_addr.s_addr );
-                       
-                       if( strcasecmp( item->name, "localhost." ) == 0 )
-                       {
-                               if( addrV4 == INADDR_LOOPBACK ) bitmask = 1;
-                       }
-                       else
-                       {
-                               addrOffset = addrV4 - kDNSServerBaseAddrV4;
-                               if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
-                               {
-                                       bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
-                               }
-                       }
-               }
-               else
-               {
-                       const uint8_t * const           addrV6 = sip->v6.sin6_addr.s6_addr;
-                       
-                       if( strcasecmp( item->name, "localhost." ) == 0 )
-                       {
-                               if( memcmp( addrV6, in6addr_loopback.s6_addr, 16 ) == 0 ) bitmask = 1;
-                       }
-                       else if( memcmp( addrV6, kDNSServerBaseAddrV6, 15 ) == 0 )
-                       {
-                               addrOffset = addrV6[ 15 ];
-                               if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
-                               {
-                                       bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
-                               }
-                       }
-               }
-       }
-       else
-       {
-               require_action_quiet( inError == kDNSServiceErr_NoSuchRecord, exit, err = inError ? inError : kUnexpectedErr );
-               bitmask = 1;
-       }
-       require_action_quiet( bitmask != 0, exit, err = kValueErr );
-       require_action_quiet( *bitmapPtr & bitmask, exit, err = kDuplicateErr );
-       
-       *bitmapPtr &= ~bitmask;
-       if( !me->gotFirstResult )
-       {
-               me->firstTicks          = nowTicks;
-               me->gotFirstResult      = true;
-       }
-       err = kNoErr;
-       
-exit:
-       if( err || ( ( me->bitmapV4 == 0 ) && ( me->bitmapV6 == 0 ) ) )
-       {
-               me->endTicks = nowTicks;
-               _GAITesterCompleteCurrentTest( me, err );
-       }
-}
-
-//===========================================================================================================================
-//     _GAITesterCompleteCurrentTest
-//===========================================================================================================================
-
-static OSStatus
-       _GAITesterGetDNSMessageFromPacket(
-               const uint8_t *         inPacketPtr,
-               size_t                          inPacketLen,
-               const uint8_t **        outMsgPtr,
-               size_t *                        outMsgLen );
-
-static void    _GAITesterCompleteCurrentTest( GAITesterRef me, OSStatus inError )
-{
-       OSStatus                                err;
-       GAITestItem * const             item    = me->currentItem;
-       struct timeval                  timeStamps[ 4 ];
-       struct timeval *                tsPtr;
-       struct timeval *                tsQA    = NULL;
-       struct timeval *                tsQAAAA = NULL;
-       struct timeval *                tsRA    = NULL;
-       struct timeval *                tsRAAAA = NULL;
-       struct timeval *                t1;
-       struct timeval *                t2;
-       int64_t                                 idleTimeUs;
-       uint8_t                                 name[ kDomainNameLengthMax ];
-       
-       dispatch_source_forget( &me->timer );
-       DNSServiceForget( &me->getAddrInfo );
-       DNSServiceForget( &me->connection );
-       
-       item->error = inError;
-       if( item->error )
-       {
-               err = kNoErr;
-               goto exit;
-       }
-       
-       err = DomainNameFromString( name, item->name, NULL );
-       require_noerr( err, exit );
-       
-       tsPtr = &timeStamps[ 0 ];
-       for( ;; )
-       {
-               int                                                     status;
-               struct pcap_pkthdr *            pktHdr;
-               const uint8_t *                         packet;
-               const uint8_t *                         msgPtr;
-               size_t                                          msgLen;
-               const DNSHeader *                       hdr;
-               unsigned int                            flags;
-               const uint8_t *                         ptr;
-               uint16_t                                        qtype, qclass;
-               uint8_t                                         qname[ kDomainNameLengthMax ];
-               
-               status = pcap_next_ex( me->pcap, &pktHdr, &packet );
-               if( status != 1 ) break;
-               if( _GAITesterGetDNSMessageFromPacket( packet, pktHdr->caplen, &msgPtr, &msgLen ) != kNoErr ) continue;
-               if( msgLen < kDNSHeaderLength ) continue;
-               
-               hdr = (const DNSHeader *) msgPtr;
-               flags = DNSHeaderGetFlags( hdr );
-               if( DNSFlagsGetOpCode( flags ) != kDNSOpCode_Query ) continue;
-               if( DNSHeaderGetQuestionCount( hdr ) < 1 ) continue;
-               
-               ptr = (const uint8_t *) &hdr[ 1 ];
-               if( DNSMessageExtractQuestion( msgPtr, msgLen, ptr, qname, &qtype, &qclass, NULL ) != kNoErr ) continue;
-               if( qclass != kDNSServiceClass_IN ) continue;
-               if( !DomainNameEqual( qname, name ) ) continue;
-               
-               if( item->wantV4 && ( qtype == kDNSServiceType_A ) )
-               {
-                       if( flags & kDNSHeaderFlag_Response )
-                       {
-                               if( tsQA && !tsRA )
-                               {
-                                       tsRA  = tsPtr++;
-                                       *tsRA = pktHdr->ts;
-                               }
-                       }
-                       else if( !tsQA )
-                       {
-                               tsQA  = tsPtr++;
-                               *tsQA = pktHdr->ts;
-                       }
-               }
-               else if( item->wantV6 && ( qtype == kDNSServiceType_AAAA ) )
-               {
-                       if( flags & kDNSHeaderFlag_Response )
-                       {
-                               if( tsQAAAA && !tsRAAAA )
-                               {
-                                       tsRAAAA  = tsPtr++;
-                                       *tsRAAAA = pktHdr->ts;
-                               }
-                       }
-                       else if( !tsQAAAA )
-                       {
-                               tsQAAAA  = tsPtr++;
-                               *tsQAAAA = pktHdr->ts;
-                       }
-               }
-       }
-       
-       // t1 is the time when the last query was sent.
-       
-       if( tsQA && tsQAAAA )   t1 = TIMEVAL_GT( *tsQA, *tsQAAAA ) ? tsQA : tsQAAAA;
-       else                                    t1 = tsQA ? tsQA : tsQAAAA;
-       
-       // t2 is when the first response was received.
-       
-       if( tsRA && tsRAAAA )   t2 = TIMEVAL_LT( *tsRA, *tsRAAAA ) ? tsRA : tsRAAAA;
-       else                                    t2 = tsRA ? tsRA : tsRAAAA;
-       
-       if( t1 && t2 )
-       {
-               idleTimeUs = TIMEVAL_USEC64_DIFF( *t2, *t1 );
-               if( idleTimeUs < 0 ) idleTimeUs = 0;
-       }
-       else
-       {
-               idleTimeUs = 0;
-       }
-       
-       item->connectionTimeUs  = UpTicksToMicroseconds( me->connTicks  - me->startTicks );
-       item->firstTimeUs               = UpTicksToMicroseconds( me->firstTicks - me->connTicks  ) - (uint64_t) idleTimeUs;
-       item->timeUs                    = UpTicksToMicroseconds( me->endTicks   - me->connTicks  ) - (uint64_t) idleTimeUs;
-       
-exit:
-       ForgetPacketCapture( &me->pcap );
-       if( err )       _GAITesterStop( me, err );
-       else            _GAITesterStartNextTest( me );
-}
-
-//===========================================================================================================================
-//     _GAITesterGetDNSMessageFromPacket
-//===========================================================================================================================
-
-#define kHeaderSizeNullLink             4
-#define kHeaderSizeIPv4Min             20
-#define kHeaderSizeIPv6                        40
-#define kHeaderSizeUDP                  8
-
-#define kIPProtocolUDP         0x11
-
-static OSStatus
-       _GAITesterGetDNSMessageFromPacket(
-               const uint8_t *         inPacketPtr,
-               size_t                          inPacketLen,
-               const uint8_t **        outMsgPtr,
-               size_t *                        outMsgLen )
-{
-       OSStatus                                        err;
-       const uint8_t *                         nullLink;
-       uint32_t                                        addressFamily;
-       const uint8_t *                         ip;
-       int                                                     ipHeaderLen;
-       int                                                     protocol;
-       const uint8_t *                         msg;
-       const uint8_t * const           end = &inPacketPtr[ inPacketLen ];
-       
-       nullLink = &inPacketPtr[ 0 ];
-       require_action_quiet( ( end - nullLink ) >= kHeaderSizeNullLink, exit, err = kUnderrunErr );
-       addressFamily = ReadHost32( &nullLink[ 0 ] );
-       
-       ip = &nullLink[ kHeaderSizeNullLink ];
-       if( addressFamily == AF_INET )
-       {
-               require_action_quiet( ( end - ip ) >= kHeaderSizeIPv4Min, exit, err = kUnderrunErr );
-               ipHeaderLen     = ( ip[ 0 ] & 0x0F ) * 4;
-               protocol        =   ip[ 9 ];
-       }
-       else if( addressFamily == AF_INET6 )
-       {
-               require_action_quiet( ( end - ip ) >= kHeaderSizeIPv6, exit, err = kUnderrunErr );
-               ipHeaderLen     = kHeaderSizeIPv6;
-               protocol        = ip[ 6 ];
-       }
-       else
-       {
-               err = kTypeErr;
-               goto exit;
-       }
-       require_action_quiet( protocol == kIPProtocolUDP, exit, err = kTypeErr );
-       require_action_quiet( ( end - ip ) >= ( ipHeaderLen + kHeaderSizeUDP ), exit, err = kUnderrunErr );
-       
-       msg = &ip[ ipHeaderLen + kHeaderSizeUDP ];
-       
-       *outMsgPtr = msg;
-       *outMsgLen = (size_t)( end - msg );
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAITestCaseCreate
-//===========================================================================================================================
-
-static OSStatus        GAITestCaseCreate( const char *inTitle, GAITestCase **outCase )
-{
-       OSStatus                        err;
-       GAITestCase *           obj;
-       
-       obj = (GAITestCase *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->title = strdup( inTitle );
-       require_action( obj->title, exit, err = kNoMemoryErr );
-       
-       *outCase = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) GAITestCaseFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAITestCaseFree
-//===========================================================================================================================
-
-static void    GAITestCaseFree( GAITestCase *inCase )
-{
-       GAITestItem *           item;
-       
-       while( ( item = inCase->itemList ) != NULL )
-       {
-               inCase->itemList = item->next;
-               GAITestItemFree( item );
-       }
-       ForgetMem( &inCase->title );
-       free( inCase );
-}
-
-//===========================================================================================================================
-//     GAITestCaseAddItem
-//===========================================================================================================================
-
-static OSStatus
-       GAITestCaseAddItem(
-               GAITestCase *   inCase,
-               unsigned int    inAliasCount,
-               unsigned int    inAddressCount,
-               int                             inTTL,
-               GAITestAddrType inHasAddrs,
-               GAITestAddrType inWantAddrs,
-               unsigned int    inTimeLimitMs,
-               unsigned int    inItemCount )
-{
-       OSStatus                        err;
-       GAITestItem *           item;
-       GAITestItem *           item2;
-       GAITestItem *           newItemList = NULL;
-       GAITestItem **          itemPtr;
-       char *                          ptr;
-       char *                          end;
-       unsigned int            i;
-       char                            name[ 64 ];
-       char                            tag[ kGAITesterTagStringLen + 1 ];
-       
-       require_action_quiet( inItemCount > 0, exit, err = kNoErr );
-       
-       // Limit address count to 64 because we use 64-bit bitmaps for keeping track of addresses.
-       
-       require_action_quiet( ( inAddressCount >= 1 ) && ( inAddressCount <= 64 ), exit, err = kCountErr );
-       require_action_quiet( ( inAliasCount >= 0 ) && ( inAliasCount <= INT32_MAX ), exit, err = kCountErr );
-       require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
-       
-       ptr = &name[ 0 ];
-       end = &name[ countof( name ) ];
-       
-       // Add Alias label.
-       
-       if(      inAliasCount == 1 ) SNPrintF_Add( &ptr, end, "alias." );
-       else if( inAliasCount >= 2 ) SNPrintF_Add( &ptr, end, "alias-%u.", inAliasCount );
-       
-       // Add Count label.
-       
-       SNPrintF_Add( &ptr, end, "count-%u.", inAddressCount );
-       
-       // Add TTL label.
-       
-       if( inTTL >= 0 ) SNPrintF_Add( &ptr, end, "ttl-%d.", inTTL );
-       
-       // Add Tag label.
-       
-       SNPrintF_Add( &ptr, end, "tag-%s.",
-               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
-       
-       // Add IPv4 or IPv6 label if necessary.
-       
-       if(      inHasAddrs == kGAITestAddrType_IPv4 ) SNPrintF_Add( &ptr, end, "ipv4." );
-       else if( inHasAddrs == kGAITestAddrType_IPv6 ) SNPrintF_Add( &ptr, end, "ipv6." );
-       
-       // Finally, add the d.test. labels.
-       
-       SNPrintF_Add( &ptr, end, "d.test." );
-       
-       // Create item.
-       
-       err = GAITestItemCreate( name, inAddressCount, inHasAddrs, inWantAddrs, inTimeLimitMs, &item );
-       require_noerr( err, exit );
-       
-       newItemList     = item;
-       itemPtr         = &item->next;
-       
-       // Create repeat items.
-       
-       for( i = 1; i < inItemCount; ++i )
-       {
-               err = GAITestItemDup( item, &item2 );
-               require_noerr( err, exit );
-               
-               *itemPtr        = item2;
-               itemPtr         = &item2->next;
-       }
-       
-       // Append to test case's item list.
-       
-       for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
-       *itemPtr        = newItemList;
-       newItemList     = NULL;
-       
-exit:
-       while( ( item = newItemList ) != NULL )
-       {
-               newItemList = item->next;
-               GAITestItemFree( item );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAITestCaseAddLocalHostItem
-//===========================================================================================================================
-
-static OSStatus
-       GAITestCaseAddLocalHostItem(
-               GAITestCase *   inCase,
-               GAITestAddrType inWantAddrs,
-               unsigned int    inTimeLimitMs,
-               unsigned int    inItemCount )
-{
-       OSStatus                        err;
-       GAITestItem *           item;
-       GAITestItem *           item2;
-       GAITestItem *           newItemList = NULL;
-       GAITestItem **          itemPtr;
-       unsigned int            i;
-       
-       require_action_quiet( inItemCount > 1, exit, err = kNoErr );
-       
-       err = GAITestItemCreate( "localhost.", 1, kGAITestAddrType_Both, inWantAddrs, inTimeLimitMs, &item );
-       require_noerr( err, exit );
-       
-       newItemList     = item;
-       itemPtr         = &item->next;
-       
-       // Create repeat items.
-       
-       for( i = 1; i < inItemCount; ++i )
-       {
-               err = GAITestItemDup( item, &item2 );
-               require_noerr( err, exit );
-               
-               *itemPtr        = item2;
-               itemPtr         = &item2->next;
-       }
-       
-       for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
-       *itemPtr        = newItemList;
-       newItemList     = NULL;
-       
-exit:
-       while( ( item = newItemList ) != NULL )
-       {
-               newItemList = item->next;
-               GAITestItemFree( item );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAITestItemCreate
-//===========================================================================================================================
-
-static OSStatus
-       GAITestItemCreate(
-               const char *    inName,
-               unsigned int    inAddressCount,
-               GAITestAddrType inHasAddrs,
-               GAITestAddrType inWantAddrs,
-               unsigned int    inTimeLimitMs,
-               GAITestItem **  outItem )
-{
-       OSStatus                        err;
-       GAITestItem *           obj = NULL;
-       
-       require_action_quiet( inAddressCount >= 1, exit, err = kCountErr );
-       require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
-       require_action_quiet( GAITestAddrTypeIsValid( inWantAddrs ), exit, err = kValueErr );
-       
-       obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name = strdup( inName );
-       require_action( obj->name, exit, err = kNoMemoryErr );
-       
-       obj->addressCount       = inAddressCount;
-       obj->hasV4                      = ( inHasAddrs  & kGAITestAddrType_IPv4 ) ? true : false;
-       obj->hasV6                      = ( inHasAddrs  & kGAITestAddrType_IPv6 ) ? true : false;
-       obj->wantV4                     = ( inWantAddrs & kGAITestAddrType_IPv4 ) ? true : false;
-       obj->wantV6                     = ( inWantAddrs & kGAITestAddrType_IPv6 ) ? true : false;
-       obj->error                      = kInProgressErr;
-       obj->timeLimitMs        = inTimeLimitMs;
-       
-       *outItem = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) GAITestItemFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAITestItemDup
-//===========================================================================================================================
-
-static OSStatus        GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem )
-{
-       OSStatus                        err;
-       GAITestItem *           obj;
-       
-       obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       *obj = *inItem;
-       obj->next = NULL;
-       if( inItem->name )
-       {
-               obj->name = strdup( inItem->name );
-               require_action( obj->name, exit, err = kNoMemoryErr );
-       }
-       
-       *outItem = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) GAITestItemFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     GAITestItemFree
-//===========================================================================================================================
-
-static void    GAITestItemFree( GAITestItem *inItem )
-{
-       ForgetMem( &inItem->name );
-       free( inItem );
-}
-
-//===========================================================================================================================
-//     MDNSDiscoveryTestCmd
-//===========================================================================================================================
-
-#define kMDNSDiscoveryTestFirstQueryTimeoutSecs                4
-
-typedef struct
-{
-       DNSServiceRef                   query;                                  // Reference to DNSServiceQueryRecord for replier's "about" TXT record.
-       dispatch_source_t               queryTimer;                             // Used to time out the "about" TXT record query.
-       NanoTime64                              startTime;                              // When the test started.
-       NanoTime64                              endTime;                                // When the test ended.
-       pid_t                                   replierPID;                             // PID of mDNS replier.
-       uint32_t                                ifIndex;                                // Index of interface to run the replier on.
-       unsigned int                    instanceCount;                  // Desired number of service instances.
-       unsigned int                    txtSize;                                // Desired size of each service instance's TXT record data.
-       unsigned int                    recordCountA;                   // Desired number of A records per replier hostname.
-       unsigned int                    recordCountAAAA;                // Desired number of AAAA records per replier hostname.
-       unsigned int                    maxDropCount;                   // Replier's --maxDropCount option argument.
-       double                                  ucastDropRate;                  // Replier's probability of dropping a unicast response.
-       double                                  mcastDropRate;                  // Replier's probability of dropping a multicast query or response.
-       Boolean                                 noAdditionals;                  // True if the replier is to not include additional records in responses.
-       Boolean                                 useIPv4;                                // True if the replier is to use IPv4.
-       Boolean                                 useIPv6;                                // True if the replier is to use IPv6.
-       Boolean                                 flushedCache;                   // True if mDNSResponder's record cache was flushed before testing.
-       char *                                  replierCommand;                 // Command used to run the replier.
-       char *                                  serviceType;                    // Type of services to browse for.
-       ServiceBrowserRef               browser;                                // Service browser.
-       unsigned int                    browseTimeSecs;                 // Amount of time to spend browsing in seconds.
-       const char *                    outputFilePath;                 // File to write test results to. If NULL, then write to stdout.
-       OutputFormatType                outputFormat;                   // Format of test results output.
-       Boolean                                 outputAppendNewline;    // True if a newline character should be appended to JSON output.
-       char                                    hostname[ 32 + 1 ];             // Base hostname that the replier is to use for instance and host names.
-       char                                    tag[ 4 + 1 ];                   // Tag that the replier is to use in its service types.
-       
-}      MDNSDiscoveryTestContext;
-
-static OSStatus        GetAnyMDNSInterface( char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex );
-static void            _MDNSDiscoveryTestFirstQueryTimeout( void *inContext );
-static void DNSSD_API
-       _MDNSDiscoveryTestAboutQueryCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static void
-       _MDNSDiscoveryTestServiceBrowserCallback(
-               ServiceBrowserResults * inResults,
-               OSStatus                                inError,
-               void *                                  inContext );
-static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen );
-
-static void    MDNSDiscoveryTestCmd( void )
-{
-       OSStatus                                                err;
-       MDNSDiscoveryTestContext *              context;
-       char                                                    queryName[ sizeof_field( MDNSDiscoveryTestContext, hostname ) + 15 ];
-       
-       context = (MDNSDiscoveryTestContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       err = CheckIntegerArgument( gMDNSDiscoveryTest_InstanceCount, "instance count", 1, UINT16_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSDiscoveryTest_TXTSize, "TXT size", 1, UINT16_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSDiscoveryTest_BrowseTimeSecs, "browse time (seconds)", 1, INT_MAX );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountA, "A record count", 0, 64 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountAAAA, "AAAA record count", 0, 64 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckDoubleArgument( gMDNSDiscoveryTest_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckDoubleArgument( gMDNSDiscoveryTest_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
-       require_noerr_quiet( err, exit );
-       
-       err = CheckIntegerArgument( gMDNSDiscoveryTest_MaxDropCount, "drop count", 0, 255 );
-       require_noerr_quiet( err, exit );
-       
-       context->replierPID                             = -1;
-       context->instanceCount                  = (unsigned int) gMDNSDiscoveryTest_InstanceCount;
-       context->txtSize                                = (unsigned int) gMDNSDiscoveryTest_TXTSize;
-       context->browseTimeSecs                 = (unsigned int) gMDNSDiscoveryTest_BrowseTimeSecs;
-       context->recordCountA                   = (unsigned int) gMDNSDiscoveryTest_RecordCountA;
-       context->recordCountAAAA                = (unsigned int) gMDNSDiscoveryTest_RecordCountAAAA;
-       context->ucastDropRate                  = gMDNSDiscoveryTest_UnicastDropRate;
-       context->mcastDropRate                  = gMDNSDiscoveryTest_MulticastDropRate;
-       context->maxDropCount                   = (unsigned int) gMDNSDiscoveryTest_MaxDropCount;
-       context->outputFilePath                 = gMDNSDiscoveryTest_OutputFilePath;
-       context->outputAppendNewline    = gMDNSDiscoveryTest_OutputAppendNewline ? true : false;
-       context->noAdditionals                  = gMDNSDiscoveryTest_NoAdditionals       ? true : false;
-       context->useIPv4                                = ( gMDNSDiscoveryTest_UseIPv4 || !gMDNSDiscoveryTest_UseIPv6 ) ? true : false;
-       context->useIPv6                                = ( gMDNSDiscoveryTest_UseIPv6 || !gMDNSDiscoveryTest_UseIPv4 ) ? true : false;
-       
-       if( gMDNSDiscoveryTest_Interface )
-       {
-               err = InterfaceIndexFromArgString( gMDNSDiscoveryTest_Interface, &context->ifIndex );
-               require_noerr_quiet( err, exit );
-       }
-       else
-       {
-               err = GetAnyMDNSInterface( NULL, &context->ifIndex );
-               require_noerr_quiet( err, exit );
-       }
-       
-       context->outputFormat = (OutputFormatType) CLIArgToValue( "format", gMDNSDiscoveryTest_OutputFormat, &err,
-               kOutputFormatStr_JSON,          kOutputFormatType_JSON,
-               kOutputFormatStr_XML,           kOutputFormatType_XML,
-               kOutputFormatStr_Binary,        kOutputFormatType_Binary,
-               NULL );
-       require_noerr_quiet( err, exit );
-       
-       if( gMDNSDiscoveryTest_FlushCache )
-       {
-               err = CheckRootUser();
-               require_noerr_quiet( err, exit );
-               
-               err = systemf( NULL, "killall -HUP mDNSResponder" );
-               require_noerr( err, exit );
-               sleep( 1 );
-               context->flushedCache = true;
-       }
-       
-       _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->hostname ) - 1,
-               context->hostname );
-       _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->tag ) - 1, context->tag );
-       
-       ASPrintF( &context->serviceType, "_t-%s-%u-%u._tcp", context->tag, context->txtSize, context->instanceCount );
-       require_action( context->serviceType, exit, err = kUnknownErr );
-       
-       err = ASPrintF( &context->replierCommand,
-               "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount %u "
-               "--countA %u --countAAAA %u --udrop %.1f --mdrop %.1f --maxDropCount %u %?s%?s%?s",
-               (int64_t) getpid(),
-               context->ifIndex,
-               context->hostname,
-               context->tag,
-               context->instanceCount,
-               context->recordCountA,
-               context->recordCountAAAA,
-               context->ucastDropRate,
-               context->mcastDropRate,
-               context->maxDropCount,
-               context->noAdditionals, " --noAdditionals",
-               context->useIPv4,               " --ipv4",
-               context->useIPv6,               " --ipv6" );
-       require_action_quiet( context->replierCommand, exit, err = kUnknownErr );
-       
-       err = SpawnCommand( &context->replierPID, "%s", context->replierCommand );
-       require_noerr_quiet( err, exit );
-       
-       // Query for the replier's about TXT record. A response means it's fully up and running.
-       
-       SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->hostname );
-       err = DNSServiceQueryRecord( &context->query, kDNSServiceFlagsForceMulticast, context->ifIndex, queryName,
-               kDNSServiceType_TXT, kDNSServiceClass_IN, _MDNSDiscoveryTestAboutQueryCallback, context );
-       require_noerr( err, exit );
-       
-       err = DNSServiceSetDispatchQueue( context->query, dispatch_get_main_queue() );
-       require_noerr( err, exit );
-       
-       err = DispatchTimerCreate( dispatch_time_seconds( kMDNSDiscoveryTestFirstQueryTimeoutSecs ),
-               DISPATCH_TIME_FOREVER, UINT64_C_safe( kMDNSDiscoveryTestFirstQueryTimeoutSecs ) * kNanosecondsPerSecond / 10, NULL,
-               _MDNSDiscoveryTestFirstQueryTimeout, NULL, context, &context->queryTimer );
-       require_noerr( err, exit );
-       dispatch_resume( context->queryTimer );
-       
-       context->startTime = NanoTimeGetCurrent();
-       dispatch_main();
-       
-exit:
-       exit( 1 );
-}
-
-//===========================================================================================================================
-//     _MDNSDiscoveryTestFirstQueryTimeout
-//===========================================================================================================================
-
-static void    _MDNSDiscoveryTestFirstQueryTimeout( void *inContext )
-{
-       MDNSDiscoveryTestContext * const                context = (MDNSDiscoveryTestContext *) inContext;
-       
-       dispatch_source_forget( &context->queryTimer );
-       
-       FPrintF( stderr, "error: Query for mdnsreplier's \"about\" TXT record timed out.\n" );
-       exit( 1 );
-}
-
-//===========================================================================================================================
-//     _MDNSDiscoveryTestAboutQueryCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _MDNSDiscoveryTestAboutQueryCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       OSStatus                                                                err;
-       MDNSDiscoveryTestContext * const                context = (MDNSDiscoveryTestContext *) inContext;
-       
-       Unused( inSDRef );
-       Unused( inInterfaceIndex );
-       Unused( inFullName );
-       Unused( inType );
-       Unused( inClass );
-       Unused( inRDataLen );
-       Unused( inRDataPtr );
-       Unused( inTTL );
-       
-       err = inError;
-       require_noerr( err, exit );
-       require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
-       
-       DNSServiceForget( &context->query );
-       dispatch_source_forget( &context->queryTimer );
-       
-       err = ServiceBrowserCreate( dispatch_get_main_queue(), 0, "local.", context->browseTimeSecs, false, &context->browser );
-       require_noerr( err, exit );
-       
-       err = ServiceBrowserAddServiceType( context->browser, context->serviceType );
-       require_noerr( err, exit );
-       
-       ServiceBrowserSetCallback( context->browser, _MDNSDiscoveryTestServiceBrowserCallback, context );
-       ServiceBrowserStart( context->browser );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     _MDNSDiscoveryTestServiceBrowserCallback
-//===========================================================================================================================
-
-#define kMDNSDiscoveryTestResultsKey_ReplierInfo                                       CFSTR( "replierInfo" )
-#define kMDNSDiscoveryTestResultsKey_StartTime                                         CFSTR( "startTime" )
-#define kMDNSDiscoveryTestResultsKey_EndTime                                           CFSTR( "endTime" )
-#define kMDNSDiscoveryTestResultsKey_BrowseTimeSecs                                    CFSTR( "browseTimeSecs" )
-#define kMDNSDiscoveryTestResultsKey_ServiceType                                       CFSTR( "serviceType" )
-#define kMDNSDiscoveryTestResultsKey_FlushedCache                                      CFSTR( "flushedCache" )
-#define kMDNSDiscoveryTestResultsKey_UnexpectedInstances                       CFSTR( "unexpectedInstances" )
-#define kMDNSDiscoveryTestResultsKey_MissingInstances                          CFSTR( "missingInstances" )
-#define kMDNSDiscoveryTestResultsKey_IncorrectInstances                                CFSTR( "incorrectInstances" )
-#define kMDNSDiscoveryTestResultsKey_Success                                           CFSTR( "success" )
-#define kMDNSDiscoveryTestResultsKey_TotalResolveTime                          CFSTR( "totalResolveTimeUs" )
-
-#define kMDNSDiscoveryTestReplierInfoKey_Command                                       CFSTR( "command" )
-#define kMDNSDiscoveryTestReplierInfoKey_InstanceCount                         CFSTR( "instanceCount" )
-#define kMDNSDiscoveryTestReplierInfoKey_TXTSize                                       CFSTR( "txtSize" )
-#define kMDNSDiscoveryTestReplierInfoKey_RecordCountA                          CFSTR( "recordCountA" )
-#define kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA                       CFSTR( "recordCountAAAA" )
-#define kMDNSDiscoveryTestReplierInfoKey_Hostname                                      CFSTR( "hostname" )
-#define kMDNSDiscoveryTestReplierInfoKey_NoAdditionals                         CFSTR( "noAdditionals" )
-#define kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate                       CFSTR( "ucastDropRate" )
-#define kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate                     CFSTR( "mcastDropRate" )
-#define kMDNSDiscoveryTestReplierInfoKey_MaxDropCount                          CFSTR( "maxDropCount" )
-
-#define kMDNSDiscoveryTestUnexpectedInstanceKey_Name                           CFSTR( "name" )
-#define kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex         CFSTR( "interfaceIndex" )
-
-#define kMDNSDiscoveryTestIncorrectInstanceKey_Name                                    CFSTR( "name" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve                      CFSTR( "didResolve" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname                     CFSTR( "badHostname" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_BadPort                         CFSTR( "badPort" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT                          CFSTR( "badTXT" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs         CFSTR( "unexpectedAddrs" )
-#define kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs                    CFSTR( "missingAddrs" )
-
-static void    _MDNSDiscoveryTestServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
-{
-       OSStatus                                                                err;
-       MDNSDiscoveryTestContext * const                context                 = (MDNSDiscoveryTestContext *) inContext;
-       const SBRDomain *                                               domain;
-       const SBRServiceType *                                  type;
-       const SBRServiceInstance *                              instance;
-       const SBRServiceInstance **                             instanceArray   = NULL;
-       const SBRIPAddress *                                    ipaddr;
-       size_t                                                                  hostnameLen;
-       const char *                                                    ptr;
-       const char *                                                    end;
-       unsigned int                                                    i;
-       uint32_t                                                                u32;
-       CFMutableArrayRef                                               unexpectedInstances;
-       CFMutableArrayRef                                               missingInstances;
-       CFMutableArrayRef                                               incorrectInstances;
-       CFMutableDictionaryRef                                  plist                   = NULL;
-       CFMutableDictionaryRef                                  badDict                 = NULL;
-       CFMutableArrayRef                                               unexpectedAddrs = NULL;
-       CFMutableArrayRef                                               missingAddrs    = NULL;
-       uint64_t                                                                maxResolveTimeUs;
-       int                                                                             success                 = false;
-       char                                                                    startTimeStr[ 32 ];
-       char                                                                    endTimeStr[ 32 ];
-       
-       context->endTime = NanoTimeGetCurrent();
-       
-       err = inError;
-       require_noerr( err, exit );
-       
-       _NanoTime64ToDateString( context->startTime, startTimeStr, sizeof( startTimeStr ) );
-       _NanoTime64ToDateString( context->endTime, endTimeStr, sizeof( endTimeStr ) );
-       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
-               "{"
-                       "%kO="
-                       "{"
-                               "%kO=%s"        // replierCommand
-                               "%kO=%lli"      // txtSize
-                               "%kO=%lli"      // instanceCount
-                               "%kO=%lli"      // recordCountA
-                               "%kO=%lli"      // recordCountAAAA
-                               "%kO=%s"        // hostname
-                               "%kO=%b"        // noAdditionals
-                               "%kO=%f"        // ucastDropRate
-                               "%kO=%f"        // mcastDropRate
-                               "%kO=%i"        // maxDropCount
-                       "}"
-                       "%kO=%s"        // startTime
-                       "%kO=%s"        // endTime
-                       "%kO=%lli"      // browseTimeSecs
-                       "%kO=%s"        // serviceType
-                       "%kO=%b"        // flushedCache
-                       "%kO=[%@]"      // unexpectedInstances
-                       "%kO=[%@]"      // missingInstances
-                       "%kO=[%@]"      // incorrectInstances
-               "}",
-               kMDNSDiscoveryTestResultsKey_ReplierInfo,
-               kMDNSDiscoveryTestReplierInfoKey_Command,                       context->replierCommand,
-               kMDNSDiscoveryTestReplierInfoKey_InstanceCount,         (int64_t) context->instanceCount,
-               kMDNSDiscoveryTestReplierInfoKey_TXTSize,                       (int64_t) context->txtSize,
-               kMDNSDiscoveryTestReplierInfoKey_RecordCountA,          (int64_t) context->recordCountA,
-               kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA,       (int64_t) context->recordCountAAAA,
-               kMDNSDiscoveryTestReplierInfoKey_Hostname,                      context->hostname,
-               kMDNSDiscoveryTestReplierInfoKey_NoAdditionals,         context->noAdditionals,
-               kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate,       context->ucastDropRate,
-               kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate,     context->mcastDropRate,
-               kMDNSDiscoveryTestReplierInfoKey_MaxDropCount,          context->maxDropCount,
-               kMDNSDiscoveryTestResultsKey_StartTime,                         startTimeStr,
-               kMDNSDiscoveryTestResultsKey_EndTime,                           endTimeStr,
-               kMDNSDiscoveryTestResultsKey_BrowseTimeSecs,            (int64_t) context->browseTimeSecs,
-               kMDNSDiscoveryTestResultsKey_ServiceType,                       context->serviceType,
-               kMDNSDiscoveryTestResultsKey_FlushedCache,                      context->flushedCache,
-               kMDNSDiscoveryTestResultsKey_UnexpectedInstances,       &unexpectedInstances,
-               kMDNSDiscoveryTestResultsKey_MissingInstances,          &missingInstances,
-               kMDNSDiscoveryTestResultsKey_IncorrectInstances,        &incorrectInstances );
-       require_noerr( err, exit );
-       
-       for( domain = inResults->domainList; domain && ( strcasecmp( domain->name, "local.") != 0 ); domain = domain->next ) {}
-       require_action( domain, exit, err = kInternalErr );
-       
-       for( type = domain->typeList; type && ( strcasecmp( type->name, context->serviceType ) != 0 ); type = type->next ) {}
-       require_action( type, exit, err = kInternalErr );
-       
-       instanceArray = (const SBRServiceInstance **) calloc( context->instanceCount, sizeof( *instanceArray ) );
-       require_action( instanceArray, exit, err = kNoMemoryErr );
-       
-       hostnameLen = strlen( context->hostname );
-       for( instance = type->instanceList; instance; instance = instance->next )
-       {
-               unsigned int            instanceNumber = 0;
-               
-               if( strcmp_prefix( instance->name, context->hostname ) == 0 )
-               {
-                       ptr = &instance->name[ hostnameLen ];
-                       if( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ) )
-                       {
-                               ptr += 2;
-                               for( end = ptr; isdigit_safe( *end ); ++end ) {}
-                               if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
-                               {
-                                       if( ( u32 >= 2 ) && ( u32 <= context->instanceCount ) && ( ptr[ 0 ] == ')' ) && ( ptr[ 1 ] == '\0' ) )
-                                       {
-                                               instanceNumber = u32;
-                                       }
-                               }
-                       }
-                       else if( *ptr == '\0' )
-                       {
-                               instanceNumber = 1;
-                       }
-               }
-               if( ( instanceNumber != 0 ) && ( instance->ifIndex == context->ifIndex ) )
-               {
-                       check( !instanceArray[ instanceNumber - 1 ] );
-                       instanceArray[ instanceNumber - 1 ] = instance;
-               }
-               else
-               {
-                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedInstances,
-                               "{"
-                                       "%kO=%s"
-                                       "%kO=%lli"
-                               "}",
-                               kMDNSDiscoveryTestUnexpectedInstanceKey_Name,                   instance->name,
-                               kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex, (int64_t) instance->ifIndex );
-                       require_noerr( err, exit );
-               }
-       }
-       
-       maxResolveTimeUs = 0;
-       for( i = 1; i <= context->instanceCount; ++i )
-       {
-               int             isHostnameValid;
-               int             isTXTValid;
-               
-               instance = instanceArray[ i - 1 ];
-               if( !instance )
-               {
-                       if( i == 1 )
-                       {
-                               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", context->hostname );
-                               require_noerr( err, exit );
-                       }
-                       else
-                       {
-                               char *          instanceName = NULL;
-                               
-                               ASPrintF( &instanceName, "%s (%u)", context->hostname, i );
-                               require_action( instanceName, exit, err = kUnknownErr );
-                               
-                               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", instanceName );
-                               free( instanceName );
-                               require_noerr( err, exit );
-                       }
-                       continue;
-               }
-               
-               if( !instance->hostname )
-               {
-                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, incorrectInstances,
-                               "{"
-                                       "%kO=%s"
-                                       "%kO=%b"
-                               "}",
-                               kMDNSDiscoveryTestIncorrectInstanceKey_Name,            instance->name,
-                               kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve,      false );
-                       require_noerr( err, exit );
-                       continue;
-               }
-               
-               badDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
-               require_action( badDict, exit, err = kNoMemoryErr );
-               
-               isHostnameValid = false;
-               if( strcmp_prefix( instance->hostname, context->hostname ) == 0 )
-               {
-                       ptr = &instance->hostname[ hostnameLen ];
-                       if( i == 1 )
-                       {
-                               if( strcmp( ptr, ".local." ) == 0 ) isHostnameValid = true;
-                       }
-                       else if( *ptr == '-' )
-                       {
-                               ++ptr;
-                               for( end = ptr; isdigit_safe( *end ); ++end ) {}
-                               if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
-                               {
-                                       if( ( u32 == i ) && ( strcmp( ptr, ".local." ) == 0 ) ) isHostnameValid = true;
-                               }
-                       }
-               }
-               if( !isHostnameValid )
-               {
-                       err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname, instance->hostname,
-                               kSizeCString );
-                       require_noerr( err, exit );
-               }
-               
-               if( instance->port != (uint16_t)( kMDNSReplierPortBase + context->txtSize ) )
-               {
-                       err = CFDictionarySetInt64( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadPort, instance->port );
-                       require_noerr( err, exit );
-               }
-               
-               isTXTValid = false;
-               if( instance->txtLen == context->txtSize )
-               {
-                       uint8_t         name[ kDomainNameLengthMax ];
-                       
-                       err = DomainNameFromString( name, instance->name, NULL );
-                       require_noerr( err, exit );
-                       
-                       err = DomainNameAppendString( name, type->name, NULL );
-                       require_noerr( err, exit );
-                       
-                       err = DomainNameAppendString( name, "local", NULL );
-                       require_noerr( err, exit );
-                       
-                       if( _MDNSDiscoveryTestTXTRecordIsValid( name, instance->txtPtr, instance->txtLen ) ) isTXTValid = true;
-               }
-               if( !isTXTValid )
-               {
-                       char *          hexStr = NULL;
-                       
-                       ASPrintF( &hexStr, "%.4H", instance->txtPtr, (int) instance->txtLen, (int) instance->txtLen );
-                       require_action( hexStr, exit, err = kUnknownErr );
-                       
-                       err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT, hexStr, kSizeCString );
-                       free( hexStr );
-                       require_noerr( err, exit );
-               }
-               
-               if( isHostnameValid )
-               {
-                       uint64_t                        addrV4Bitmap, addrV6Bitmap, bitmask, resolveTimeUs;
-                       unsigned int            j;
-                       uint8_t                         addrV4[ 4 ];
-                       uint8_t                         addrV6[ 16 ];
-                       
-                       if( context->recordCountA < 64 )        addrV4Bitmap = ( UINT64_C( 1 ) << context->recordCountA ) - 1;
-                       else                                                            addrV4Bitmap =  ~UINT64_C( 0 );
-                       
-                       if( context->recordCountAAAA < 64 ) addrV6Bitmap = ( UINT64_C( 1 ) << context->recordCountAAAA ) - 1;
-                       else                                                            addrV6Bitmap =  ~UINT64_C( 0 );
-                       
-                       addrV4[ 0 ] = 0;
-                       WriteBig16( &addrV4[ 1 ], i );
-                       addrV4[ 3 ] = 0;
-                       
-                       memcpy( addrV6, kMDNSReplierBaseAddrV6, 16 );
-                       WriteBig16( &addrV6[ 12 ], i );
-                       
-                       unexpectedAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-                       require_action( unexpectedAddrs, exit, err = kNoMemoryErr );
-                       
-                       resolveTimeUs = 0;
-                       for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
-                       {
-                               const uint8_t *         addrPtr;
-                               unsigned int            lsb;
-                               int                                     isAddrValid = false;
-                               
-                               if( ipaddr->sip.sa.sa_family == AF_INET )
-                               {
-                                       addrPtr = (const uint8_t *) &ipaddr->sip.v4.sin_addr.s_addr;
-                                       lsb             = addrPtr[ 3 ];
-                                       if( ( memcmp( addrPtr, addrV4, 3 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountA ) )
-                                       {
-                                               bitmask = UINT64_C( 1 ) << ( lsb - 1 );
-                                               addrV4Bitmap &= ~bitmask;
-                                               isAddrValid = true;
-                                       }
-                               }
-                               else if( ipaddr->sip.sa.sa_family == AF_INET6 )
-                               {
-                                       addrPtr = ipaddr->sip.v6.sin6_addr.s6_addr;
-                                       lsb             = addrPtr[ 15 ];
-                                       if( ( memcmp( addrPtr, addrV6, 15 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountAAAA ) )
-                                       {
-                                               bitmask = UINT64_C( 1 ) << ( lsb - 1 );
-                                               addrV6Bitmap &= ~bitmask;
-                                               isAddrValid = true;
-                                       }
-                               }
-                               if( isAddrValid )
-                               {
-                                       if( ipaddr->resolveTimeUs > resolveTimeUs ) resolveTimeUs = ipaddr->resolveTimeUs;
-                               }
-                               else
-                               {
-                                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedAddrs, "%##a", &ipaddr->sip );
-                                       require_noerr( err, exit );
-                               }
-                       }
-                       
-                       resolveTimeUs += ( instance->discoverTimeUs + instance->resolveTimeUs );
-                       if( resolveTimeUs > maxResolveTimeUs ) maxResolveTimeUs = resolveTimeUs;
-                       
-                       if( CFArrayGetCount( unexpectedAddrs ) > 0 )
-                       {
-                               CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs, unexpectedAddrs );
-                       }
-                       ForgetCF( &unexpectedAddrs );
-                       
-                       missingAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-                       require_action( missingAddrs, exit, err = kNoMemoryErr );
-                       
-                       for( j = 1; addrV4Bitmap != 0; ++j )
-                       {
-                               bitmask = UINT64_C( 1 ) << ( j - 1 );
-                               if( addrV4Bitmap & bitmask )
-                               {
-                                       addrV4Bitmap &= ~bitmask;
-                                       addrV4[ 3 ] = (uint8_t) j;
-                                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.4a", addrV4 );
-                                       require_noerr( err, exit );
-                               }
-                       }
-                       for( j = 1; addrV6Bitmap != 0; ++j )
-                       {
-                               bitmask = UINT64_C( 1 ) << ( j - 1 );
-                               if( addrV6Bitmap & bitmask )
-                               {
-                                       addrV6Bitmap &= ~bitmask;
-                                       addrV6[ 15 ] = (uint8_t) j;
-                                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.16a", addrV6 );
-                                       require_noerr( err, exit );
-                               }
-                       }
-                       
-                       if( CFArrayGetCount( missingAddrs ) > 0 )
-                       {
-                               CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs, missingAddrs );
-                       }
-                       ForgetCF( &missingAddrs );
-               }
-               
-               if( CFDictionaryGetCount( badDict ) > 0 )
-               {
-                       err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_Name, instance->name,
-                               kSizeCString );
-                       require_noerr( err, exit );
-                       
-                       CFDictionarySetBoolean( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve, true );
-                       CFArrayAppendValue( incorrectInstances, badDict );
-               }
-               ForgetCF( &badDict );
-       }
-       
-       if( ( CFArrayGetCount( unexpectedInstances ) == 0 ) &&
-               ( CFArrayGetCount( missingInstances )    == 0 ) &&
-               ( CFArrayGetCount( incorrectInstances )  == 0 ) )
-       {
-               err = CFDictionarySetInt64( plist, kMDNSDiscoveryTestResultsKey_TotalResolveTime, (int64_t) maxResolveTimeUs );
-               require_noerr( err, exit );
-               success = true;
-       }
-       else
-       {
-               success = false;
-       }
-       CFDictionarySetBoolean( plist, kMDNSDiscoveryTestResultsKey_Success, success );
-       
-       err = OutputPropertyList( plist, context->outputFormat, context->outputAppendNewline, context->outputFilePath );
-       require_noerr_quiet( err, exit );
-       
-exit:
-       ForgetCF( &context->browser );
-       if( context->replierPID != -1 )
-       {
-               kill( context->replierPID, SIGTERM );
-               context->replierPID = -1;
-       }
-       FreeNullSafe( instanceArray );
-       CFReleaseNullSafe( plist );
-       CFReleaseNullSafe( badDict );
-       CFReleaseNullSafe( unexpectedAddrs );
-       CFReleaseNullSafe( missingAddrs );
-       exit( err ? 1 : ( success ? 0 : 2 ) );
-}
-
-//===========================================================================================================================
-//     _MDNSDiscoveryTestTXTRecordIsValid
-//===========================================================================================================================
-
-static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen )
-{
-       uint32_t                        hash;
-       int                                     n;
-       const uint8_t *         ptr;
-       size_t                          i, wholeCount, remCount;
-       uint8_t                         txtStr[ 16 ];
-       
-       if( inTXTLen == 0 ) return( false );
-       
-       hash = FNV1( inRecordName, DomainNameLength( inRecordName ) );
-       
-       txtStr[ 0 ] = 15;
-       n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
-       check( n == 15 );
-       
-       ptr = inTXTPtr;
-       wholeCount = inTXTLen / 16;
-       for( i = 0; i < wholeCount; ++i )
-       {
-               if( memcmp( ptr, txtStr, 16 ) != 0 ) return( false );
-               ptr += 16;
-       }
-       
-       remCount = inTXTLen % 16;
-       if( remCount > 0 )
-       {
-               txtStr[ 0 ] = (uint8_t)( remCount - 1 );
-               if( memcmp( ptr, txtStr, remCount ) != 0 ) return( false );
-               ptr += remCount;
-       }
-       check( ptr == &inTXTPtr[ inTXTLen ] );
-       return( true );
-}
-
-//===========================================================================================================================
-//     DotLocalTestCmd
-//===========================================================================================================================
-
-#define kDotLocalTestPreparationTimeLimitSecs          5
-#define kDotLocalTestSubTestDurationSecs                       5
-
-// Constants for SRV record query subtest.
-
-#define kDotLocalTestSRV_Priority              1
-#define kDotLocalTestSRV_Weight                        0
-#define kDotLocalTestSRV_Port                  80
-#define kDotLocalTestSRV_TargetName            ( (const uint8_t *) "\x03" "www" "\x07" "example" "\x03" "com" )
-#define kDotLocalTestSRV_TargetStr             "www.example.com."
-#define kDotLocalTestSRV_ResultStr             "1 0 80 " kDotLocalTestSRV_TargetStr
-
-typedef enum
-{
-       kDotLocalTestState_Unset                                = 0,
-       kDotLocalTestState_Preparing                    = 1,
-       kDotLocalTestState_GAIMDNSOnly                  = 2,
-       kDotLocalTestState_GAIDNSOnly                   = 3,
-       kDotLocalTestState_GAIBoth                              = 4,
-       kDotLocalTestState_GAINeither                   = 5,
-       kDotLocalTestState_GAINoSuchRecord              = 6,
-       kDotLocalTestState_QuerySRV                             = 7,
-       kDotLocalTestState_Done                                 = 8
-       
-}      DotLocalTestState;
-
-typedef struct
-{
-       const char *                    testDesc;                       // Description of the current subtest.
-       char *                                  queryName;                      // Query name for GetAddrInfo or QueryRecord operation.
-       dispatch_source_t               timer;                          // Timer used for limiting the time for each subtest.
-       NanoTime64                              startTime;                      // Timestamp of when the subtest started.
-       NanoTime64                              endTime;                        // Timestamp of when the subtest ended.
-       CFMutableArrayRef               correctResults;         // Operation results that were expected.
-       CFMutableArrayRef               duplicateResults;       // Operation results that were expected, but were already received.
-       CFMutableArrayRef               unexpectedResults;      // Operation results that were unexpected.
-       OSStatus                                error;                          // Subtest's error code.
-       uint32_t                                addrDNSv4;                      // If hasDNSv4 is true, the expected DNS IPv4 address for queryName.
-       uint32_t                                addrMDNSv4;                     // If hasMDNSv4 is true, the expected MDNS IPv4 address for queryName.
-       uint8_t                                 addrDNSv6[ 16 ];        // If hasDNSv6 is true, the expected DNS IPv6 address for queryName.
-       uint8_t                                 addrMDNSv6[ 16 ];       // If hasMDNSv6 is true, the expected MDNS IPv6 address for queryName.
-       Boolean                                 hasDNSv4;                       // True if queryName has a DNS IPv4 address.
-       Boolean                                 hasDNSv6;                       // True if queryName has a DNS IPv6 address.
-       Boolean                                 hasMDNSv4;                      // True if queryName has an MDNS IPv4 address.
-       Boolean                                 hasMDNSv6;                      // True if queryName has an MDNS IPv6 address.
-       Boolean                                 needDNSv4;                      // True if operation is expecting, but hasn't received a DNS IPv4 result.
-       Boolean                                 needDNSv6;                      // True if operation is expecting, but hasn't received a DNS IPv6 result.
-       Boolean                                 needMDNSv4;                     // True if operation is expecting, but hasn't received an MDNS IPv4 result.
-       Boolean                                 needMDNSv6;                     // True if operation is expecting, but hasn't received an MDNS IPv6 result.
-       Boolean                                 needSRV;                        // True if operation is expecting, but hasn't received an SRV result.
-       
-}      DotLocalSubtest;
-
-typedef struct
-{
-       dispatch_source_t               timer;                          // Timer used for limiting the time for each state/subtest.
-       DotLocalSubtest *               subtest;                        // Current subtest's state.
-       DNSServiceRef                   connection;                     // Shared connection for DNS-SD operations.
-       DNSServiceRef                   op;                                     // Reference for the current DNS-SD operation.
-       DNSServiceRef                   op2;                            // Reference for mdnsreplier probe query used during preparing state.
-       DNSRecordRef                    localSOARef;            // Reference returned by DNSServiceRegisterRecord() for local. SOA record.
-       char *                                  replierCmd;                     // Command used to invoke the mdnsreplier.
-       char *                                  serverCmd;                      // Command used to invoke the test DNS server.
-       CFMutableArrayRef               reportsGAI;                     // Reports for subtests that use DNSServiceGetAddrInfo.
-       CFMutableArrayRef               reportsQuerySRV;        // Reports for subtests that use DNSServiceQueryRecord for SRV records.
-       NanoTime64                              startTime;                      // Timestamp for when the test started.
-       NanoTime64                              endTime;                        // Timestamp for when the test ended.
-       DotLocalTestState               state;                          // The test's current state.
-       pid_t                                   replierPID;                     // PID of spawned mdnsreplier.
-       pid_t                                   serverPID;                      // PID of spawned test DNS server.
-       uint32_t                                ifIndex;                        // Interface index used for mdnsreplier.
-       char *                                  outputFilePath;         // File to write test results to. If NULL, then write to stdout.
-       OutputFormatType                outputFormat;           // Format of test results output.
-       Boolean                                 appendNewline;          // True if a newline character should be appended to JSON output.
-       Boolean                                 registeredSOA;          // True if the dummy local. SOA record was successfully registered.
-       Boolean                                 serverIsReady;          // True if response was received for test DNS server probe query.
-       Boolean                                 replierIsReady;         // True if response was received for mdnsreplier probe query.
-       Boolean                                 testFailed;                     // True if at least one subtest failed.
-       char                                    labelStr[ 20 + 1 ];     // Unique label string used for for making the query names used by subtests.
-                                                                                               // The format of this string is "dotlocal-test-<six random chars>".
-}      DotLocalTestContext;
-
-static void    _DotLocalTestStateMachine( DotLocalTestContext *inContext );
-static void DNSSD_API
-       _DotLocalTestProbeQueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static void DNSSD_API
-       _DotLocalTestRegisterRecordCallback(
-               DNSServiceRef           inSDRef,
-               DNSRecordRef            inRecordRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               void *                          inContext );
-static void    _DotLocalTestTimerHandler( void *inContext );
-static void DNSSD_API
-       _DotLocalTestGAICallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static void DNSSD_API
-       _DotLocalTestQueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-
-static void    DotLocalTestCmd( void )
-{
-       OSStatus                                        err;
-       DotLocalTestContext *           context;
-       uint8_t *                                       rdataPtr;
-       size_t                                          rdataLen;
-       DNSServiceFlags                         flags;
-       char                                            queryName[ 64 ];
-       char                                            randBuf[ 6 + 1 ];       // Large enough for four and six character random strings below.
-       
-       context = (DotLocalTestContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->startTime      = NanoTimeGetCurrent();
-       context->endTime        = kNanoTime_Invalid;
-       
-       context->state = kDotLocalTestState_Preparing;
-       
-       if( gDotLocalTest_Interface )
-       {
-               err = InterfaceIndexFromArgString( gDotLocalTest_Interface, &context->ifIndex );
-               require_noerr_quiet( err, exit );
-       }
-       else
-       {
-               err = GetAnyMDNSInterface( NULL, &context->ifIndex );
-               require_noerr_quiet( err, exit );
-       }
-       
-       if( gDotLocalTest_OutputFilePath )
-       {
-               context->outputFilePath = strdup( gDotLocalTest_OutputFilePath );
-               require_action( context->outputFilePath, exit, err = kNoMemoryErr );
-       }
-       
-       context->outputFormat = (OutputFormatType) CLIArgToValue( "format", gDotLocalTest_OutputFormat, &err,
-               kOutputFormatStr_JSON,          kOutputFormatType_JSON,
-               kOutputFormatStr_XML,           kOutputFormatType_XML,
-               kOutputFormatStr_Binary,        kOutputFormatType_Binary,
-               NULL );
-       require_noerr_quiet( err, exit );
-       
-       context->appendNewline = gDotLocalTest_OutputAppendNewline ? true : false;
-       
-       context->reportsGAI = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-       require_action( context->reportsGAI, exit, err = kNoMemoryErr );
-       
-       context->reportsQuerySRV = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-       require_action( context->reportsQuerySRV, exit, err = kNoMemoryErr );
-       
-       SNPrintF( context->labelStr, sizeof( context->labelStr ), "dotlocal-test-%s",
-               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 6, randBuf ) );
-       
-       // Spawn an mdnsreplier.
-       
-       err = ASPrintF( &context->replierCmd,
-               "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount 2 --countA 1"
-               " --countAAAA 1",
-               (int64_t) getpid(), context->ifIndex, context->labelStr,
-               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 4, randBuf ) );
-       require_action_quiet( context->replierCmd, exit, err = kUnknownErr );
-       
-       err = SpawnCommand( &context->replierPID, "%s", context->replierCmd );
-       require_noerr( err, exit );
-       
-       // Spawn a test DNS server
-       
-       err = ASPrintF( &context->serverCmd,
-               "dnssdutil server --loopback --follow %lld --port 0 --defaultTTL 300 --domain %s.local.",
-               (int64_t) getpid(), context->labelStr );
-       require_action_quiet( context->serverCmd, exit, err = kUnknownErr );
-       
-       err = SpawnCommand( &context->serverPID, "%s", context->serverCmd );
-       require_noerr( err, exit );
-       
-       // Create a shared DNS-SD connection.
-       
-       err = DNSServiceCreateConnection( &context->connection );
-       require_noerr( err, exit );
-       
-       err = DNSServiceSetDispatchQueue( context->connection, dispatch_get_main_queue() );
-       require_noerr( err, exit );
-       
-       // Create probe query for DNS server, i.e., query for any name that has an A record.
-       
-       SNPrintF( queryName, sizeof( queryName ), "tag-dotlocal-test-probe.ipv4.%s.local.", context->labelStr );
-       
-       flags = kDNSServiceFlagsShareConnection;
-#if( TARGET_OS_WATCH )
-       flags |= kDNSServiceFlagsPathEvaluationDone;
-#endif
-       
-       context->op = context->connection;
-       err = DNSServiceQueryRecord( &context->op, flags, kDNSServiceInterfaceIndexAny, queryName, kDNSServiceType_A,
-               kDNSServiceClass_IN, _DotLocalTestProbeQueryRecordCallback, context );
-       require_noerr( err, exit );
-       
-       // Create probe query for mdnsreplier's "about" TXT record.
-       
-       SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->labelStr );
-       
-       flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsForceMulticast;
-#if( TARGET_OS_WATCH )
-       flags |= kDNSServiceFlagsPathEvaluationDone;
-#endif
-       
-       context->op2 = context->connection;
-       err = DNSServiceQueryRecord( &context->op2, flags, context->ifIndex, queryName, kDNSServiceType_TXT, kDNSServiceClass_IN,
-               _DotLocalTestProbeQueryRecordCallback, context );
-       require_noerr( err, exit );
-       
-       // Register a dummy local. SOA record.
-       
-       err = CreateSOARecordData( kRootLabel, kRootLabel, 1976040101, 1 * kSecondsPerDay, 2 * kSecondsPerHour,
-               1000 * kSecondsPerHour, 2 * kSecondsPerDay, &rdataPtr, &rdataLen );
-       require_noerr( err, exit );
-       
-       err = DNSServiceRegisterRecord( context->connection, &context->localSOARef, kDNSServiceFlagsUnique,
-               kDNSServiceInterfaceIndexLocalOnly, "local.", kDNSServiceType_SOA, kDNSServiceClass_IN, 1,
-               rdataPtr, 1 * kSecondsPerHour, _DotLocalTestRegisterRecordCallback, context );
-       require_noerr( err, exit );
-       
-       // Start timer for probe responses and SOA record registration.
-       
-       err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestPreparationTimeLimitSecs ),
-               INT64_C_safe( kDotLocalTestPreparationTimeLimitSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
-               _DotLocalTestTimerHandler, context, &context->timer );
-       require_noerr( err, exit );
-       dispatch_resume( context->timer );
-       
-       dispatch_main();
-       
-exit:
-       if( err ) ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-//     _DotLocalTestStateMachine
-//===========================================================================================================================
-
-static OSStatus        _DotLocalSubtestCreate( DotLocalSubtest **outSubtest );
-static void            _DotLocalSubtestFree( DotLocalSubtest *inSubtest );
-static OSStatus        _DotLocalTestStartSubtest( DotLocalTestContext *inContext );
-static OSStatus        _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext );
-static void            _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext ) ATTRIBUTE_NORETURN;
-
-static void    _DotLocalTestStateMachine( DotLocalTestContext *inContext )
-{
-       OSStatus                                err;
-       DotLocalTestState               nextState;
-       
-       DNSServiceForget( &inContext->op );
-       DNSServiceForget( &inContext->op2 );
-       dispatch_source_forget( &inContext->timer );
-       
-       switch( inContext->state )
-       {
-               case kDotLocalTestState_Preparing:                      nextState = kDotLocalTestState_GAIMDNSOnly;             break;
-               case kDotLocalTestState_GAIMDNSOnly:            nextState = kDotLocalTestState_GAIDNSOnly;              break;
-               case kDotLocalTestState_GAIDNSOnly:                     nextState = kDotLocalTestState_GAIBoth;                 break;
-               case kDotLocalTestState_GAIBoth:                        nextState = kDotLocalTestState_GAINeither;              break;
-               case kDotLocalTestState_GAINeither:                     nextState = kDotLocalTestState_GAINoSuchRecord; break;
-               case kDotLocalTestState_GAINoSuchRecord:        nextState = kDotLocalTestState_QuerySRV;                break;
-               case kDotLocalTestState_QuerySRV:                       nextState = kDotLocalTestState_Done;                    break;
-               default:                                                                        err = kStateErr;                                                                goto exit;
-       }
-       
-       if( inContext->state == kDotLocalTestState_Preparing )
-       {
-               if( !inContext->registeredSOA || !inContext->serverIsReady || !inContext->replierIsReady )
-               {
-                       FPrintF( stderr, "Preparation timed out: Registered SOA? %s. Server ready? %s. mdnsreplier ready? %s.\n",
-                               YesNoStr( inContext->registeredSOA ),
-                               YesNoStr( inContext->serverIsReady ),
-                               YesNoStr( inContext->replierIsReady ) );
-                       err = kNotPreparedErr;
-                       goto exit;
-               }
-       }
-       else
-       {
-               err = _DotLocalTestFinalizeSubtest( inContext );
-               require_noerr( err, exit );
-       }
-       
-       inContext->state = nextState;
-       if( inContext->state == kDotLocalTestState_Done ) _DotLocalTestFinalizeAndExit( inContext );
-       err = _DotLocalTestStartSubtest( inContext );
-       
-exit:
-       if( err ) ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-//     _DotLocalSubtestCreate
-//===========================================================================================================================
-
-static OSStatus        _DotLocalSubtestCreate( DotLocalSubtest **outSubtest )
-{
-       OSStatus                                err;
-       DotLocalSubtest *               obj;
-       
-       obj = (DotLocalSubtest *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->correctResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-       require_action( obj->correctResults, exit, err = kNoMemoryErr );
-       
-       obj->duplicateResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-       require_action( obj->duplicateResults, exit, err = kNoMemoryErr );
-       
-       obj->unexpectedResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
-       require_action( obj->unexpectedResults, exit, err = kNoMemoryErr );
-       
-       *outSubtest = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) _DotLocalSubtestFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _DotLocalSubtestFree
-//===========================================================================================================================
-
-static void    _DotLocalSubtestFree( DotLocalSubtest *inSubtest )
-{
-       ForgetMem( &inSubtest->queryName );
-       ForgetCF( &inSubtest->correctResults );
-       ForgetCF( &inSubtest->duplicateResults );
-       ForgetCF( &inSubtest->unexpectedResults );
-       free( inSubtest );
-}
-
-//===========================================================================================================================
-//     _DotLocalTestStartSubtest
-//===========================================================================================================================
-
-static OSStatus        _DotLocalTestStartSubtest( DotLocalTestContext *inContext )
-{
-       OSStatus                                err;
-       DotLocalSubtest *               subtest = NULL;
-       DNSServiceRef                   op              = NULL;
-       DNSServiceFlags                 flags;
-       
-       err = _DotLocalSubtestCreate( &subtest );
-       require_noerr( err, exit );
-       
-       if( inContext->state == kDotLocalTestState_GAIMDNSOnly )
-       {
-               ASPrintF( &subtest->queryName, "%s-2.local.", inContext->labelStr );
-               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-               
-               subtest->hasMDNSv4 = subtest->needMDNSv4 = true;
-               subtest->hasMDNSv6 = subtest->needMDNSv6 = true;
-               
-               subtest->addrMDNSv4 = htonl( 0x00000201 );                                      // 0.0.2.1
-               memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 );      // 2001:db8:2::2:1
-               subtest->addrMDNSv6[ 13 ] = 2;
-               subtest->addrMDNSv6[ 15 ] = 1;
-               
-               subtest->testDesc = kDotLocalTestSubtestDesc_GAIMDNSOnly;
-       }
-       
-       else if( inContext->state == kDotLocalTestState_GAIDNSOnly )
-       {
-               ASPrintF( &subtest->queryName, "tag-dns-only.%s.local.", inContext->labelStr );
-               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-               
-               subtest->hasDNSv4 = subtest->needDNSv4 = true;
-               subtest->hasDNSv6 = subtest->needDNSv6 = true;
-               
-               subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 );         // 203.0.113.1
-               memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 );         // 2001:db8:1::1
-               subtest->addrDNSv6[ 15 ] = 1;
-               
-               subtest->testDesc = kDotLocalTestSubtestDesc_GAIDNSOnly;
-       }
-       
-       else if( inContext->state == kDotLocalTestState_GAIBoth )
-       {
-               ASPrintF( &subtest->queryName, "%s.local.", inContext->labelStr );
-               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-               
-               subtest->hasDNSv4       = subtest->needDNSv4    = true;
-               subtest->hasDNSv6       = subtest->needDNSv6    = true;
-               subtest->hasMDNSv4      = subtest->needMDNSv4   = true;
-               subtest->hasMDNSv6      = subtest->needMDNSv6   = true;
-               
-               subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 );         // 203.0.113.1
-               memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 );         // 2001:db8:1::1
-               subtest->addrDNSv6[ 15 ] = 1;
-               
-               subtest->addrMDNSv4 = htonl( 0x00000101 );                                      // 0.0.1.1
-               memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 );      // 2001:db8:2::1:1
-               subtest->addrMDNSv6[ 13 ] = 1;
-               subtest->addrMDNSv6[ 15 ] = 1;
-               
-               subtest->testDesc = kDotLocalTestSubtestDesc_GAIBoth;
-       }
-       
-       else if( inContext->state == kDotLocalTestState_GAINeither )
-       {
-               ASPrintF( &subtest->queryName, "doesnotexit-%s.local.", inContext->labelStr );
-               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-               
-               subtest->testDesc = kDotLocalTestSubtestDesc_GAINeither;
-       }
-       
-       else if( inContext->state == kDotLocalTestState_GAINoSuchRecord )
-       {
-               ASPrintF( &subtest->queryName, "doesnotexit-dns.%s.local.", inContext->labelStr );
-               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-               
-               subtest->hasDNSv4 = subtest->needDNSv4 = true;
-               subtest->hasDNSv6 = subtest->needDNSv6 = true;
-               subtest->testDesc = kDotLocalTestSubtestDesc_GAINoSuchRecord;
-       }
-       
-       else if( inContext->state == kDotLocalTestState_QuerySRV )
-       {
-               ASPrintF( &subtest->queryName, "_http._tcp.srv-%u-%u-%u.%s%s.local.",
-                       kDotLocalTestSRV_Priority, kDotLocalTestSRV_Weight, kDotLocalTestSRV_Port, kDotLocalTestSRV_TargetStr,
-                       inContext->labelStr );
-               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
-               
-               subtest->needSRV        = true;
-               subtest->testDesc       = kDotLocalTestSubtestDesc_QuerySRV;
-       }
-       
-       else
-       {
-               err = kStateErr;
-               goto exit;
-       }
-       
-       // Start new operation.
-       
-       flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
-#if( TARGET_OS_WATCH )
-       flags |= kDNSServiceFlagsPathEvaluationDone;
-#endif
-       
-       subtest->startTime      = NanoTimeGetCurrent();
-       subtest->endTime        = kNanoTime_Invalid;
-       
-       if( inContext->state == kDotLocalTestState_QuerySRV )
-       {
-               op = inContext->connection;
-               err = DNSServiceQueryRecord( &op, flags, kDNSServiceInterfaceIndexAny, subtest->queryName,
-                       kDNSServiceType_SRV, kDNSServiceClass_IN, _DotLocalTestQueryRecordCallback, inContext );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               op = inContext->connection;
-               err = DNSServiceGetAddrInfo( &op, flags, kDNSServiceInterfaceIndexAny,
-                       kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, subtest->queryName, _DotLocalTestGAICallback, inContext );
-               require_noerr( err, exit );
-       }
-       
-       // Start timer.
-       
-       check( !inContext->timer );
-       err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestSubTestDurationSecs ),
-               INT64_C_safe( kDotLocalTestSubTestDurationSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
-               _DotLocalTestTimerHandler, inContext, &inContext->timer );
-       require_noerr( err, exit );
-       dispatch_resume( inContext->timer );
-       
-       check( !inContext->op );
-       inContext->op = op;
-       op = NULL;
-       
-       check( !inContext->subtest );
-       inContext->subtest = subtest;
-       subtest = NULL;
-       
-exit:
-       if( subtest )   _DotLocalSubtestFree( subtest );
-       if( op )                DNSServiceRefDeallocate( op );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _DotLocalTestFinalizeSubtest
-//===========================================================================================================================
-
-#define kDotLocalTestReportKey_StartTime                               CFSTR( "startTime" )            // String.
-#define kDotLocalTestReportKey_EndTime                                 CFSTR( "endTime" )                      // String.
-#define kDotLocalTestReportKey_Success                                 CFSTR( "success" )                      // Boolean.
-#define kDotLocalTestReportKey_MDNSReplierCmd                  CFSTR( "replierCmd" )           // String.
-#define kDotLocalTestReportKey_DNSServerCmd                            CFSTR( "serverCmd" )            // String.
-#define kDotLocalTestReportKey_GetAddrInfoTests                        CFSTR( "testsGAI" )                     // Array of Dictionaries.
-#define kDotLocalTestReportKey_QuerySRVTests                   CFSTR( "testsQuerySRV" )        // Array of Dictionaries.
-#define kDotLocalTestReportKey_Description                             CFSTR( "description" )          // String.
-#define kDotLocalTestReportKey_QueryName                               CFSTR( "queryName" )            // String.
-#define kDotLocalTestReportKey_Error                                   CFSTR( "error" )                        // Integer.
-#define kDotLocalTestReportKey_Results                                 CFSTR( "results" )                      // Dictionary of Arrays.
-#define kDotLocalTestReportKey_CorrectResults                  CFSTR( "correct" )                      // Array of Strings
-#define kDotLocalTestReportKey_DuplicateResults                        CFSTR( "duplicates" )           // Array of Strings.
-#define kDotLocalTestReportKey_UnexpectedResults               CFSTR( "unexpected" )           // Array of Strings.
-#define kDotLocalTestReportKey_MissingResults                  CFSTR( "missing" )                      // Array of Strings.
-
-static OSStatus        _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext )
-{
-       OSStatus                                        err;
-       DotLocalSubtest *                       subtest;
-       CFMutableDictionaryRef          reportDict;
-       CFMutableDictionaryRef          resultsDict;
-       CFMutableArrayRef                       missingResults, reportArray;
-       char                                            startTimeStr[ 32 ];
-       char                                            endTimeStr[ 32 ];
-       
-       subtest = inContext->subtest;
-       inContext->subtest = NULL;
-       
-       subtest->endTime = NanoTimeGetCurrent();
-       _NanoTime64ToDateString( subtest->startTime, startTimeStr, sizeof( startTimeStr ) );
-       _NanoTime64ToDateString( subtest->endTime, endTimeStr, sizeof( endTimeStr ) );
-       
-       reportDict = NULL;
-       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &reportDict,
-               "{"
-                       "%kO=%s"        // startTime
-                       "%kO=%s"        // endTime
-                       "%kO=%s"        // queryName
-                       "%kO=%s"        // description
-                       "%kO={%@}"      // results
-               "}",
-               kDotLocalTestReportKey_StartTime,       startTimeStr,
-               kDotLocalTestReportKey_EndTime,         endTimeStr,
-               kDotLocalTestReportKey_QueryName,       subtest->queryName,
-               kDotLocalTestReportKey_Description,     subtest->testDesc,
-               kDotLocalTestReportKey_Results,         &resultsDict );
-       require_noerr( err, exit );
-       
-       missingResults = NULL;
-       switch( inContext->state )
-       {
-               case kDotLocalTestState_GAIMDNSOnly:
-               case kDotLocalTestState_GAIDNSOnly:
-               case kDotLocalTestState_GAIBoth:
-               case kDotLocalTestState_GAINeither:
-                       if( subtest->needDNSv4 || subtest->needDNSv6 || subtest->needMDNSv4 || subtest->needMDNSv6 )
-                       {
-                               err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
-                                       "["
-                                               "%.4a"  // Expected DNS IPv4 address
-                                               "%.16a" // Expected DNS IPv6 address
-                                               "%.4a"  // Expected MDNS IPv4 address
-                                               "%.16a" // Expected MDNS IPv6 address
-                                       "]",
-                                       subtest->needDNSv4  ? &subtest->addrDNSv4  : NULL,
-                                       subtest->needDNSv6  ?  subtest->addrDNSv6  : NULL,
-                                       subtest->needMDNSv4 ? &subtest->addrMDNSv4 : NULL,
-                                       subtest->needMDNSv6 ?  subtest->addrMDNSv6 : NULL );
-                               require_noerr( err, exit );
-                       }
-                       break;
-               
-               case kDotLocalTestState_QuerySRV:
-                       if( subtest->needSRV )
-                       {
-                               err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
-                                       "["
-                                               "%s"    // Expected SRV record data as a string.
-                                       "]",
-                                       kDotLocalTestSRV_ResultStr );
-                               require_noerr( err, exit );
-                       }
-                       break;
-               
-               case kDotLocalTestState_GAINoSuchRecord:
-                       if( subtest->needDNSv4 || subtest->needDNSv6 )
-                       {
-                               err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
-                                       "["
-                                               "%s" // No Such Record (A)
-                                               "%s" // No Such Record (AAAA)
-                                       "]",
-                                       subtest->needDNSv4 ? kNoSuchRecordAStr    : NULL,
-                                       subtest->needDNSv6 ? kNoSuchRecordAAAAStr : NULL );
-                               require_noerr( err, exit );
-                       }
-                       break;
-               
-               default:
-                       err = kStateErr;
-                       goto exit;
-       }
-       
-       CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_CorrectResults, subtest->correctResults );
-       
-       if( missingResults )
-       {
-               CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_MissingResults, missingResults );
-               ForgetCF( &missingResults );
-               if( !subtest->error ) subtest->error = kNotFoundErr;
-       }
-       
-       if( CFArrayGetCount( subtest->unexpectedResults ) > 0 )
-       {
-               CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_UnexpectedResults, subtest->unexpectedResults );
-               if( !subtest->error ) subtest->error = kUnexpectedErr;
-       }
-       
-       if( CFArrayGetCount( subtest->duplicateResults ) > 0 )
-       {
-               CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_DuplicateResults, subtest->duplicateResults );
-               if( !subtest->error ) subtest->error = kDuplicateErr;
-       }
-       
-       if( subtest->error ) inContext->testFailed = true;
-       err = CFDictionarySetInt64( reportDict, kDotLocalTestReportKey_Error, subtest->error );
-       require_noerr( err, exit );
-       
-       reportArray = ( inContext->state == kDotLocalTestState_QuerySRV ) ? inContext->reportsQuerySRV : inContext->reportsGAI;
-       CFArrayAppendValue( reportArray, reportDict );
-       
-exit:
-       _DotLocalSubtestFree( subtest );
-       CFReleaseNullSafe( reportDict );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _DotLocalTestFinalizeAndExit
-//===========================================================================================================================
-
-static void    _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext )
-{
-       OSStatus                                err;
-       CFPropertyListRef               plist;
-       char                                    startTimeStr[ 32 ];
-       char                                    endTimeStr[ 32 ];
-       
-       check( !inContext->subtest );
-       inContext->endTime = NanoTimeGetCurrent();
-       
-       if( inContext->replierPID != -1 )
-       {
-               kill( inContext->replierPID, SIGTERM );
-               inContext->replierPID = -1;
-       }
-       if( inContext->serverPID != -1 )
-       {
-               kill( inContext->serverPID, SIGTERM );
-               inContext->serverPID = -1;
-       }
-       err = DNSServiceRemoveRecord( inContext->connection, inContext->localSOARef, 0 );
-       require_noerr( err, exit );
-       
-       _NanoTime64ToDateString( inContext->startTime, startTimeStr, sizeof( startTimeStr ) );
-       _NanoTime64ToDateString( inContext->endTime, endTimeStr, sizeof( endTimeStr ) );
-       
-       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
-               "{"
-                       "%kO=%s"        // startTime
-                       "%kO=%s"        // endTime
-                       "%kO=%O"        // testsGAI
-                       "%kO=%O"        // testsQuerySRV
-                       "%kO=%b"        // success
-                       "%kO=%s"        // replierCmd
-                       "%kO=%s"        // serverCmd
-               "}",
-               kDotLocalTestReportKey_StartTime,                       startTimeStr,
-               kDotLocalTestReportKey_EndTime,                         endTimeStr,
-               kDotLocalTestReportKey_GetAddrInfoTests,        inContext->reportsGAI,
-               kDotLocalTestReportKey_QuerySRVTests,           inContext->reportsQuerySRV,
-               kDotLocalTestReportKey_Success,                         inContext->testFailed ? false : true,
-               kDotLocalTestReportKey_MDNSReplierCmd,          inContext->replierCmd,
-               kDotLocalTestReportKey_DNSServerCmd,            inContext->serverCmd );
-       require_noerr( err, exit );
-       
-       ForgetCF( &inContext->reportsGAI );
-       ForgetCF( &inContext->reportsQuerySRV );
-       
-       err = OutputPropertyList( plist, inContext->outputFormat, inContext->appendNewline, inContext->outputFilePath );
-       CFRelease( plist );
-       require_noerr( err, exit );
-       
-       exit( inContext->testFailed ? 2 : 0 );
-       
-exit:
-       ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-//     _DotLocalTestProbeQueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _DotLocalTestProbeQueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       DotLocalTestContext * const             context = (DotLocalTestContext *) inContext;
-       
-       Unused( inInterfaceIndex );
-       Unused( inFullName );
-       Unused( inType );
-       Unused( inClass );
-       Unused( inRDataLen );
-       Unused( inRDataPtr );
-       Unused( inTTL );
-       
-       check( context->state == kDotLocalTestState_Preparing );
-       
-       require_quiet( ( inFlags & kDNSServiceFlagsAdd ) && !inError, exit );
-       
-       if( inSDRef == context->op )
-       {
-               DNSServiceForget( &context->op );
-               context->serverIsReady = true;
-       }
-       else if( inSDRef == context->op2 )
-       {
-               DNSServiceForget( &context->op2 );
-               context->replierIsReady = true;
-       }
-       
-       if( context->registeredSOA && context->serverIsReady && context->replierIsReady )
-       {
-               _DotLocalTestStateMachine( context );
-       }
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     _DotLocalTestRegisterRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _DotLocalTestRegisterRecordCallback(
-               DNSServiceRef           inSDRef,
-               DNSRecordRef            inRecordRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               void *                          inContext )
-{
-       DotLocalTestContext * const             context = (DotLocalTestContext *) inContext;
-       
-       Unused( inSDRef );
-       Unused( inRecordRef );
-       Unused( inFlags );
-       
-       if( inError ) ErrQuit( 1, "error: local. SOA record registration failed: %#m\n", inError );
-       
-       if( !context->registeredSOA )
-       {
-               context->registeredSOA = true;
-               if( context->serverIsReady && context->replierIsReady ) _DotLocalTestStateMachine( context );
-       }
-}
-
-//===========================================================================================================================
-//     _DotLocalTestTimerHandler
-//===========================================================================================================================
-
-static void    _DotLocalTestTimerHandler( void *inContext )
-{
-       _DotLocalTestStateMachine( (DotLocalTestContext *) inContext );
-}
-
-//===========================================================================================================================
-//     _DotLocalTestGAICallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _DotLocalTestGAICallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       OSStatus                                                err;
-       DotLocalTestContext * const             context = (DotLocalTestContext *) inContext;
-       DotLocalSubtest * const                 subtest = context->subtest;
-       const sockaddr_ip * const               sip             = (const sockaddr_ip *) inSockAddr;
-       
-       Unused( inSDRef );
-       Unused( inInterfaceIndex );
-       Unused( inHostname );
-       Unused( inTTL );
-       
-       require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
-       require_action_quiet( ( sip->sa.sa_family == AF_INET ) || ( sip->sa.sa_family == AF_INET6 ), exit, err = kTypeErr );
-       
-       if( context->state == kDotLocalTestState_GAINoSuchRecord )
-       {
-               if( inError == kDNSServiceErr_NoSuchRecord )
-               {
-                       CFMutableArrayRef               array = NULL;   
-                       const char *                    noSuchRecordStr;
-                       
-                       if( sip->sa.sa_family == AF_INET )
-                       {
-                               array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
-                               subtest->needDNSv4 = false;
-                               
-                               noSuchRecordStr = kNoSuchRecordAStr;
-                       }
-                       else
-                       {
-                               array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
-                               subtest->needDNSv6 = false;
-                               
-                               noSuchRecordStr = kNoSuchRecordAAAAStr;
-                       }
-                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", noSuchRecordStr );
-                       require_noerr( err, fatal );
-               }
-               else if( !inError )
-               {
-                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%##a", sip );
-                       require_noerr( err, fatal );
-               }
-               else
-               {
-                       err = inError;
-                       goto exit;
-               }
-       }
-       else
-       {
-               if( !inError )
-               {
-                       CFMutableArrayRef               array = NULL;   
-                       
-                       if( sip->sa.sa_family == AF_INET )
-                       {
-                               const uint32_t          addrV4 = sip->v4.sin_addr.s_addr;
-                               
-                               if( subtest->hasDNSv4 && ( addrV4 == subtest->addrDNSv4 ) )
-                               {
-                                       array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
-                                       subtest->needDNSv4 = false;
-                               }
-                               else if( subtest->hasMDNSv4 && ( addrV4 == subtest->addrMDNSv4 ) )
-                               {
-                                       array = subtest->needMDNSv4 ? subtest->correctResults : subtest->duplicateResults;
-                                       subtest->needMDNSv4 = false;
-                               }
-                       }
-                       else
-                       {
-                               const uint8_t * const           addrV6 = sip->v6.sin6_addr.s6_addr;
-                               
-                               if( subtest->hasDNSv6 && ( memcmp( addrV6, subtest->addrDNSv6, 16 ) == 0 ) )
-                               {
-                                       array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
-                                       subtest->needDNSv6 = false;
-                               }
-                               else if( subtest->hasMDNSv6 && ( memcmp( addrV6, subtest->addrMDNSv6, 16 ) == 0 ) )
-                               {
-                                       array = subtest->needMDNSv6 ? subtest->correctResults : subtest->duplicateResults;
-                                       subtest->needMDNSv6 = false;
-                               }
-                       }
-                       if( !array ) array = subtest->unexpectedResults;
-                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%##a", sip );
-                       require_noerr( err, fatal );
-               }
-               else if( inError == kDNSServiceErr_NoSuchRecord )
-               {
-                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%s",
-                               ( sip->sa.sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr );
-                       require_noerr( err, fatal );
-               }
-               else
-               {
-                       err = inError;
-                       goto exit;
-               }
-       }
-       
-exit:
-       if( err )
-       {
-               subtest->error = err;
-               _DotLocalTestStateMachine( context );
-       }
-       return;
-       
-fatal:
-       ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-//     _DotLocalTestQueryRecordCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _DotLocalTestQueryRecordCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       OSStatus                                                                err;
-       DotLocalTestContext * const                             context = (DotLocalTestContext *) inContext;
-       DotLocalSubtest * const                                 subtest = context->subtest;
-       const SRVRecordDataFixedFields *                fields;
-       const uint8_t *                                                 target;
-       const uint8_t *                                                 ptr;
-       const uint8_t *                                                 end;
-       char *                                                                  rdataStr;
-       unsigned int                                                    priority, weight, port;
-       CFMutableArrayRef                                               array;
-       
-       Unused( inSDRef );
-       Unused( inInterfaceIndex );
-       Unused( inFullName );
-       Unused( inTTL );
-       
-       check( context->state == kDotLocalTestState_QuerySRV );
-       
-       err = inError;
-       require_noerr_quiet( err, exit );
-       require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
-       require_action_quiet( ( inType == kDNSServiceType_SRV ) && ( inClass == kDNSServiceClass_IN ), exit, err = kTypeErr );
-       require_action_quiet( inRDataLen > sizeof( SRVRecordDataFixedFields ), exit, err = kSizeErr );
-       
-       fields  = (const SRVRecordDataFixedFields *) inRDataPtr;
-       SRVRecordDataFixedFieldsGet( fields, &priority, &weight, &port );
-       target  = (const uint8_t *) &fields[ 1 ];
-       end             = ( (const uint8_t *) inRDataPtr ) + inRDataLen;
-       for( ptr = target; ( ptr < end ) && ( *ptr != 0 ); ptr += ( 1 + *ptr ) ) {}
-       
-       if( ( priority == kDotLocalTestSRV_Priority ) &&
-               ( weight   == kDotLocalTestSRV_Weight )   &&
-               ( port     == kDotLocalTestSRV_Port )     &&
-               ( ptr < end ) && DomainNameEqual( target, kDotLocalTestSRV_TargetName ) )
-       {
-               array = subtest->needSRV ? subtest->correctResults : subtest->duplicateResults;
-               subtest->needSRV = false;
-       }
-       else
-       {
-               array = subtest->unexpectedResults;
-       }
-       
-       rdataStr = NULL;
-       DNSRecordDataToString( inRDataPtr, inRDataLen, kDNSServiceType_SRV, NULL, 0, &rdataStr );
-       if( !rdataStr )
-       {
-               ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, inRDataLen );
-               require_action( rdataStr, fatal, err = kNoMemoryErr );
-       }
-       
-       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", rdataStr );
-       free( rdataStr );
-       require_noerr( err, fatal );
-       
-exit:
-       if( err )
-       {
-               subtest->error = err;
-               _DotLocalTestStateMachine( context );
-       }
-       return;
-       
-fatal:
-       ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-//     ProbeConflictTestCmd
-//===========================================================================================================================
-
-#define kProbeConflictTestService_DefaultName          "name"
-#define kProbeConflictTestService_Port                         60000
-
-#define kProbeConflictTestTXTPtr               "\x13" "PROBE-CONFLICT-TEST"
-#define kProbeConflictTestTXTLen               sizeof_string( kProbeConflictTestTXTPtr )
-
-typedef struct
-{
-       const char *            description;
-       const char *            program;
-       Boolean                         expectsRename;
-       
-}      ProbeConflictTestCase;
-
-#define kPCTProgPreWait                        "wait 1000;"    // Wait 1 second before sending gratuitous response.
-#define kPCTProgPostWait               "wait 8000;"    // Wait 8 seconds after sending gratuitous response.
-                                                                                               // This allows ~2.75 seconds for probing and ~5 seconds for a rename.
-
-static const ProbeConflictTestCase             kProbeConflictTestCases[] =
-{
-       // No conflicts
-       
-       { "No probe conflicts.",                       kPCTProgPreWait "probes n-n-n;"       "send;" kPCTProgPostWait, false },
-       
-       // One multicast probe conflict
-       
-       { "One multicast probe conflict (1).",         kPCTProgPreWait "probes m;"           "send;" kPCTProgPostWait, false },
-       { "One multicast probe conflict (2).",         kPCTProgPreWait "probes n-m;"         "send;" kPCTProgPostWait, false },
-       { "One multicast probe conflict (3).",         kPCTProgPreWait "probes n-n-m;"       "send;" kPCTProgPostWait, false },
-       
-       // One unicast probe conflict
-       
-       { "One unicast probe conflict (1).",           kPCTProgPreWait "probes u;"           "send;" kPCTProgPostWait, true },
-       { "One unicast probe conflict (2).",           kPCTProgPreWait "probes n-u;"         "send;" kPCTProgPostWait, true },
-       { "One unicast probe conflict (3).",           kPCTProgPreWait "probes n-n-u;"       "send;" kPCTProgPostWait, true },
-       
-       // One multicast and one unicast probe conflict
-       
-       { "Multicast and unicast probe conflict (1).", kPCTProgPreWait "probes m-u;"         "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (2).", kPCTProgPreWait "probes m-n-u;"       "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (3).", kPCTProgPreWait "probes m-n-n-u;"     "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (4).", kPCTProgPreWait "probes n-m-u;"       "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (5).", kPCTProgPreWait "probes n-m-n-u;"     "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (6).", kPCTProgPreWait "probes n-m-n-n-u;"   "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (7).", kPCTProgPreWait "probes n-n-m-u;"     "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (8).", kPCTProgPreWait "probes n-n-m-n-u;"   "send;" kPCTProgPostWait, true },
-       { "Multicast and unicast probe conflict (9).", kPCTProgPreWait "probes n-n-m-n-n-u;" "send;" kPCTProgPostWait, true },
-       
-       // Two multicast probe conflicts
-       
-       { "Two multicast probe conflicts (1).",        kPCTProgPreWait "probes m-m;"         "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (2).",        kPCTProgPreWait "probes m-n-m;"       "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (3).",        kPCTProgPreWait "probes m-n-n-m;"     "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (4).",        kPCTProgPreWait "probes n-m-m;"       "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (5).",        kPCTProgPreWait "probes n-m-n-m-n;"   "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (6).",        kPCTProgPreWait "probes n-m-n-n-m;"   "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (7).",        kPCTProgPreWait "probes n-n-m-m;"     "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (8).",        kPCTProgPreWait "probes n-n-m-n-m;"   "send;" kPCTProgPostWait, true },
-       { "Two multicast probe conflicts (9).",        kPCTProgPreWait "probes n-n-m-n-n-m;" "send;" kPCTProgPostWait, true },
-};
-
-#define kProbeConflictTestCaseCount            countof( kProbeConflictTestCases )
-
-typedef struct
-{
-       DNSServiceRef                   registration;   // Test service registration.
-       NanoTime64                              testStartTime;  // Test's start time.
-       NanoTime64                              startTime;              // Current test case's start time.
-       MDNSColliderRef                 collider;               // mDNS collider object.
-       CFMutableArrayRef               results;                // Array of test case results.
-       char *                                  serviceName;    // Test service's instance name as a string. (malloced)
-       char *                                  serviceType;    // Test service's service type as a string. (malloced)
-       uint8_t *                               recordName;             // FQDN of collider's record (same as test service's SRV+TXT records). (malloced)
-       unsigned int                    testCaseIndex;  // Index of the current test case.
-       uint32_t                                ifIndex;                // Index of the interface that the collider is to operate on.
-       char *                                  outputFilePath; // File to write test results to. If NULL, then write to stdout. (malloced)
-       OutputFormatType                outputFormat;   // Format of test report output.
-       Boolean                                 appendNewline;  // True if a newline character should be appended to JSON output.
-       Boolean                                 registered;             // True if the test service instance is currently registered.
-       Boolean                                 testFailed;             // True if at least one test case failed.
-       
-}      ProbeConflictTestContext;
-
-static void DNSSD_API
-       _ProbeConflictTestRegisterCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inType,
-               const char *            inDomain,
-               void *                          inContext );
-static void            _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError );
-static OSStatus        _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext );
-static OSStatus        _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed );
-static void            _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext ) ATTRIBUTE_NORETURN;
-
-static void    ProbeConflictTestCmd( void )
-{
-       OSStatus                                                err;
-       ProbeConflictTestContext *              context;
-       const char *                                    serviceName;
-       char                                                    tag[ 6 + 1 ];
-       
-       context = (ProbeConflictTestContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       if( gProbeConflictTest_Interface )
-       {
-               err = InterfaceIndexFromArgString( gProbeConflictTest_Interface, &context->ifIndex );
-               require_noerr_quiet( err, exit );
-       }
-       else
-       {
-               err = GetAnyMDNSInterface( NULL, &context->ifIndex );
-               require_noerr_quiet( err, exit );
-       }
-       
-       if( gProbeConflictTest_OutputFilePath )
-       {
-               context->outputFilePath = strdup( gProbeConflictTest_OutputFilePath );
-               require_action( context->outputFilePath, exit, err = kNoMemoryErr );
-       }
-       
-       context->appendNewline  = gProbeConflictTest_OutputAppendNewline ? true : false;
-       context->outputFormat   = (OutputFormatType) CLIArgToValue( "format", gProbeConflictTest_OutputFormat, &err,
-               kOutputFormatStr_JSON,          kOutputFormatType_JSON,
-               kOutputFormatStr_XML,           kOutputFormatType_XML,
-               kOutputFormatStr_Binary,        kOutputFormatType_Binary,
-               NULL );
-       require_noerr_quiet( err, exit );
-       
-       context->results = CFArrayCreateMutable( NULL, kProbeConflictTestCaseCount, &kCFTypeArrayCallBacks );
-       require_action( context->results, exit, err = kNoMemoryErr );
-       
-       serviceName = gProbeConflictTest_UseComputerName ? NULL : kProbeConflictTestService_DefaultName;
-       
-       ASPrintF( &context->serviceType, "_pctest-%s._udp",
-               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
-       require_action( context->serviceType, exit, err = kNoMemoryErr );
-       
-       context->testStartTime = NanoTimeGetCurrent();
-       err = DNSServiceRegister( &context->registration, 0, context->ifIndex, serviceName, context->serviceType, "local.",
-               NULL, htons( kProbeConflictTestService_Port ), 0, NULL, _ProbeConflictTestRegisterCallback, context );
-       require_noerr( err, exit );
-       
-       err = DNSServiceSetDispatchQueue( context->registration, dispatch_get_main_queue() );
-       require_noerr( err, exit );
-       
-       dispatch_main();
-       
-exit:
-       exit( 1 );
-}
-
-//===========================================================================================================================
-//     _ProbeConflictTestRegisterCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _ProbeConflictTestRegisterCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inType,
-               const char *            inDomain,
-               void *                          inContext )
-{
-       OSStatus                                                                err;
-       ProbeConflictTestContext * const                context = (ProbeConflictTestContext *) inContext;
-       
-       Unused( inSDRef );
-       Unused( inType );
-       Unused( inDomain );
-       
-       err = inError;
-       require_noerr( err, exit );
-       
-       if( !context->registered )
-       {
-               if( inFlags & kDNSServiceFlagsAdd )
-               {
-                       uint8_t *                       ptr;
-                       size_t                          recordNameLen;
-                       unsigned int            len;
-                       uint8_t                         name[ kDomainNameLengthMax ];
-                       
-                       context->registered = true;
-                       
-                       FreeNullSafe( context->serviceName );
-                       context->serviceName = strdup( inName );
-                       require_action( context->serviceName, exit, err = kNoMemoryErr );
-                       
-                       err = DomainNameFromString( name, context->serviceName, NULL );
-                       require_noerr( err, exit );
-                       
-                       err = DomainNameAppendString( name, context->serviceType, NULL );
-                       require_noerr( err, exit );
-                       
-                       err = DomainNameAppendString( name, "local", NULL );
-                       require_noerr( err, exit );
-                       
-                       ForgetMem( &context->recordName );
-                       err = DomainNameDup( name, &context->recordName, &recordNameLen );
-                       require_noerr( err, exit );
-                       require_fatal( recordNameLen > 0, "Record name length is zero." );      // Prevents dubious static analyzer warning.
-                       
-                       // Make the first label all caps so that it's easier to spot in system logs.
-                       
-                       ptr = context->recordName;
-                       for( len = *ptr++; len > 0; --len, ++ptr ) *ptr = (uint8_t) toupper_safe( *ptr );
-                       
-                       err = _ProbeConflictTestStartNextTest( context );
-                       require_noerr( err, exit );
-               }
-       }
-       else
-       {
-               if( !( inFlags & kDNSServiceFlagsAdd ) )
-               {
-                       context->registered = false;
-                       err = _ProbeConflictTestStopCurrentTest( context, true );
-                       require_noerr( err, exit );
-               }
-       }
-       err = kNoErr;
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     _ProbeConflictTestColliderStopHandler
-//===========================================================================================================================
-
-static void    _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError )
-{
-       OSStatus                                                                err;
-       ProbeConflictTestContext * const                context = (ProbeConflictTestContext *) inContext;
-       
-       err = inError;
-       require_noerr_quiet( err, exit );
-       
-       ForgetCF( &context->collider );
-       
-       err = _ProbeConflictTestStopCurrentTest( context, false );
-       require_noerr( err, exit );
-       
-       err = _ProbeConflictTestStartNextTest( context );
-       require_noerr( err, exit );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     _ProbeConflictTestStartNextTest
-//===========================================================================================================================
-
-static OSStatus        _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext )
-{
-       OSStatus                                                        err;
-       const ProbeConflictTestCase *           testCase;
-       
-       check( !inContext->collider );
-       
-       if( inContext->testCaseIndex < kProbeConflictTestCaseCount )
-       {
-               testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
-       }
-       else
-       {
-               _ProbeConflictTestFinalizeAndExit( inContext );
-       }
-       
-       err = MDNSColliderCreate( dispatch_get_main_queue(), &inContext->collider );
-       require_noerr( err, exit );
-       
-       err = MDNSColliderSetProgram( inContext->collider, testCase->program );
-       require_noerr( err, exit );
-       
-       err = MDNSColliderSetRecord( inContext->collider, inContext->recordName, kDNSServiceType_TXT,
-               kProbeConflictTestTXTPtr, kProbeConflictTestTXTLen );
-       require_noerr( err, exit );
-       
-       MDNSColliderSetProtocols( inContext->collider, kMDNSColliderProtocol_IPv4 );
-       MDNSColliderSetInterfaceIndex( inContext->collider, inContext->ifIndex );
-       MDNSColliderSetStopHandler( inContext->collider, _ProbeConflictTestColliderStopHandler, inContext );
-       
-       inContext->startTime = NanoTimeGetCurrent();
-       err = MDNSColliderStart( inContext->collider );
-       require_noerr( err, exit );
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ProbeConflictTestStopCurrentTest
-//===========================================================================================================================
-
-#define kProbeConflictTestCaseResultKey_Description                    CFSTR( "description" )
-#define kProbeConflictTestCaseResultKey_StartTime                      CFSTR( "startTime" )
-#define kProbeConflictTestCaseResultKey_EndTime                                CFSTR( "endTime" )
-#define kProbeConflictTestCaseResultKey_ExpectedRename         CFSTR( "expectedRename" )
-#define kProbeConflictTestCaseResultKey_ServiceName                    CFSTR( "serviceName" )
-#define kProbeConflictTestCaseResultKey_Passed                         CFSTR( "passed" )
-
-static OSStatus        _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed )
-{
-       OSStatus                                                        err;
-       const ProbeConflictTestCase *           testCase;
-       NanoTime64                                                      endTime;
-       Boolean                                                         passed;
-       char                                                            startTimeStr[ 32 ];
-       char                                                            endTimeStr[ 32 ];
-       
-       endTime = NanoTimeGetCurrent();
-       
-       if( inContext->collider )
-       {
-               MDNSColliderSetStopHandler( inContext->collider, NULL, NULL );
-               MDNSColliderStop( inContext->collider );
-               CFRelease( inContext->collider );
-               inContext->collider = NULL;
-       }
-       
-       testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
-       passed = ( ( testCase->expectsRename && inRenamed ) || ( !testCase->expectsRename && !inRenamed ) ) ? true : false;
-       if( !passed ) inContext->testFailed = true;
-       
-       _NanoTime64ToDateString( inContext->startTime, startTimeStr, sizeof( startTimeStr ) );
-       _NanoTime64ToDateString( endTime, endTimeStr, sizeof( endTimeStr ) );
-       
-       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, inContext->results,
-               "{"
-                       "%kO=%s"        // description
-                       "%kO=%b"        // expectedRename
-                       "%kO=%s"        // startTime
-                       "%kO=%s"        // endTime
-                       "%kO=%s"        // serviceName
-                       "%kO=%b"        // passed
-               "}",
-               kProbeConflictTestCaseResultKey_Description,    testCase->description,
-               kProbeConflictTestCaseResultKey_ExpectedRename, testCase->expectsRename,
-               kProbeConflictTestCaseResultKey_StartTime,              startTimeStr,
-               kProbeConflictTestCaseResultKey_EndTime,                endTimeStr,
-               kProbeConflictTestCaseResultKey_ServiceName,    inContext->serviceName,
-               kProbeConflictTestCaseResultKey_Passed,                 passed );
-       require_noerr( err, exit );
-       
-       ++inContext->testCaseIndex;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ProbeConflictTestFinalizeAndExit
-//===========================================================================================================================
-
-#define kProbeConflictTestReportKey_StartTime          CFSTR( "startTime" )
-#define kProbeConflictTestReportKey_EndTime                    CFSTR( "endTime" )
-#define kProbeConflictTestReportKey_ServiceType                CFSTR( "serviceType" )
-#define kProbeConflictTestReportKey_Results                    CFSTR( "results" )
-#define kProbeConflictTestReportKey_Passed                     CFSTR( "passed" )
-
-static void    _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext )
-{
-       OSStatus                                err;
-       CFPropertyListRef               plist;
-       NanoTime64                              endTime;
-       char                                    startTimeStr[ 32 ];
-       char                                    endTimeStr[ 32 ];
-       
-       endTime = NanoTimeGetCurrent();
-       
-       check( !inContext->collider );
-       
-       _NanoTime64ToDateString( inContext->testStartTime, startTimeStr, sizeof( startTimeStr ) );
-       _NanoTime64ToDateString( endTime, endTimeStr, sizeof( endTimeStr ) );
-       
-       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
-               "{"
-                       "%kO=%s"        // startTime
-                       "%kO=%s"        // endTime
-                       "%kO=%s"        // serviceType
-                       "%kO=%O"        // results
-                       "%kO=%b"        // passed
-               "}",
-               kProbeConflictTestReportKey_StartTime,          startTimeStr,
-               kProbeConflictTestReportKey_EndTime,            endTimeStr,
-               kProbeConflictTestReportKey_ServiceType,        inContext->serviceType,
-               kProbeConflictTestReportKey_Results,            inContext->results,
-               kProbeConflictTestReportKey_Passed,                     inContext->testFailed ? false : true );
-       require_noerr( err, exit );
-       ForgetCF( &inContext->results );
-       
-       err = OutputPropertyList( plist, inContext->outputFormat, inContext->appendNewline, inContext->outputFilePath );
-       CFRelease( plist );
-       require_noerr( err, exit );
-       
-       exit( inContext->testFailed ? 2 : 0 );
-       
-exit:
-       ErrQuit( 1, "error: %#m\n", err );
-}
-
-//===========================================================================================================================
-//     SSDPDiscoverCmd
-//===========================================================================================================================
-
-#define kSSDPPort              1900
-
-typedef struct
-{
-       HTTPHeader                              header;                 // HTTP header object for sending and receiving.
-       dispatch_source_t               readSourceV4;   // Read dispatch source for IPv4 socket.
-       dispatch_source_t               readSourceV6;   // Read dispatch source for IPv6 socket.
-       int                                             receiveSecs;    // After send, the amount of time to spend receiving.
-       uint32_t                                ifindex;                // Index of the interface over which to send the query.
-       Boolean                                 useIPv4;                // True if the query should be sent via IPv4 multicast.
-       Boolean                                 useIPv6;                // True if the query should be sent via IPv6 multicast.
-       
-}      SSDPDiscoverContext;
-
-static void            SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext );
-static void            SSDPDiscoverReadHandler( void *inContext );
-static int             SocketToPortNumber( SocketRef inSock );
-static OSStatus        WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST );
-
-static void    SSDPDiscoverCmd( void )
-{
-       OSStatus                                        err;
-       struct timeval                          now;
-       SSDPDiscoverContext *           context;
-       dispatch_source_t                       signalSource    = NULL;
-       SocketRef                                       sockV4                  = kInvalidSocketRef;
-       SocketRef                                       sockV6                  = kInvalidSocketRef;
-       ssize_t                                         n;
-       int                                                     sendCount;
-       
-       // Set up SIGINT handler.
-       
-       signal( SIGINT, SIG_IGN );
-       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
-       require_noerr( err, exit );
-       dispatch_resume( signalSource );
-       
-       // Check command parameters.
-       
-       if( gSSDPDiscover_ReceiveSecs < -1 )
-       {
-               FPrintF( stdout, "Invalid receive time: %d seconds.\n", gSSDPDiscover_ReceiveSecs );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       // Create context.
-       
-       context = (SSDPDiscoverContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->receiveSecs    = gSSDPDiscover_ReceiveSecs;
-       context->useIPv4                = ( gSSDPDiscover_UseIPv4 || !gSSDPDiscover_UseIPv6 ) ? true : false;
-       context->useIPv6                = ( gSSDPDiscover_UseIPv6 || !gSSDPDiscover_UseIPv4 ) ? true : false;
-       
-       err = InterfaceIndexFromArgString( gInterface, &context->ifindex );
-       require_noerr_quiet( err, exit );
-       
-       // Set up IPv4 socket.
-       
-       if( context->useIPv4 )
-       {
-               int port;
-               err = UDPClientSocketOpen( AF_INET, NULL, 0, -1, &port, &sockV4 );
-               require_noerr( err, exit );
-               
-               err = SocketSetMulticastInterface( sockV4, NULL, context->ifindex );
-               require_noerr( err, exit );
-               
-               err = setsockopt( sockV4, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
-               err = map_socket_noerr_errno( sockV4, err );
-               require_noerr( err, exit );
-       }
-       
-       // Set up IPv6 socket.
-       
-       if( context->useIPv6 )
-       {
-               err = UDPClientSocketOpen( AF_INET6, NULL, 0, -1, NULL, &sockV6 );
-               require_noerr( err, exit );
-               
-               err = SocketSetMulticastInterface( sockV6, NULL, context->ifindex );
-               require_noerr( err, exit );
-               
-               err = setsockopt( sockV6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
-               err = map_socket_noerr_errno( sockV6, err );
-               require_noerr( err, exit );
-       }
-       
-       // Print prologue.
-       
-       SSDPDiscoverPrintPrologue( context );
-       
-       // Send mDNS query message.
-       
-       sendCount = 0;
-       if( IsValidSocket( sockV4 ) )
-       {
-               struct sockaddr_in              mcastAddr4;
-               
-               memset( &mcastAddr4, 0, sizeof( mcastAddr4 ) );
-               SIN_LEN_SET( &mcastAddr4 );
-               mcastAddr4.sin_family           = AF_INET;
-               mcastAddr4.sin_port                     = htons( kSSDPPort );
-               mcastAddr4.sin_addr.s_addr      = htonl( 0xEFFFFFFA );  // 239.255.255.250
-               
-               err = WriteSSDPSearchRequest( &context->header, &mcastAddr4, gSSDPDiscover_MX, gSSDPDiscover_ST );
-               require_noerr( err, exit );
-               
-               n = sendto( sockV4, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr4,
-                       (socklen_t) sizeof( mcastAddr4 ) );
-               err = map_socket_value_errno( sockV4, n == (ssize_t) context->header.len, n );
-               if( err )
-               {
-                       FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
-                       ForgetSocket( &sockV4 );
-               }
-               else
-               {
-                       if( gSSDPDiscover_Verbose )
-                       {
-                               gettimeofday( &now, NULL );
-                               FPrintF( stdout, "---\n" );
-                               FPrintF( stdout, "Send time:    %{du:time}\n",  &now );
-                               FPrintF( stdout, "Source Port:  %d\n",                  SocketToPortNumber( sockV4 ) );
-                               FPrintF( stdout, "Destination:  %##a\n",                &mcastAddr4 );
-                               FPrintF( stdout, "Message size: %zu\n",                 context->header.len );
-                               FPrintF( stdout, "HTTP header:\n%1{text}",              context->header.buf, context->header.len );
-                       }
-                       ++sendCount;
-               }
-       }
-       
-       if( IsValidSocket( sockV6 ) )
-       {
-               struct sockaddr_in6             mcastAddr6;
-               
-               memset( &mcastAddr6, 0, sizeof( mcastAddr6 ) );
-               SIN6_LEN_SET( &mcastAddr6 );
-               mcastAddr6.sin6_family                          = AF_INET6;
-               mcastAddr6.sin6_port                            = htons( kSSDPPort );
-               mcastAddr6.sin6_addr.s6_addr[  0 ]      = 0xFF; // SSDP IPv6 link-local multicast address FF02::C
-               mcastAddr6.sin6_addr.s6_addr[  1 ]      = 0x02;
-               mcastAddr6.sin6_addr.s6_addr[ 15 ]      = 0x0C;
-               
-               err = WriteSSDPSearchRequest( &context->header, &mcastAddr6, gSSDPDiscover_MX, gSSDPDiscover_ST );
-               require_noerr( err, exit );
-               
-               n = sendto( sockV6, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr6,
-                       (socklen_t) sizeof( mcastAddr6 ) );
-               err = map_socket_value_errno( sockV6, n == (ssize_t) context->header.len, n );
-               if( err )
-               {
-                       FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
-                       ForgetSocket( &sockV6 );
-               }
-               else
-               {
-                       if( gSSDPDiscover_Verbose )
-                       {
-                               gettimeofday( &now, NULL );
-                               FPrintF( stdout, "---\n" );
-                               FPrintF( stdout, "Send time:    %{du:time}\n",  &now );
-                               FPrintF( stdout, "Source Port:  %d\n",                  SocketToPortNumber( sockV6 ) );
-                               FPrintF( stdout, "Destination:  %##a\n",                &mcastAddr6 );
-                               FPrintF( stdout, "Message size: %zu\n",                 context->header.len );
-                               FPrintF( stdout, "HTTP header:\n%1{text}",              context->header.buf, context->header.len );
-                       }
-                       ++sendCount;
-               }
-       }
-       require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
-       
-       // If there's no wait period after the send, then exit.
-       
-       if( context->receiveSecs == 0 ) goto exit;
-       
-       // Create dispatch read sources for socket(s).
-       
-       if( IsValidSocket( sockV4 ) )
-       {
-               SocketContext *         sockCtx;
-               
-               err = SocketContextCreate( sockV4, context, &sockCtx );
-               require_noerr( err, exit );
-               sockV4 = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
-                       &context->readSourceV4 );
-               if( err ) ForgetSocketContext( &sockCtx );
-               require_noerr( err, exit );
-               
-               dispatch_resume( context->readSourceV4 );
-       }
-       
-       if( IsValidSocket( sockV6 ) )
-       {
-               SocketContext *         sockCtx;
-               
-               err = SocketContextCreate( sockV6, context, &sockCtx );
-               require_noerr( err, exit );
-               sockV6 = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
-                       &context->readSourceV6 );
-               if( err ) ForgetSocketContext( &sockCtx );
-               require_noerr( err, exit );
-               
-               dispatch_resume( context->readSourceV6 );
-       }
-       
-       if( context->receiveSecs > 0 )
-       {
-               dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
-                       Exit );
-       }
-       dispatch_main();
-       
-exit:
-       ForgetSocket( &sockV4 );
-       ForgetSocket( &sockV6 );
-       dispatch_source_forget( &signalSource );
-       if( err ) exit( 1 );
-}
-
-static int     SocketToPortNumber( SocketRef inSock )
-{
-       OSStatus                err;
-       sockaddr_ip             sip;
-       socklen_t               len;
-       
-       len = (socklen_t) sizeof( sip );
-       err = getsockname( inSock, &sip.sa, &len );
-       err = map_socket_noerr_errno( inSock, err );
-       check_noerr( err );
-       return( err ? -1 : SockAddrGetPort( &sip ) );
-}
-
-static OSStatus        WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST )
-{
-       OSStatus                err;
-       
-       err = HTTPHeader_InitRequest( inHeader, "M-SEARCH", "*", "HTTP/1.1" );
-       require_noerr( err, exit );
-       
-       err = HTTPHeader_SetField( inHeader, "Host", "%##a", inHostSA );
-       require_noerr( err, exit );
-       
-       err = HTTPHeader_SetField( inHeader, "ST", "%s", inST ? inST : "ssdp:all" );
-       require_noerr( err, exit );
-       
-       err = HTTPHeader_SetField( inHeader, "Man", "\"ssdp:discover\"" );
-       require_noerr( err, exit );
-       
-       err = HTTPHeader_SetField( inHeader, "MX", "%d", inMX );
-       require_noerr( err, exit );
-       
-       err = HTTPHeader_Commit( inHeader );
-       require_noerr( err, exit );
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     SSDPDiscoverPrintPrologue
-//===========================================================================================================================
-
-static void    SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext )
-{
-       const int                               receiveSecs = inContext->receiveSecs;
-       const char *                    ifName;
-       char                                    ifNameBuf[ IF_NAMESIZE + 1 ];
-       NetTransportType                ifType;
-       
-       ifName = if_indextoname( inContext->ifindex, ifNameBuf );
-       
-       ifType = kNetTransportType_Undefined;
-       if( ifName ) SocketGetInterfaceInfo( kInvalidSocketRef, ifName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ifType );
-       
-       FPrintF( stdout, "Interface:        %s/%d/%s\n",
-               ifName ? ifName : "?", inContext->ifindex, NetTransportTypeToString( ifType ) );
-       FPrintF( stdout, "IP protocols:     %?s%?s%?s\n",
-               inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
-       FPrintF( stdout, "Receive duration: " );
-       if( receiveSecs >= 0 )  FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
-       else                                    FPrintF( stdout, "∞\n" );
-       FPrintF( stdout, "Start time:       %{du:time}\n", NULL );
-}
-
-//===========================================================================================================================
-//     SSDPDiscoverReadHandler
-//===========================================================================================================================
-
-static void    SSDPDiscoverReadHandler( void *inContext )
-{
-       OSStatus                                                err;
-       struct timeval                                  now;
-       SocketContext * const                   sockCtx = (SocketContext *) inContext;
-       SSDPDiscoverContext * const             context = (SSDPDiscoverContext *) sockCtx->userContext;
-       HTTPHeader * const                              header  = &context->header;
-       sockaddr_ip                                             fromAddr;
-       size_t                                                  msgLen;
-       
-       gettimeofday( &now, NULL );
-       
-       err = SocketRecvFrom( sockCtx->sock, header->buf, sizeof( header->buf ), &msgLen, &fromAddr, sizeof( fromAddr ),
-               NULL, NULL, NULL, NULL );
-       require_noerr( err, exit );
-       
-       FPrintF( stdout, "---\n" );
-       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
-       FPrintF( stdout, "Source:       %##a\n",                &fromAddr );
-       FPrintF( stdout, "Message size: %zu\n",                 msgLen );
-       header->len = msgLen;
-       if( HTTPHeader_Validate( header ) )
-       {
-               FPrintF( stdout, "HTTP header:\n%1{text}", header->buf, header->len );
-               if( header->extraDataLen > 0 )
-               {
-                       FPrintF( stdout, "HTTP body: %1.1H", header->extraDataPtr, (int) header->extraDataLen, INT_MAX );
-               }
-       }
-       else
-       {
-               FPrintF( stdout, "Invalid HTTP message:\n%1.1H", header->buf, (int) msgLen, INT_MAX );
-               goto exit;
-       }
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     HTTPHeader_Validate
-//
-//     Parses for the end of an HTTP header and updates the HTTPHeader structure so it's ready to parse. Returns true if valid.
-//     This assumes the "buf" and "len" fields are set. The other fields are set by this function.
-//
-//     Note: This was copied from CoreUtils because the HTTPHeader_Validate function is currently not exported in the framework.
-//===========================================================================================================================
-
-Boolean        HTTPHeader_Validate( HTTPHeader *inHeader )
-{
-       const char *            src;
-       const char *            end;
-       
-       // Check for interleaved binary data (4 byte header that begins with $). See RFC 2326 section 10.12.
-       
-       require( inHeader->len < sizeof( inHeader->buf ), exit );
-       src = inHeader->buf;
-       end = src + inHeader->len;
-       if( ( ( end - src ) >= 4 ) && ( src[ 0 ] == '$' ) )
-       {
-               src += 4;
-       }
-       else
-       {
-               // Search for an empty line (HTTP-style header/body separator). CRLFCRLF, LFCRLF, or LFLF accepted.
-               // $$$ TO DO: Start from the last search location to avoid re-searching the same data over and over.
-               
-               for( ;; )
-               {
-                       while( ( src < end ) && ( src[ 0 ] != '\n' ) ) ++src;
-                       if( src >= end ) goto exit;
-                       ++src;
-                       if( ( ( end - src ) >= 2 ) && ( src[ 0 ] == '\r' ) && ( src[ 1 ] == '\n' ) ) // CFLFCRLF or LFCRLF
-                       {
-                               src += 2;
-                               break;
-                       }
-                       else if( ( ( end - src ) >= 1 ) && ( src[ 0 ] == '\n' ) ) // LFLF
-                       {
-                               src += 1;
-                               break;
-                       }
-               }
-       }
-       inHeader->extraDataPtr  = src;
-       inHeader->extraDataLen  = (size_t)( end - src );
-       inHeader->len                   = (size_t)( src - inHeader->buf );
-       return( true );
-       
-exit:
-       return( false );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-//     ResQueryCmd
-//===========================================================================================================================
-
-// res_query() from libresolv is actually called res_9_query (see /usr/include/resolv.h).
-
-SOFT_LINK_LIBRARY_EX( "/usr/lib", resolv );
-SOFT_LINK_FUNCTION_EX( resolv, res_9_query,
-       int,
-       ( const char *dname, int class, int type, u_char *answer, int anslen ),
-       ( dname, class, type, answer, anslen ) );
-
-// res_query() from libinfo
-
-SOFT_LINK_LIBRARY_EX( "/usr/lib", info );
-SOFT_LINK_FUNCTION_EX( info, res_query,
-       int,
-       ( const char *dname, int class, int type, u_char *answer, int anslen ),
-       ( dname, class, type, answer, anslen ) );
-
-typedef int ( *res_query_f )( const char *dname, int class, int type, u_char *answer, int anslen );
-
-static void    ResQueryCmd( void )
-{
-       OSStatus                err;
-       res_query_f             res_query_ptr;
-       int                             n;
-       uint16_t                type, class;
-       uint8_t                 answer[ 1024 ];
-       
-       // Get pointer to one of the res_query() functions.
-       
-       if( gResQuery_UseLibInfo )
-       {
-               if( !SOFT_LINK_HAS_FUNCTION( info, res_query ) )
-               {
-                       FPrintF( stderr, "Failed to soft link res_query from libinfo.\n" );
-                       err = kNotFoundErr;
-                       goto exit;
-               }
-               res_query_ptr = soft_res_query;
-       }
-       else
-       {
-               if( !SOFT_LINK_HAS_FUNCTION( resolv, res_9_query ) )
-               {
-                       FPrintF( stderr, "Failed to soft link res_query from libresolv.\n" );
-                       err = kNotFoundErr;
-                       goto exit;
-               }
-               res_query_ptr = soft_res_9_query;
-       }
-       
-       // Get record type.
-       
-       err = RecordTypeFromArgString( gResQuery_Type, &type );
-       require_noerr( err, exit );
-       
-       // Get record class.
-       
-       if( gResQuery_Class )
-       {
-               err = RecordClassFromArgString( gResQuery_Class, &class );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               class = kDNSServiceClass_IN;
-       }
-       
-       // Print prologue.
-       
-       FPrintF( stdout, "Name:       %s\n",                    gResQuery_Name );
-       FPrintF( stdout, "Type:       %s (%u)\n",               RecordTypeToString( type ), type );
-       FPrintF( stdout, "Class:      %s (%u)\n",               ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
-       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
-       FPrintF( stdout, "---\n" );
-       
-       // Call res_query().
-       
-       n = res_query_ptr( gResQuery_Name, class, type, (u_char *) answer, (int) sizeof( answer ) );
-       if( n < 0 )
-       {
-               FPrintF( stderr, "res_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
-               err = kUnknownErr;
-               goto exit;
-       }
-       
-       // Print result.
-       
-       FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     ResolvDNSQueryCmd
-//===========================================================================================================================
-
-// dns_handle_t is defined as a pointer to a privately-defined struct in /usr/include/dns.h. It's defined as a void * here to
-// avoid including the header file.
-
-typedef void *         dns_handle_t;
-
-SOFT_LINK_FUNCTION_EX( resolv, dns_open, dns_handle_t, ( const char *path ), ( path ) );
-SOFT_LINK_FUNCTION_VOID_RETURN_EX( resolv, dns_free, ( dns_handle_t *dns ), ( dns ) );
-SOFT_LINK_FUNCTION_EX( resolv, dns_query,
-       int32_t, (
-               dns_handle_t            dns,
-               const char *            name,
-               uint32_t                        dnsclass,
-               uint32_t                        dnstype,
-               char *                          buf,
-               uint32_t                        len,
-               struct sockaddr *       from,
-               uint32_t *                      fromlen ),
-       ( dns, name, dnsclass, dnstype, buf, len, from, fromlen ) );
-
-static void    ResolvDNSQueryCmd( void )
-{
-       OSStatus                        err;
-       int                                     n;
-       dns_handle_t            dns = NULL;
-       uint16_t                        type, class;
-       sockaddr_ip                     from;
-       uint32_t                        fromLen;
-       uint8_t                         answer[ 1024 ];
-       
-       // Make sure that the required symbols are available.
-       
-       if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_open ) )
-       {
-               FPrintF( stderr, "Failed to soft link dns_open from libresolv.\n" );
-               err = kNotFoundErr;
-               goto exit;
-       }
-       
-       if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_free ) )
-       {
-               FPrintF( stderr, "Failed to soft link dns_free from libresolv.\n" );
-               err = kNotFoundErr;
-               goto exit;
-       }
-       
-       if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_query ) )
-       {
-               FPrintF( stderr, "Failed to soft link dns_query from libresolv.\n" );
-               err = kNotFoundErr;
-               goto exit;
-       }
-       
-       // Get record type.
-       
-       err = RecordTypeFromArgString( gResolvDNSQuery_Type, &type );
-       require_noerr( err, exit );
-       
-       // Get record class.
-       
-       if( gResolvDNSQuery_Class )
-       {
-               err = RecordClassFromArgString( gResolvDNSQuery_Class, &class );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               class = kDNSServiceClass_IN;
-       }
-       
-       // Get dns handle.
-       
-       dns = soft_dns_open( gResolvDNSQuery_Path );
-       if( !dns )
-       {
-               FPrintF( stderr, "dns_open( %s ) failed.\n", gResolvDNSQuery_Path );
-               err = kUnknownErr;
-               goto exit;
-       }
-       
-       // Print prologue.
-       
-       FPrintF( stdout, "Name:       %s\n",                    gResolvDNSQuery_Name );
-       FPrintF( stdout, "Type:       %s (%u)\n",               RecordTypeToString( type ), type );
-       FPrintF( stdout, "Class:      %s (%u)\n",               ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
-       FPrintF( stdout, "Path:       %s\n",                    gResolvDNSQuery_Path ? gResolvDNSQuery_Name : "<NULL>" );
-       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
-       FPrintF( stdout, "---\n" );
-       
-       // Call dns_query().
-       
-       memset( &from, 0, sizeof( from ) );
-       fromLen = (uint32_t) sizeof( from );
-       n = soft_dns_query( dns, gResolvDNSQuery_Name, class, type, (char *) answer, (uint32_t) sizeof( answer ), &from.sa,
-               &fromLen );
-       if( n < 0 )
-       {
-               FPrintF( stderr, "dns_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
-               err = kUnknownErr;
-               goto exit;
-       }
-       
-       // Print result.
-       
-       FPrintF( stdout, "From:         %##a\n", &from );
-       FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
-       
-exit:
-       if( dns ) soft_dns_free( dns );
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     CFHostCmd
-//===========================================================================================================================
-
-static void
-       _CFHostResolveCallback(
-               CFHostRef                               inHost,
-               CFHostInfoType                  inInfoType,
-               const CFStreamError *   inError,
-               void *                                  inInfo );
-
-static void    CFHostCmd( void )
-{
-       OSStatus                                err;
-       CFStringRef                             name;
-       Boolean                                 success;
-       CFHostRef                               host = NULL;
-       CFHostClientContext             context;
-       CFStreamError                   streamErr;
-       
-       name = CFStringCreateWithCString( kCFAllocatorDefault, gCFHost_Name, kCFStringEncodingUTF8 );
-       require_action( name, exit, err = kUnknownErr );
-       
-       host = CFHostCreateWithName( kCFAllocatorDefault, name );
-       ForgetCF( &name );
-       require_action( host, exit, err = kUnknownErr );
-       
-       memset( &context, 0, sizeof( context ) );
-       success = CFHostSetClient( host, _CFHostResolveCallback, &context );
-       require_action( success, exit, err = kUnknownErr );
-       
-       CFHostScheduleWithRunLoop( host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
-       
-       // Print prologue.
-       
-       FPrintF( stdout, "Hostname:   %s\n",                    gCFHost_Name );
-       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
-       FPrintF( stdout, "---\n" );
-       
-       success = CFHostStartInfoResolution( host, kCFHostAddresses, &streamErr );
-       require_action( success, exit, err = kUnknownErr );
-       err = kNoErr;
-       
-       CFRunLoopRun();
-       
-exit:
-       CFReleaseNullSafe( host );
-       if( err ) exit( 1 );
-}
-
-static void    _CFHostResolveCallback( CFHostRef inHost, CFHostInfoType inInfoType, const CFStreamError *inError, void *inInfo )
-{
-       OSStatus                        err;
-       struct timeval          now;
-       
-       gettimeofday( &now, NULL );
-       
-       Unused( inInfoType );
-       Unused( inInfo );
-       
-       if( inError && ( inError->domain != 0 ) && ( inError->error ) )
-       {
-               err = inError->error;
-               if( inError->domain == kCFStreamErrorDomainNetDB )
-               {
-                       FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
-               }
-               else
-               {
-                       FPrintF( stderr, "Error %#m\n", err );
-               }
-       }
-       else
-       {
-               CFArrayRef                                      addresses;
-               CFIndex                                         count, i;
-               CFDataRef                                       addrData;
-               const struct sockaddr *         sockAddr;
-               Boolean                                         wasResolved = false;
-               
-               addresses = CFHostGetAddressing( inHost, &wasResolved );
-               check( wasResolved );
-               
-               if( addresses )
-               {
-                       count = CFArrayGetCount( addresses );
-                       for( i = 0; i < count; ++i )
-                       {
-                               addrData = CFArrayGetCFDataAtIndex( addresses, i, &err );
-                               require_noerr( err, exit );
-                               
-                               sockAddr = (const struct sockaddr *) CFDataGetBytePtr( addrData );
-                               FPrintF( stdout, "%##a\n", sockAddr );
-                       }
-               }
-               err = kNoErr;
-       }
-       
-       FPrintF( stdout, "---\n" );
-       FPrintF( stdout, "End time:   %{du:time}\n", &now );
-       
-       if( gCFHost_WaitSecs > 0 ) sleep( (unsigned int) gCFHost_WaitSecs );
-       
-exit:
-       exit( err ? 1 : 0 );
-}
-
-//===========================================================================================================================
-//     DNSConfigAddCmd
-//
-//     Note: Based on ajn's supplemental test tool.
-//===========================================================================================================================
-
-static void    DNSConfigAddCmd( void )
-{
-       OSStatus                                        err;
-       CFMutableDictionaryRef          dict    = NULL;
-       CFMutableArrayRef                       array   = NULL;
-       size_t                                          i;
-       SCDynamicStoreRef                       store   = NULL;
-       CFStringRef                                     key             = NULL;
-       Boolean                                         success;
-       
-       // Create dictionary.
-       
-       dict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
-       require_action( dict, exit, err = kNoMemoryErr );
-       
-       // Add DNS server IP addresses.
-       
-       array = CFArrayCreateMutable( NULL, (CFIndex) gDNSConfigAdd_IPAddrCount, &kCFTypeArrayCallBacks );
-       require_action( array, exit, err = kNoMemoryErr );
-       
-       for( i = 0; i < gDNSConfigAdd_IPAddrCount; ++i )
-       {
-               CFStringRef             addrStr;
-               
-               addrStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_IPAddrArray[ i ], kCFStringEncodingUTF8 );
-               require_action( addrStr, exit, err = kUnknownErr );
-               
-               CFArrayAppendValue( array, addrStr );
-               CFRelease( addrStr );
-       }
-       
-       CFDictionarySetValue( dict, kSCPropNetDNSServerAddresses, array );
-       ForgetCF( &array );
-       
-       // Add domains, if any.
-       
-       array = CFArrayCreateMutable( NULL, (CFIndex) Min( gDNSConfigAdd_DomainCount, 1 ), &kCFTypeArrayCallBacks );
-       require_action( array, exit, err = kNoMemoryErr );
-       
-       if( gDNSConfigAdd_DomainCount > 0 )
-       {
-               for( i = 0; i < gDNSConfigAdd_DomainCount; ++i )
-               {
-                       CFStringRef             domainStr;
-                       
-                       domainStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_DomainArray[ i ], kCFStringEncodingUTF8 );
-                       require_action( domainStr, exit, err = kUnknownErr );
-                       
-                       CFArrayAppendValue( array, domainStr );
-                       CFRelease( domainStr );
-               }
-       }
-       else
-       {
-               // There are no domains, but the domain array needs to be non-empty, so add a zero-length string to the array.
-               
-               CFArrayAppendValue( array, CFSTR( "" ) );
-       }
-       
-       CFDictionarySetValue( dict, kSCPropNetDNSSupplementalMatchDomains, array );
-       ForgetCF( &array );
-       
-       // Add interface, if any.
-       
-       if( gDNSConfigAdd_Interface )
-       {
-               err = CFDictionarySetCString( dict, kSCPropInterfaceName, gDNSConfigAdd_Interface, kSizeCString );
-               require_noerr( err, exit );
-               
-               CFDictionarySetValue( dict, kSCPropNetDNSConfirmedServiceID, gDNSConfigAdd_ID );
-       }
-       
-       // Set dictionary in dynamic store.
-       
-       store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
-       err = map_scerror( store );
-       require_noerr( err, exit );
-       
-       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigAdd_ID, kSCEntNetDNS );
-       require_action( key, exit, err = kUnknownErr );
-       
-       success = SCDynamicStoreSetValue( store, key, dict );
-       require_action( success, exit, err = kUnknownErr );
-       
-exit:
-       CFReleaseNullSafe( dict );
-       CFReleaseNullSafe( array );
-       CFReleaseNullSafe( store );
-       CFReleaseNullSafe( key );
-       gExitCode = err ? 1 : 0;
-}
-
-//===========================================================================================================================
-//     DNSConfigRemoveCmd
-//===========================================================================================================================
-
-static void    DNSConfigRemoveCmd( void )
-{
-       OSStatus                                err;
-       SCDynamicStoreRef               store   = NULL;
-       CFStringRef                             key             = NULL;
-       Boolean                                 success;
-       
-       store = SCDynamicStoreCreate( NULL, CFSTR( "com.apple.dnssdutil" ), NULL, NULL );
-       err = map_scerror( store );
-       require_noerr( err, exit );
-       
-       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigRemove_ID, kSCEntNetDNS );
-       require_action( key, exit, err = kUnknownErr );
-       
-       success = SCDynamicStoreRemoveValue( store, key );
-       require_action( success, exit, err = kUnknownErr );
-       
-exit:
-       CFReleaseNullSafe( store );
-       CFReleaseNullSafe( key );
-       gExitCode = err ? 1 : 0;
-}
-#endif // TARGET_OS_DARWIN
-
-//===========================================================================================================================
-//     DaemonVersionCmd
-//===========================================================================================================================
-
-static void    DaemonVersionCmd( void )
-{
-       OSStatus                err;
-       uint32_t                size, version;
-       char                    strBuf[ 16 ];
-       
-       size = (uint32_t) sizeof( version );
-       err = DNSServiceGetProperty( kDNSServiceProperty_DaemonVersion, &version, &size );
-       require_noerr( err, exit );
-       
-       FPrintF( stdout, "Daemon version: %s\n", SourceVersionToCString( version, strBuf ) );
-       
-exit:
-       if( err ) exit( 1 );
-}
-
-//===========================================================================================================================
-//     Exit
-//===========================================================================================================================
-
-static void    Exit( void *inContext )
-{
-       const char * const              reason = (const char *) inContext;
-       
-       FPrintF( stdout, "---\n" );
-       FPrintF( stdout, "End time:   %{du:time}\n", NULL );
-       if( reason ) FPrintF( stdout, "End reason: %s\n", reason );
-       exit( gExitCode );
-}
-
-//===========================================================================================================================
-//     PrintFTimestampHandler
-//===========================================================================================================================
-
-static int
-       PrintFTimestampHandler(
-               PrintFContext * inContext,
-               PrintFFormat *  inFormat,
-               PrintFVAList *  inArgs,
-               void *                  inUserContext )
-{
-       struct timeval                          now;
-       const struct timeval *          tv;
-       struct tm *                                     localTime;
-       size_t                                          len;
-       int                                                     n;
-       char                                            dateTimeStr[ 32 ];
-       
-       Unused( inUserContext );
-       
-       tv = va_arg( inArgs->args, const struct timeval * );
-       require_action_quiet( !inFormat->suppress, exit, n = 0 );
-       
-       if( !tv )
-       {
-               gettimeofday( &now, NULL );
-               tv = &now;
-       }
-       localTime = localtime( &tv->tv_sec );
-       len = strftime( dateTimeStr, sizeof( dateTimeStr ), "%Y-%m-%d %H:%M:%S", localTime );
-       if( len == 0 ) dateTimeStr[ 0 ] = '\0';
-       
-       n = PrintFCore( inContext, "%s.%06u", dateTimeStr, (unsigned int) tv->tv_usec );
-       
-exit:
-       return( n );
-}
-
-//===========================================================================================================================
-//     PrintFDNSMessageHandler
-//===========================================================================================================================
-
-static int
-       PrintFDNSMessageHandler(
-               PrintFContext * inContext,
-               PrintFFormat *  inFormat,
-               PrintFVAList *  inArgs,
-               void *                  inUserContext )
-{
-       OSStatus                        err;
-       const void *            msgPtr;
-       size_t                          msgLen;
-       char *                          text;
-       int                                     n;
-       Boolean                         isMDNS;
-       Boolean                         printRawRData;
-       
-       Unused( inUserContext );
-       
-       msgPtr = va_arg( inArgs->args, const void * );
-       msgLen = va_arg( inArgs->args, size_t );
-       require_action_quiet( !inFormat->suppress, exit, n = 0 );
-       
-       isMDNS = ( inFormat->altForm > 0 ) ? true : false;
-       if(      inFormat->precision == 0 ) printRawRData = false;
-       else if( inFormat->precision == 1 ) printRawRData = true;
-       else
-       {
-               n = PrintFCore( inContext, "<< BAD %%{du:dnsmsg} PRECISION >>" );
-               goto exit;
-       }
-       
-       err = DNSMessageToText( msgPtr, msgLen, isMDNS, printRawRData, &text );
-       if( !err )
-       {
-               n = PrintFCore( inContext, "%*{text}", inFormat->fieldWidth, text, kSizeCString );
-               free( text );
-       }
-       else
-       {
-               n = PrintFCore( inContext, "%*.1H", inFormat->fieldWidth, msgPtr, (int) msgLen, (int) msgLen );
-       }
-       
-exit:
-       return( n );
-}
-
-//===========================================================================================================================
-//     PrintFAddRmvFlagsHandler
-//===========================================================================================================================
-
-static int
-       PrintFAddRmvFlagsHandler(
-               PrintFContext * inContext,
-               PrintFFormat *  inFormat,
-               PrintFVAList *  inArgs,
-               void *                  inUserContext )
-{
-       DNSServiceFlags         flags;
-       int                                     n;
-       
-       Unused( inUserContext );
-       
-       flags = va_arg( inArgs->args, DNSServiceFlags );
-       require_action_quiet( !inFormat->suppress, exit, n = 0 );
-       
-       n = PrintFCore( inContext, "%08X %s%c%c", flags,
-               ( flags & kDNSServiceFlagsAdd )           ? "Add" : "Rmv",
-               ( flags & kDNSServiceFlagsMoreComing )    ? '+'   : ' ',
-               ( flags & kDNSServiceFlagsExpiredAnswer ) ? '!'   : ' ' );
-       
-exit:
-       return( n );
-}
-
-//===========================================================================================================================
-//     GetDNSSDFlagsFromOpts
-//===========================================================================================================================
-
-static DNSServiceFlags GetDNSSDFlagsFromOpts( void )
-{
-       DNSServiceFlags         flags;
-       
-       flags = (DNSServiceFlags) gDNSSDFlags;
-       if( flags & kDNSServiceFlagsShareConnection )
-       {
-               FPrintF( stderr, "*** Warning: kDNSServiceFlagsShareConnection (0x%X) is explicitly set in flag parameters.\n",
-                       kDNSServiceFlagsShareConnection );
-       }
-       
-       if( gDNSSDFlag_AllowExpiredAnswers )    flags |= kDNSServiceFlagsAllowExpiredAnswers;
-       if( gDNSSDFlag_BrowseDomains )                  flags |= kDNSServiceFlagsBrowseDomains;
-       if( gDNSSDFlag_DenyCellular )                   flags |= kDNSServiceFlagsDenyCellular;
-       if( gDNSSDFlag_DenyExpensive )                  flags |= kDNSServiceFlagsDenyExpensive;
-       if( gDNSSDFlag_ForceMulticast )                 flags |= kDNSServiceFlagsForceMulticast;
-       if( gDNSSDFlag_IncludeAWDL )                    flags |= kDNSServiceFlagsIncludeAWDL;
-       if( gDNSSDFlag_NoAutoRename )                   flags |= kDNSServiceFlagsNoAutoRename;
-       if( gDNSSDFlag_PathEvaluationDone )             flags |= kDNSServiceFlagsPathEvaluationDone;
-       if( gDNSSDFlag_RegistrationDomains )    flags |= kDNSServiceFlagsRegistrationDomains;
-       if( gDNSSDFlag_ReturnIntermediates )    flags |= kDNSServiceFlagsReturnIntermediates;
-       if( gDNSSDFlag_Shared )                                 flags |= kDNSServiceFlagsShared;
-       if( gDNSSDFlag_SuppressUnusable )               flags |= kDNSServiceFlagsSuppressUnusable;
-       if( gDNSSDFlag_Timeout )                                flags |= kDNSServiceFlagsTimeout;
-       if( gDNSSDFlag_UnicastResponse )                flags |= kDNSServiceFlagsUnicastResponse;
-       if( gDNSSDFlag_Unique )                                 flags |= kDNSServiceFlagsUnique;
-       if( gDNSSDFlag_WakeOnResolve )                  flags |= kDNSServiceFlagsWakeOnResolve;
-       
-       return( flags );
-}
-
-//===========================================================================================================================
-//     CreateConnectionFromArgString
-//===========================================================================================================================
-
-static OSStatus
-       CreateConnectionFromArgString(
-               const char *                    inString,
-               dispatch_queue_t                inQueue,
-               DNSServiceRef *                 outSDRef,
-               ConnectionDesc *                outDesc )
-{
-       OSStatus                        err;
-       DNSServiceRef           sdRef = NULL;
-       ConnectionType          type;
-       int32_t                         pid = -1;       // Initializing because the analyzer claims pid may be used uninitialized.
-       uint8_t                         uuid[ 16 ];
-       
-       if( strcasecmp( inString, kConnectionArg_Normal ) == 0 )
-       {
-               err = DNSServiceCreateConnection( &sdRef );
-               require_noerr( err, exit );
-               type = kConnectionType_Normal;
-       }
-       else if( stricmp_prefix( inString, kConnectionArgPrefix_PID ) == 0 )
-       {
-               const char * const              pidStr = inString + sizeof_string( kConnectionArgPrefix_PID );
-               
-               err = StringToInt32( pidStr, &pid );
-               if( err )
-               {
-                       FPrintF( stderr, "Invalid delegate connection PID value: %s\n", pidStr );
-                       err = kParamErr;
-                       goto exit;
-               }
-               
-               memset( uuid, 0, sizeof( uuid ) );
-               err = DNSServiceCreateDelegateConnection( &sdRef, pid, uuid );
-               if( err )
-               {
-                       FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for PID %d\n", err, pid );
-                       goto exit;
-               }
-               type = kConnectionType_DelegatePID;
-       }
-       else if( stricmp_prefix( inString, kConnectionArgPrefix_UUID ) == 0 )
-       {
-               const char * const              uuidStr = inString + sizeof_string( kConnectionArgPrefix_UUID );
-               
-               check_compile_time_code( sizeof( uuid ) == sizeof( uuid_t ) );
-               
-               err = StringToUUID( uuidStr, kSizeCString, false, uuid );
-               if( err )
-               {
-                       FPrintF( stderr, "Invalid delegate connection UUID value: %s\n", uuidStr );
-                       err = kParamErr;
-                       goto exit;
-               }
-               
-               err = DNSServiceCreateDelegateConnection( &sdRef, 0, uuid );
-               if( err )
-               {
-                       FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for UUID %#U\n", err, uuid );
-                       goto exit;
-               }
-               type = kConnectionType_DelegateUUID;
-       }
-       else
-       {
-               FPrintF( stderr, "Unrecognized connection string \"%s\".\n", inString );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       err = DNSServiceSetDispatchQueue( sdRef, inQueue );
-       require_noerr( err, exit );
-       
-       *outSDRef = sdRef;
-       if( outDesc )
-       {
-               outDesc->type = type;
-               if(      type == kConnectionType_DelegatePID )  outDesc->delegate.pid = pid;
-               else if( type == kConnectionType_DelegateUUID ) memcpy( outDesc->delegate.uuid, uuid, 16 );
-       }
-       sdRef = NULL;
-       
-exit:
-       if( sdRef ) DNSServiceRefDeallocate( sdRef );
-       return( err );
-}
-
-//===========================================================================================================================
-//     InterfaceIndexFromArgString
-//===========================================================================================================================
-
-static OSStatus        InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex )
-{
-       OSStatus                err;
-       uint32_t                ifIndex;
-       
-       if( inString )
-       {
-               ifIndex = if_nametoindex( inString );
-               if( ifIndex == 0 )
-               {
-                       err = StringToUInt32( inString, &ifIndex );
-                       if( err )
-                       {
-                               FPrintF( stderr, "error: Invalid interface value: %s\n", inString );
-                               err = kParamErr;
-                               goto exit;
-                       }
-               }
-       }
-       else
-       {
-               ifIndex = 0;
-       }
-       
-       *outIndex = ifIndex;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     RecordDataFromArgString
-//===========================================================================================================================
-
-static OSStatus        RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen )
-{
-       OSStatus                err;
-       uint8_t *               dataPtr = NULL;
-       size_t                  dataLen;
-       
-       if( 0 ) {}
-       
-       // Domain name
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_Domain ) == 0 )
-       {
-               const char * const              str = inString + sizeof_string( kRDataArgPrefix_Domain );
-               
-               err = StringToDomainName( str, &dataPtr, &dataLen );
-               require_noerr_quiet( err, exit );
-       }
-       
-       // File path
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_File ) == 0 )
-       {
-               const char * const              path = inString + sizeof_string( kRDataArgPrefix_File );
-               
-               err = CopyFileDataByPath( path, (char **) &dataPtr, &dataLen );
-               require_noerr( err, exit );
-               require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
-       }
-       
-       // Hexadecimal string
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_HexString ) == 0 )
-       {
-               const char * const              str = inString + sizeof_string( kRDataArgPrefix_HexString );
-               
-               err = HexToDataCopy( str, kSizeCString, kHexToData_DefaultFlags, &dataPtr, &dataLen, NULL );
-               require_noerr( err, exit );
-               require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
-       }
-       
-       // IPv4 address string
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_IPv4 ) == 0 )
-       {
-               const char * const              str = inString + sizeof_string( kRDataArgPrefix_IPv4 );
-               
-               err = StringToARecordData( str, &dataPtr, &dataLen );
-               require_noerr_quiet( err, exit );
-       }
-       
-       // IPv6 address string
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_IPv6 ) == 0 )
-       {
-               const char * const              str = inString + sizeof_string( kRDataArgPrefix_IPv6 );
-               
-               err = StringToAAAARecordData( str, &dataPtr, &dataLen );
-               require_noerr_quiet( err, exit );
-       }
-       
-       // SRV record
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_SRV ) == 0 )
-       {
-               const char * const              str = inString + sizeof_string( kRDataArgPrefix_SRV );
-               
-               err = CreateSRVRecordDataFromString( str, &dataPtr, &dataLen );
-               require_noerr( err, exit );
-       }
-       
-       // String with escaped hex and octal bytes
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_String ) == 0 )
-       {
-               const char * const              str = inString + sizeof_string( kRDataArgPrefix_String );
-               const char * const              end = str + strlen( str );
-               size_t                                  copiedLen;
-               size_t                                  totalLen;
-               Boolean                                 success;
-               
-               if( str < end )
-               {
-                       success = ParseQuotedEscapedString( str, end, "", NULL, 0, NULL, &totalLen, NULL );
-                       require_action( success, exit, err = kParamErr );
-                       require_action( totalLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
-                       
-                       dataLen = totalLen;
-                       dataPtr = (uint8_t *) malloc( dataLen );
-                       require_action( dataPtr, exit, err = kNoMemoryErr );
-                       
-                       success = ParseQuotedEscapedString( str, end, "", (char *) dataPtr, dataLen, &copiedLen, NULL, NULL );
-                       require_action( success, exit, err = kParamErr );
-                       check( copiedLen == dataLen );
-               }
-               else
-               {
-                       dataPtr = NULL;
-                       dataLen = 0;
-               }
-       }
-       
-       // TXT record
-       
-       else if( stricmp_prefix( inString, kRDataArgPrefix_TXT ) == 0 )
-       {
-               const char * const              str = inString + sizeof_string( kRDataArgPrefix_TXT );
-               
-               err = CreateTXTRecordDataFromString( str, ',', &dataPtr, &dataLen );
-               require_noerr( err, exit );
-       }
-       
-       // Unrecognized format
-       
-       else
-       {
-               FPrintF( stderr, "Unrecognized record data string \"%s\".\n", inString );
-               err = kParamErr;
-               goto exit;
-       }
-       
-       err = kNoErr;
-       *outDataLen = dataLen;
-       *outDataPtr = dataPtr;
-       dataPtr = NULL;
-       
-exit:
-       FreeNullSafe( dataPtr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     RecordTypeFromArgString
-//===========================================================================================================================
-
-typedef struct
-{
-       uint16_t                        value;  // Record type's numeric value.
-       const char *            name;   // Record type's name as a string (e.g., "A", "PTR", "SRV").
-       
-}      RecordType;
-
-static const RecordType                kRecordTypes[] =
-{
-       // Common types.
-       
-       { kDNSServiceType_A,                    "A" },
-       { kDNSServiceType_AAAA,                 "AAAA" },
-       { kDNSServiceType_PTR,                  "PTR" },
-       { kDNSServiceType_SRV,                  "SRV" },
-       { kDNSServiceType_TXT,                  "TXT" },
-       { kDNSServiceType_CNAME,                "CNAME" },
-       { kDNSServiceType_SOA,                  "SOA" },
-       { kDNSServiceType_NSEC,                 "NSEC" },
-       { kDNSServiceType_NS,                   "NS" },
-       { kDNSServiceType_MX,                   "MX" },
-       { kDNSServiceType_ANY,                  "ANY" },
-       { kDNSServiceType_OPT,                  "OPT" },
-       
-       // Less common types.
-       
-       { kDNSServiceType_MD,                   "MD" },
-       { kDNSServiceType_NS,                   "NS" },
-       { kDNSServiceType_MD,                   "MD" },
-       { kDNSServiceType_MF,                   "MF" },
-       { kDNSServiceType_MB,                   "MB" },
-       { kDNSServiceType_MG,                   "MG" },
-       { kDNSServiceType_MR,                   "MR" },
-       { kDNSServiceType_NULL,                 "NULL" },
-       { kDNSServiceType_WKS,                  "WKS" },
-       { kDNSServiceType_HINFO,                "HINFO" },
-       { kDNSServiceType_MINFO,                "MINFO" },
-       { kDNSServiceType_RP,                   "RP" },
-       { kDNSServiceType_AFSDB,                "AFSDB" },
-       { kDNSServiceType_X25,                  "X25" },
-       { kDNSServiceType_ISDN,                 "ISDN" },
-       { kDNSServiceType_RT,                   "RT" },
-       { kDNSServiceType_NSAP,                 "NSAP" },
-       { kDNSServiceType_NSAP_PTR,             "NSAP_PTR" },
-       { kDNSServiceType_SIG,                  "SIG" },
-       { kDNSServiceType_KEY,                  "KEY" },
-       { kDNSServiceType_PX,                   "PX" },
-       { kDNSServiceType_GPOS,                 "GPOS" },
-       { kDNSServiceType_LOC,                  "LOC" },
-       { kDNSServiceType_NXT,                  "NXT" },
-       { kDNSServiceType_EID,                  "EID" },
-       { kDNSServiceType_NIMLOC,               "NIMLOC" },
-       { kDNSServiceType_ATMA,                 "ATMA" },
-       { kDNSServiceType_NAPTR,                "NAPTR" },
-       { kDNSServiceType_KX,                   "KX" },
-       { kDNSServiceType_CERT,                 "CERT" },
-       { kDNSServiceType_A6,                   "A6" },
-       { kDNSServiceType_DNAME,                "DNAME" },
-       { kDNSServiceType_SINK,                 "SINK" },
-       { kDNSServiceType_APL,                  "APL" },
-       { kDNSServiceType_DS,                   "DS" },
-       { kDNSServiceType_SSHFP,                "SSHFP" },
-       { kDNSServiceType_IPSECKEY,             "IPSECKEY" },
-       { kDNSServiceType_RRSIG,                "RRSIG" },
-       { kDNSServiceType_DNSKEY,               "DNSKEY" },
-       { kDNSServiceType_DHCID,                "DHCID" },
-       { kDNSServiceType_NSEC3,                "NSEC3" },
-       { kDNSServiceType_NSEC3PARAM,   "NSEC3PARAM" },
-       { kDNSServiceType_HIP,                  "HIP" },
-       { kDNSServiceType_SPF,                  "SPF" },
-       { kDNSServiceType_UINFO,                "UINFO" },
-       { kDNSServiceType_UID,                  "UID" },
-       { kDNSServiceType_GID,                  "GID" },
-       { kDNSServiceType_UNSPEC,               "UNSPEC" },
-       { kDNSServiceType_TKEY,                 "TKEY" },
-       { kDNSServiceType_TSIG,                 "TSIG" },
-       { kDNSServiceType_IXFR,                 "IXFR" },
-       { kDNSServiceType_AXFR,                 "AXFR" },
-       { kDNSServiceType_MAILB,                "MAILB" },
-       { kDNSServiceType_MAILA,                "MAILA" }
-};
-
-static OSStatus        RecordTypeFromArgString( const char *inString, uint16_t *outValue )
-{
-       OSStatus                                                err;
-       int32_t                                                 i32;
-       const RecordType *                              type;
-       const RecordType * const                end = kRecordTypes + countof( kRecordTypes );
-       
-       for( type = kRecordTypes; type < end; ++type )
-       {
-               if( strcasecmp( type->name, inString ) == 0 )
-               {
-                       *outValue = type->value;
-                       return( kNoErr );
-               }
-       }
-       
-       err = StringToInt32( inString, &i32 );
-       require_noerr_quiet( err, exit );
-       require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
-       
-       *outValue = (uint16_t) i32;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     RecordClassFromArgString
-//===========================================================================================================================
-
-static OSStatus        RecordClassFromArgString( const char *inString, uint16_t *outValue )
-{
-       OSStatus                err;
-       int32_t                 i32;
-       
-       if( strcasecmp( inString, "IN" ) == 0 )
-       {
-               *outValue = kDNSServiceClass_IN;
-               err = kNoErr;
-               goto exit;
-       }
-       
-       err = StringToInt32( inString, &i32 );
-       require_noerr_quiet( err, exit );
-       require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
-       
-       *outValue = (uint16_t) i32;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     InterfaceIndexToName
-//===========================================================================================================================
-
-static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] )
-{
-       switch( inIfIndex )
-       {
-               case kDNSServiceInterfaceIndexAny:
-                       strlcpy( inNameBuf, "Any", kInterfaceNameBufLen );
-                       break;
-               
-               case kDNSServiceInterfaceIndexLocalOnly:
-                       strlcpy( inNameBuf, "LocalOnly", kInterfaceNameBufLen );
-                       break;
-               
-               case kDNSServiceInterfaceIndexUnicast:
-                       strlcpy( inNameBuf, "Unicast", kInterfaceNameBufLen );
-                       break;
-               
-               case kDNSServiceInterfaceIndexP2P:
-                       strlcpy( inNameBuf, "P2P", kInterfaceNameBufLen );
-                       break;
-               
-       #if( defined( kDNSServiceInterfaceIndexBLE ) )
-               case kDNSServiceInterfaceIndexBLE:
-                       strlcpy( inNameBuf, "BLE", kInterfaceNameBufLen );
-                       break;
-       #endif
-               
-               default:
-               {
-                       const char *            name;
-                       
-                       name = if_indextoname( inIfIndex, inNameBuf );
-                       if( !name ) strlcpy( inNameBuf, "NO NAME", kInterfaceNameBufLen );
-                       break;
-               }
-       }
-       
-       return( inNameBuf );
-}
-
-//===========================================================================================================================
-//     RecordTypeToString
-//===========================================================================================================================
-
-static const char *    RecordTypeToString( unsigned int inValue )
-{
-       const RecordType *                              type;
-       const RecordType * const                end = kRecordTypes + countof( kRecordTypes );
-       
-       for( type = kRecordTypes; type < end; ++type )
-       {
-               if( type->value == inValue ) return( type->name );
-       }
-       return( "???" );
-}
-
-//===========================================================================================================================
-//     DNSMessageExtractDomainName
-//===========================================================================================================================
-
-static OSStatus
-       DNSMessageExtractDomainName(
-               const uint8_t *         inMsgPtr,
-               size_t                          inMsgLen,
-               const uint8_t *         inNamePtr,
-               uint8_t                         inBuf[ kDomainNameLengthMax ],
-               const uint8_t **        outNextPtr )
-{
-       OSStatus                                        err;
-       const uint8_t *                         label;
-       uint8_t                                         labelLen;
-       const uint8_t *                         nextLabel;
-       const uint8_t * const           msgEnd  = inMsgPtr + inMsgLen;
-       uint8_t *                                       dst             = inBuf;
-       const uint8_t * const           dstLim  = inBuf ? ( inBuf + kDomainNameLengthMax ) : NULL;
-       const uint8_t *                         nameEnd = NULL;
-       
-       require_action( ( inNamePtr >= inMsgPtr ) && ( inNamePtr < msgEnd ), exit, err = kRangeErr );
-       
-       for( label = inNamePtr; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
-       {
-               if( labelLen <= kDomainLabelLengthMax )
-               {
-                       nextLabel = label + 1 + labelLen;
-                       require_action( nextLabel < msgEnd, exit, err = kUnderrunErr );
-                       if( dst )
-                       {
-                               require_action( ( dstLim - dst ) > ( 1 + labelLen ), exit, err = kOverrunErr );
-                               memcpy( dst, label, 1 + labelLen );
-                               dst += ( 1 + labelLen );
-                       }
-               }
-               else if( IsCompressionByte( labelLen ) )
-               {
-                       uint16_t                offset;
-                       
-                       require_action( ( msgEnd - label ) >= 2, exit, err = kUnderrunErr );
-                       if( !nameEnd )
-                       {
-                               nameEnd = label + 2;
-                               if( !dst ) break;
-                       }
-                       offset = (uint16_t)( ( ( label[ 0 ] & 0x3F ) << 8 ) | label[ 1 ] );
-                       nextLabel = inMsgPtr + offset;
-                       require_action( nextLabel < msgEnd, exit, err = kUnderrunErr );
-                       require_action( !IsCompressionByte( nextLabel[ 0 ] ), exit, err = kMalformedErr );
-               }
-               else
-               {
-                       dlogassert( "Unhandled label length 0x%02X\n", labelLen );
-                       err = kMalformedErr;
-                       goto exit;
-               }
-       }
-       
-       if( dst ) *dst = 0;
-       if( !nameEnd ) nameEnd = label + 1;
-       
-       if( outNextPtr ) *outNextPtr = nameEnd;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSMessageExtractDomainNameString
-//===========================================================================================================================
-
-static OSStatus
-       DNSMessageExtractDomainNameString(
-               const void *            inMsgPtr,
-               size_t                          inMsgLen,
-               const void *            inNamePtr,
-               char                            inBuf[ kDNSServiceMaxDomainName ],
-               const uint8_t **        outNextPtr )
-{
-       OSStatus                        err;
-       const uint8_t *         nextPtr;
-       uint8_t                         domainName[ kDomainNameLengthMax ];
-       
-       err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inNamePtr, domainName, &nextPtr );
-       require_noerr( err, exit );
-       
-       err = DomainNameToString( domainName, NULL, inBuf, NULL );
-       require_noerr( err, exit );
-       
-       if( outNextPtr ) *outNextPtr = nextPtr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSMessageExtractQuestion
-//===========================================================================================================================
-
-static OSStatus
-       DNSMessageExtractQuestion(
-               const uint8_t *         inMsgPtr,
-               size_t                          inMsgLen,
-               const uint8_t *         inPtr,
-               uint8_t                         inNameBuf[ kDomainNameLengthMax ],
-               uint16_t *                      outType,
-               uint16_t *                      outClass,
-               const uint8_t **        outPtr )
-{
-       OSStatus                                                        err;
-       const uint8_t * const                           msgEnd = &inMsgPtr[ inMsgLen ];
-       const uint8_t *                                         ptr;
-       const DNSQuestionFixedFields *          fields;
-       
-       err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, inNameBuf, &ptr );
-       require_noerr_quiet( err, exit );
-       require_action_quiet( (size_t)( msgEnd - ptr ) >= sizeof( DNSQuestionFixedFields ), exit, err = kUnderrunErr );
-       
-       fields = (const DNSQuestionFixedFields *) ptr;
-       if( outType )  *outType  = DNSQuestionFixedFieldsGetType( fields );
-       if( outClass ) *outClass = DNSQuestionFixedFieldsGetClass( fields );
-       if( outPtr )   *outPtr   = (const uint8_t *) &fields[ 1 ];
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSMessageExtractRecord
-//===========================================================================================================================
-
-typedef struct
-{
-       uint8_t         type[ 2 ];
-       uint8_t         class[ 2 ];
-       uint8_t         ttl[ 4 ];
-       uint8_t         rdLength[ 2 ];
-       uint8_t         rdata[ 1 ];
-       
-}      DNSRecordFields;
-
-check_compile_time( offsetof( DNSRecordFields, rdata ) == 10 );
-
-static OSStatus
-       DNSMessageExtractRecord(
-               const uint8_t *         inMsgPtr,
-               size_t                          inMsgLen,
-               const uint8_t *         inPtr,
-               uint8_t                         inNameBuf[ kDomainNameLengthMax ],
-               uint16_t *                      outType,
-               uint16_t *                      outClass,
-               uint32_t *                      outTTL,
-               const uint8_t **        outRDataPtr,
-               size_t *                        outRDataLen,
-               const uint8_t **        outPtr )
-{
-       OSStatus                                        err;
-       const uint8_t * const           msgEnd = inMsgPtr + inMsgLen;
-       const uint8_t *                         ptr;
-       const DNSRecordFields *         record;
-       size_t                                          rdLength;
-       
-       err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, inNameBuf, &ptr );
-       require_noerr_quiet( err, exit );
-       require_action_quiet( (size_t)( msgEnd - ptr ) >= offsetof( DNSRecordFields, rdata ), exit, err = kUnderrunErr );
-       
-       record = (DNSRecordFields *) ptr;
-       rdLength = ReadBig16( record->rdLength );
-       require_action_quiet( (size_t)( msgEnd - record->rdata ) >= rdLength , exit, err = kUnderrunErr );
-       
-       if( outType )           *outType                = ReadBig16( record->type );
-       if( outClass )          *outClass               = ReadBig16( record->class );
-       if( outTTL )            *outTTL                 = ReadBig32( record->ttl );
-       if( outRDataPtr )       *outRDataPtr    = record->rdata;
-       if( outRDataLen )       *outRDataLen    = rdLength;
-       if( outPtr )            *outPtr                 = record->rdata + rdLength;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSMessageGetAnswerSection
-//===========================================================================================================================
-
-static OSStatus        DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr )
-{
-       OSStatus                                err;
-       unsigned int                    questionCount, i;
-       const DNSHeader *               hdr;
-       const uint8_t *                 ptr;
-       
-       require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
-       
-       hdr = (DNSHeader *) inMsgPtr;
-       questionCount = DNSHeaderGetQuestionCount( hdr );
-       
-       ptr = (const uint8_t *) &hdr[ 1 ];
-       for( i = 0; i < questionCount; ++i )
-       {
-               err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, NULL, NULL, NULL, &ptr );
-               require_noerr( err, exit );
-       }
-       
-       if( outPtr ) *outPtr = ptr;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSRecordDataToString
-//===========================================================================================================================
-
-static OSStatus
-       DNSRecordDataToString(
-               const void *    inRDataPtr,
-               size_t                  inRDataLen,
-               unsigned int    inRDataType,
-               const void *    inMsgPtr,
-               size_t                  inMsgLen,
-               char **                 outString )
-{
-       OSStatus                                        err;
-       const uint8_t * const           rdataPtr = (uint8_t *) inRDataPtr;
-       const uint8_t * const           rdataEnd = rdataPtr + inRDataLen;
-       char *                                          rdataStr;
-       const uint8_t *                         ptr;
-       int                                                     n;
-       char                                            domainNameStr[ kDNSServiceMaxDomainName ];
-       
-       rdataStr = NULL;
-       if( inRDataType == kDNSServiceType_A )
-       {
-               require_action_quiet( inRDataLen == 4, exit, err = kMalformedErr );
-               
-               ASPrintF( &rdataStr, "%.4a", rdataPtr );
-               require_action( rdataStr, exit, err = kNoMemoryErr );
-       }
-       else if( inRDataType == kDNSServiceType_AAAA )
-       {
-               require_action_quiet( inRDataLen == 16, exit, err = kMalformedErr );
-               
-               ASPrintF( &rdataStr, "%.16a", rdataPtr );
-               require_action( rdataStr, exit, err = kNoMemoryErr );
-       }
-       else if( ( inRDataType == kDNSServiceType_PTR ) || ( inRDataType == kDNSServiceType_CNAME ) ||
-                       ( inRDataType == kDNSServiceType_NS ) )
-       {
-               if( inMsgPtr )
-               {
-                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, NULL );
-                       require_noerr( err, exit );
-               }
-               else
-               {
-                       err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, NULL );
-                       require_noerr( err, exit );
-               }
-               
-               rdataStr = strdup( domainNameStr );
-               require_action( rdataStr, exit, err = kNoMemoryErr );
-       }
-       else if( inRDataType == kDNSServiceType_SRV )
-       {
-               const SRVRecordDataFixedFields *                fields;
-               const uint8_t *                                                 target;
-               unsigned int                                                    priority, weight, port;
-               
-               require_action_quiet( inRDataLen > sizeof( SRVRecordDataFixedFields ), exit, err = kMalformedErr );
-               
-               fields = (const SRVRecordDataFixedFields *) rdataPtr;
-               SRVRecordDataFixedFieldsGet( fields, &priority, &weight, &port );
-               target = (const uint8_t *) &fields[ 1 ];
-               
-               if( inMsgPtr )
-               {
-                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, target, domainNameStr, NULL );
-                       require_noerr( err, exit );
-               }
-               else
-               {
-                       err = DomainNameToString( target, rdataEnd, domainNameStr, NULL );
-                       require_noerr( err, exit );
-               }
-               
-               ASPrintF( &rdataStr, "%u %u %u %s", priority, weight, port, domainNameStr );
-               require_action( rdataStr, exit, err = kNoMemoryErr );
-       }
-       else if( inRDataType == kDNSServiceType_TXT )
-       {
-               require_action_quiet( inRDataLen > 0, exit, err = kMalformedErr );
-               
-               if( inRDataLen == 1 )
-               {
-                       ASPrintF( &rdataStr, "%#H", rdataPtr, (int) inRDataLen, INT_MAX );
-                       require_action( rdataStr, exit, err = kNoMemoryErr );
-               }
-               else
-               {
-                       ASPrintF( &rdataStr, "%#{txt}", rdataPtr, inRDataLen );
-                       require_action( rdataStr, exit, err = kNoMemoryErr );
-               }
-       }
-       else if( inRDataType == kDNSServiceType_SOA )
-       {
-               uint32_t                serial, refresh, retry, expire, minimum;
-               
-               if( inMsgPtr )
-               {
-                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
-                       require_noerr( err, exit );
-                       
-                       require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
-                       
-                       rdataStr = strdup( domainNameStr );
-                       require_action( rdataStr, exit, err = kNoMemoryErr );
-                       
-                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, ptr, domainNameStr, &ptr );
-                       require_noerr( err, exit );
-               }
-               else
-               {
-                       err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
-                       require_noerr( err, exit );
-                       
-                       rdataStr = strdup( domainNameStr );
-                       require_action( rdataStr, exit, err = kNoMemoryErr );
-                       
-                       err = DomainNameToString( ptr, rdataEnd, domainNameStr, &ptr );
-                       require_noerr( err, exit );
-               }
-               
-               require_action_quiet( ( rdataEnd - ptr ) == sizeof( SOARecordDataFixedFields ), exit, err = kMalformedErr );
-               
-               SOARecordDataFixedFieldsGet( (const SOARecordDataFixedFields *) ptr, &serial, &refresh, &retry, &expire, &minimum );
-               
-               n = AppendPrintF( &rdataStr, " %s %u %u %u %u %u\n", domainNameStr, serial, refresh, retry, expire, minimum );
-               require_action( n > 0, exit, err = kUnknownErr );
-       }
-       else if( inRDataType == kDNSServiceType_NSEC )
-       {
-               unsigned int            windowBlock, bitmapLen, i, recordType;
-               const uint8_t *         bitmapPtr;
-               
-               if( inMsgPtr )
-               {
-                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
-                       require_noerr( err, exit );
-               }
-               else
-               {
-                       err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
-                       require_noerr( err, exit );
-               }
-               
-               require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
-               
-               rdataStr = strdup( domainNameStr );
-               require_action( rdataStr, exit, err = kNoMemoryErr );
-               
-               for( ; ptr < rdataEnd; ptr += ( 2 + bitmapLen ) )
-               {
-                       require_action_quiet( ( ptr + 2 ) < rdataEnd, exit, err = kMalformedErr );
-                       
-                       windowBlock     =  ptr[ 0 ];
-                       bitmapLen       =  ptr[ 1 ];
-                       bitmapPtr       = &ptr[ 2 ];
-                       
-                       require_action_quiet( ( bitmapLen >= 1 ) && ( bitmapLen <= 32 ) , exit, err = kMalformedErr );
-                       require_action_quiet( ( bitmapPtr + bitmapLen ) <= rdataEnd, exit, err = kMalformedErr );
-                       
-                       for( i = 0; i < BitArray_MaxBits( bitmapLen ); ++i )
-                       {
-                               if( BitArray_GetBit( bitmapPtr, bitmapLen, i ) )
-                               {
-                                       recordType = ( windowBlock * 256 ) + i;
-                                       n = AppendPrintF( &rdataStr, " %s", RecordTypeToString( recordType ) );
-                                       require_action( n > 0, exit, err = kUnknownErr );
-                               }
-                       }
-               }
-       }
-       else if( inRDataType == kDNSServiceType_MX )
-       {
-               uint16_t                        preference;
-               const uint8_t *         exchange;
-               
-               require_action_quiet( ( rdataPtr + 2 ) < rdataEnd, exit, err = kMalformedErr );
-               
-               preference      = ReadBig16( rdataPtr );
-               exchange        = &rdataPtr[ 2 ];
-               
-               if( inMsgPtr )
-               {
-                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, exchange, domainNameStr, NULL );
-                       require_noerr( err, exit );
-               }
-               else
-               {
-                       err = DomainNameToString( exchange, rdataEnd, domainNameStr, NULL );
-                       require_noerr( err, exit );
-               }
-               
-               n = ASPrintF( &rdataStr, "%u %s", preference, domainNameStr );
-               require_action( n > 0, exit, err = kUnknownErr );
-       }
-       else
-       {
-               err = kNotHandledErr;
-               goto exit;
-       }
-       
-       check( rdataStr );
-       *outString = rdataStr;
-       rdataStr = NULL;
-       err = kNoErr;
-       
-exit:
-       FreeNullSafe( rdataStr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     DomainNameAppendString
-//===========================================================================================================================
-
-static OSStatus
-       DomainNameAppendString(
-               uint8_t                 inDomainName[ kDomainNameLengthMax ],
-               const char *    inString,
-               uint8_t **              outEndPtr )
-{
-       OSStatus                                        err;
-       const char *                            src;
-       uint8_t *                                       root;
-       const uint8_t * const           nameLim = inDomainName + kDomainNameLengthMax;
-       
-       for( root = inDomainName; ( root < nameLim ) && *root; root += ( 1 + *root ) ) {}
-       require_action_quiet( root < nameLim, exit, err = kMalformedErr );
-       
-       // If the string is a single dot, denoting the root domain, then there are no non-empty labels.
-       
-       src = inString;
-       if( ( src[ 0 ] == '.' ) && ( src[ 1 ] == '\0' ) ) ++src;
-       while( *src )
-       {
-               uint8_t * const                         label           = root;
-               const uint8_t * const           labelLim        = Min( &label[ 1 + kDomainLabelLengthMax ], nameLim - 1 );
-               uint8_t *                                       dst;
-               int                                                     c;
-               size_t                                          labelLen;
-               
-               dst = &label[ 1 ];
-               while( *src && ( ( c = *src++ ) != '.' ) )
-               {
-                       if( c == '\\' )
-                       {
-                               require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
-                               c = *src++;
-                               if( isdigit_safe( c ) && isdigit_safe( src[ 0 ] ) && isdigit_safe( src[ 1 ] ) )
-                               {
-                                       const int               decimal = ( ( c - '0' ) * 100 ) + ( ( src[ 0 ] - '0' ) * 10 ) + ( src[ 1 ] - '0' );
-                                       
-                                       if( decimal <= 255 )
-                                       {
-                                               c = decimal;
-                                               src += 2;
-                                       }
-                               }
-                       }
-                       require_action_quiet( dst < labelLim, exit, err = kOverrunErr );
-                       *dst++ = (uint8_t) c;
-               }
-               
-               labelLen = (size_t)( dst - &label[ 1 ] );
-               require_action_quiet( labelLen > 0, exit, err = kMalformedErr );
-               
-               label[ 0 ] = (uint8_t) labelLen;
-               root = dst;
-               *root = 0;
-       }
-       
-       if( outEndPtr ) *outEndPtr = root + 1;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DomainNameEqual
-//===========================================================================================================================
-
-static Boolean DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 )
-{
-       const uint8_t *         p1 = inName1;
-       const uint8_t *         p2 = inName2;
-       unsigned int            len;
-       
-       for( ;; )
-       {
-               if( ( len = *p1++ ) != *p2++ ) return( false );
-               if( len == 0 ) break;
-               for( ; len > 0; ++p1, ++p2, --len )
-               {
-                       if( tolower_safe( *p1 ) != tolower_safe( *p2 ) ) return( false );
-               }
-       }
-       return( true );
-}
-
-//===========================================================================================================================
-//     DomainNameLength
-//===========================================================================================================================
-
-static size_t  DomainNameLength( const uint8_t * const inName )
-{
-       const uint8_t *         ptr;
-       
-       for( ptr = inName; *ptr != 0; ptr += ( 1 + *ptr ) ) {}
-       return( (size_t)( ptr - inName ) + 1 );
-}
-
-//===========================================================================================================================
-//     DomainNameDupEx
-//===========================================================================================================================
-
-static OSStatus        DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen )
-{
-       OSStatus                        err;
-       uint8_t *                       namePtr;
-       const size_t            nameLen = DomainNameLength( inName );
-       
-       if( inLower )
-       {
-               const uint8_t *         src;
-               uint8_t *                       dst;
-               unsigned int            len;
-               
-               namePtr = (uint8_t *) malloc( nameLen );
-               require_action( namePtr, exit, err = kNoMemoryErr );
-               
-               src = inName;
-               dst = namePtr;
-               while( ( len = *src ) != 0 )
-               {
-                       *dst++ = *src++;
-                       while( len-- )
-                       {
-                               *dst++ = (uint8_t) tolower_safe( *src );
-                               ++src;
-                       }
-               }
-               *dst = 0;
-       }
-       else
-       {
-               namePtr = (uint8_t *) memdup( inName, nameLen );
-               require_action( namePtr, exit, err = kNoMemoryErr );
-       }
-       
-       *outNamePtr = namePtr;
-       if( outNameLen ) *outNameLen = nameLen;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DomainNameFromString
-//===========================================================================================================================
-
-static OSStatus
-       DomainNameFromString(
-               uint8_t                 inDomainName[ kDomainNameLengthMax ],
-               const char *    inString,
-               uint8_t **              outEndPtr )
-{
-       inDomainName[ 0 ] = 0;
-       return( DomainNameAppendString( inDomainName, inString, outEndPtr ) );
-}
-
-//===========================================================================================================================
-//     DomainNameToString
-//===========================================================================================================================
-
-static OSStatus
-       DomainNameToString(
-               const uint8_t *         inDomainName,
-               const uint8_t *         inEnd,
-               char                            inBuf[ kDNSServiceMaxDomainName ],
-               const uint8_t **        outNextPtr )
-{
-       OSStatus                        err;
-       const uint8_t *         label;
-       uint8_t                         labelLen;
-       const uint8_t *         nextLabel;
-       char *                          dst;
-       const uint8_t *         src;
-       
-       require_action( !inEnd || ( inDomainName < inEnd ), exit, err = kUnderrunErr );
-       
-       // Convert each label up until the root label, i.e., the zero-length label.
-       
-       dst = inBuf;
-       for( label = inDomainName; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
-       {
-               require_action( labelLen <= kDomainLabelLengthMax, exit, err = kMalformedErr );
-               
-               nextLabel = &label[ 1 ] + labelLen;
-               require_action( ( nextLabel - inDomainName ) < kDomainNameLengthMax, exit, err = kMalformedErr );
-               require_action( !inEnd || ( nextLabel < inEnd ), exit, err = kUnderrunErr );
-               
-               for( src = &label[ 1 ]; src < nextLabel; ++src )
-               {
-                       if( isprint_safe( *src ) )
-                       {
-                               if( ( *src == '.' ) || ( *src == '\\' ) ||  ( *src == ' ' ) ) *dst++ = '\\';
-                               *dst++ = (char) *src;
-                       }
-                       else
-                       {
-                               *dst++ = '\\';
-                               *dst++ = '0' + (   *src / 100 );
-                               *dst++ = '0' + ( ( *src /  10 ) % 10 );
-                               *dst++ = '0' + (   *src         % 10 );
-                       }
-               }
-               *dst++ = '.';
-       }
-       
-       // At this point, label points to the root label.
-       // If the root label was the only label, then write a dot for it.
-       
-       if( label == inDomainName ) *dst++ = '.';
-       *dst = '\0';
-       if( outNextPtr ) *outNextPtr = label + 1;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSMessageToText
-//===========================================================================================================================
-
-#define DNSFlagsOpCodeToString( X ) (                                  \
-       ( (X) == kDNSOpCode_Query )                     ? "Query"       :       \
-       ( (X) == kDNSOpCode_InverseQuery )      ? "IQuery"      :       \
-       ( (X) == kDNSOpCode_Status )            ? "Status"      :       \
-       ( (X) == kDNSOpCode_Notify )            ? "Notify"      :       \
-       ( (X) == kDNSOpCode_Update )            ? "Update"      :       \
-                                                                                 "Unassigned" )
-
-#define DNSFlagsRCodeToString( X ) (                                           \
-       ( (X) == kDNSRCode_NoError )            ? "NoError"             :       \
-       ( (X) == kDNSRCode_FormatError )        ? "FormErr"             :       \
-       ( (X) == kDNSRCode_ServerFailure )      ? "ServFail"    :       \
-       ( (X) == kDNSRCode_NXDomain )           ? "NXDomain"    :       \
-       ( (X) == kDNSRCode_NotImplemented )     ? "NotImp"              :       \
-       ( (X) == kDNSRCode_Refused )            ? "Refused"             :       \
-                                                                                 "???" )
-
-static OSStatus
-       DNSMessageToText(
-               const uint8_t * inMsgPtr,
-               size_t                  inMsgLen,
-               const Boolean   inMDNS,
-               const Boolean   inPrintRaw,
-               char **                 outText )
-{
-       OSStatus                                err;
-       DataBuffer                              dataBuf;
-       size_t                                  len;
-       const DNSHeader *               hdr;
-       const uint8_t *                 ptr;
-       unsigned int                    id, flags, opcode, rcode;
-       unsigned int                    questionCount, answerCount, authorityCount, additionalCount, i, totalRRCount;
-       uint8_t                                 name[ kDomainNameLengthMax ];
-       char                                    nameStr[ kDNSServiceMaxDomainName ];
-       
-       DataBuffer_Init( &dataBuf, NULL, 0, SIZE_MAX );
-       #define _Append( ... )          do { err = DataBuffer_AppendF( &dataBuf, __VA_ARGS__ ); require_noerr( err, exit ); } while( 0 )
-       
-       require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
-       
-       hdr                             = (DNSHeader *) inMsgPtr;
-       id                              = DNSHeaderGetID( hdr );
-       flags                   = DNSHeaderGetFlags( hdr );
-       questionCount   = DNSHeaderGetQuestionCount( hdr );
-       answerCount             = DNSHeaderGetAnswerCount( hdr );
-       authorityCount  = DNSHeaderGetAuthorityCount( hdr );
-       additionalCount = DNSHeaderGetAdditionalCount( hdr );
-       opcode                  = DNSFlagsGetOpCode( flags );
-       rcode                   = DNSFlagsGetRCode( flags );
-       
-       _Append( "ID:               0x%04X (%u)\n", id, id );
-       _Append( "Flags:            0x%04X %c/%s %cAA%cTC%cRD%cRA%?s%?s %s\n",
-               flags,
-               ( flags & kDNSHeaderFlag_Response )                             ? 'R' : 'Q', DNSFlagsOpCodeToString( opcode ),
-               ( flags & kDNSHeaderFlag_AuthAnswer )                   ? ' ' : '!',
-               ( flags & kDNSHeaderFlag_Truncation )                   ? ' ' : '!',
-               ( flags & kDNSHeaderFlag_RecursionDesired )             ? ' ' : '!',
-               ( flags & kDNSHeaderFlag_RecursionAvailable )   ? ' ' : '!',
-               !inMDNS, ( flags & kDNSHeaderFlag_AuthenticData )               ? " AD" : "!AD",
-               !inMDNS, ( flags & kDNSHeaderFlag_CheckingDisabled )    ? " CD" : "!CD",
-               DNSFlagsRCodeToString( rcode ) );
-       _Append( "Question count:   %u\n", questionCount );
-       _Append( "Answer count:     %u\n", answerCount );
-       _Append( "Authority count:  %u\n", authorityCount );
-       _Append( "Additional count: %u\n", additionalCount );
-       
-       ptr = (const uint8_t *) &hdr[ 1 ];
-       for( i = 0; i < questionCount; ++i )
-       {
-               uint16_t                qtype, qclass;
-               Boolean                 isQU;
-               
-               err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, name, &qtype, &qclass, &ptr );
-               require_noerr( err, exit );
-               
-               err = DomainNameToString( name, NULL, nameStr, NULL );
-               require_noerr( err, exit );
-               
-               isQU = ( inMDNS && ( qclass & kQClassUnicastResponseBit ) ) ? true : false;
-               if( inMDNS ) qclass &= ~kQClassUnicastResponseBit;
-               
-               if( i == 0 ) _Append( "\nQUESTION SECTION\n" );
-               
-               _Append( "%-30s %2s %?2s%?2u %-5s\n",
-                       nameStr, inMDNS ? ( isQU ? "QU" : "QM" ) : "",
-                       ( qclass == kDNSServiceClass_IN ), "IN", ( qclass != kDNSServiceClass_IN ), qclass, RecordTypeToString( qtype ) );
-       }
-       
-       totalRRCount = answerCount + authorityCount + additionalCount;
-       for( i = 0; i < totalRRCount; ++i )
-       {
-               uint16_t                        type;
-               uint16_t                        class;
-               uint32_t                        ttl;
-               const uint8_t *         rdataPtr;
-               size_t                          rdataLen;
-               char *                          rdataStr;
-               Boolean                         cacheFlush;
-               
-               err = DNSMessageExtractRecord( inMsgPtr, inMsgLen, ptr, name, &type, &class, &ttl, &rdataPtr, &rdataLen, &ptr );
-               require_noerr( err, exit );
-               
-               err = DomainNameToString( name, NULL, nameStr, NULL );
-               require_noerr( err, exit );
-               
-               cacheFlush = ( inMDNS && ( class & kRRClassCacheFlushBit ) ) ? true : false;
-               if( inMDNS ) class &= ~kRRClassCacheFlushBit;
-               
-               rdataStr = NULL;
-               if( !inPrintRaw ) DNSRecordDataToString( rdataPtr, rdataLen, type, inMsgPtr, inMsgLen, &rdataStr );
-               if( !rdataStr )
-               {
-                       ASPrintF( &rdataStr, "%#H", rdataPtr, (int) rdataLen, INT_MAX );
-                       require_action( rdataStr, exit, err = kNoMemoryErr );
-               }
-               
-               if(      answerCount     && ( i ==   0                              ) ) _Append( "\nANSWER SECTION\n" );
-               else if( authorityCount  && ( i ==   answerCount                    ) ) _Append( "\nAUTHORITY SECTION\n" );
-               else if( additionalCount && ( i == ( answerCount + authorityCount ) ) ) _Append( "\nADDITIONAL SECTION\n" );
-               
-               _Append( "%-42s %6u %2s %?2s%?2u %-5s %s\n",
-                       nameStr, ttl, cacheFlush ? "CF" : "",
-                       ( class == kDNSServiceClass_IN ), "IN", ( class != kDNSServiceClass_IN ), class,
-                       RecordTypeToString( type ), rdataStr );
-               free( rdataStr );
-       }
-       _Append( "\n" );
-       
-       err = DataBuffer_Append( &dataBuf, "", 1 );
-       require_noerr( err, exit );
-       
-       err = DataBuffer_Detach( &dataBuf, (uint8_t **) outText, &len );
-       require_noerr( err, exit );
-       
-exit:
-       DataBuffer_Free( &dataBuf );
-       return( err );
-}
-
-//===========================================================================================================================
-//     WriteDNSQueryMessage
-//===========================================================================================================================
-
-static OSStatus
-       WriteDNSQueryMessage(
-               uint8_t                 inMsg[ kDNSQueryMessageMaxLen ],
-               uint16_t                inMsgID,
-               uint16_t                inFlags,
-               const char *    inQName,
-               uint16_t                inQType,
-               uint16_t                inQClass,
-               size_t *                outMsgLen )
-{
-       OSStatus                                err;
-       DNSHeader * const               hdr = (DNSHeader *) inMsg;
-       uint8_t *                               ptr;
-       size_t                                  msgLen;
-       
-       memset( hdr, 0, sizeof( *hdr ) );
-       DNSHeaderSetID( hdr, inMsgID );
-       DNSHeaderSetFlags( hdr, inFlags );
-       DNSHeaderSetQuestionCount( hdr, 1 );
-       
-       ptr = (uint8_t *)( hdr + 1 );
-       err = DomainNameFromString( ptr, inQName, &ptr );
-       require_noerr_quiet( err, exit );
-       
-       DNSQuestionFixedFieldsInit( (DNSQuestionFixedFields *) ptr, inQType, inQClass );
-       ptr += 4;
-       
-       msgLen = (size_t)( ptr - inMsg );
-       check( msgLen <= kDNSQueryMessageMaxLen );
-       
-       if( outMsgLen ) *outMsgLen = msgLen;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DispatchSignalSourceCreate
-//===========================================================================================================================
-
-static OSStatus
-       DispatchSignalSourceCreate(
-               int                                     inSignal,
-               DispatchHandler         inEventHandler,
-               void *                          inContext,
-               dispatch_source_t *     outSource )
-{
-       OSStatus                                err;
-       dispatch_source_t               source;
-       
-       source = dispatch_source_create( DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t) inSignal, 0, dispatch_get_main_queue() );
-       require_action( source, exit, err = kUnknownErr );
-       
-       dispatch_set_context( source, inContext );
-       dispatch_source_set_event_handler_f( source, inEventHandler );
-       
-       *outSource = source;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DispatchSocketSourceCreate
-//===========================================================================================================================
-
-static OSStatus
-       DispatchSocketSourceCreate(
-               SocketRef                               inSock,
-               dispatch_source_type_t  inType,
-               dispatch_queue_t                inQueue,
-               DispatchHandler                 inEventHandler,
-               DispatchHandler                 inCancelHandler,
-               void *                                  inContext,
-               dispatch_source_t *             outSource )
-{
-       OSStatus                                err;
-       dispatch_source_t               source;
-       
-       source = dispatch_source_create( inType, (uintptr_t) inSock, 0, inQueue ? inQueue : dispatch_get_main_queue() );
-       require_action( source, exit, err = kUnknownErr );
-       
-       dispatch_set_context( source, inContext );
-       dispatch_source_set_event_handler_f( source, inEventHandler );
-       dispatch_source_set_cancel_handler_f( source, inCancelHandler );
-       
-       *outSource = source;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DispatchTimerCreate
-//===========================================================================================================================
-
-static OSStatus
-       DispatchTimerCreate(
-               dispatch_time_t         inStart,
-               uint64_t                        inIntervalNs,
-               uint64_t                        inLeewayNs,
-               dispatch_queue_t        inQueue,
-               DispatchHandler         inEventHandler,
-               DispatchHandler         inCancelHandler,
-               void *                          inContext,
-               dispatch_source_t *     outTimer )
-{
-       OSStatus                                err;
-       dispatch_source_t               timer;
-       
-       timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, inQueue ? inQueue : dispatch_get_main_queue() );
-       require_action( timer, exit, err = kUnknownErr );
-       
-       dispatch_source_set_timer( timer, inStart, inIntervalNs, inLeewayNs );
-       dispatch_set_context( timer, inContext );
-       dispatch_source_set_event_handler_f( timer, inEventHandler );
-       dispatch_source_set_cancel_handler_f( timer, inCancelHandler );
-       
-       *outTimer = timer;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     DispatchProcessMonitorCreate
-//===========================================================================================================================
-
-static OSStatus
-       DispatchProcessMonitorCreate(
-               pid_t                           inPID,
-               unsigned long           inFlags,
-               dispatch_queue_t        inQueue,
-               DispatchHandler         inEventHandler,
-               DispatchHandler         inCancelHandler,
-               void *                          inContext,
-               dispatch_source_t *     outMonitor )
-{
-       OSStatus                                err;
-       dispatch_source_t               monitor;
-       
-       monitor = dispatch_source_create( DISPATCH_SOURCE_TYPE_PROC, (uintptr_t) inPID, inFlags,
-               inQueue ? inQueue : dispatch_get_main_queue() );
-       require_action( monitor, exit, err = kUnknownErr );
-       
-       dispatch_set_context( monitor, inContext );
-       dispatch_source_set_event_handler_f( monitor, inEventHandler );
-       dispatch_source_set_cancel_handler_f( monitor, inCancelHandler );
-       
-       *outMonitor = monitor;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     ServiceTypeDescription
-//===========================================================================================================================
-
-typedef struct
-{
-       const char *            name;                   // Name of the service type in two-label "_service._proto" format.
-       const char *            description;    // Description of the service type.
-       
-}      ServiceType;
-
-// A Non-comprehensive table of DNS-SD service types
-
-static const ServiceType               kServiceTypes[] =
-{
-       { "_acp-sync._tcp",                     "AirPort Base Station Sync" },
-       { "_adisk._tcp",                        "Automatic Disk Discovery" },
-       { "_afpovertcp._tcp",           "Apple File Sharing" },
-       { "_airdrop._tcp",                      "AirDrop" },
-       { "_airplay._tcp",                      "AirPlay" },
-       { "_airport._tcp",                      "AirPort Base Station" },
-       { "_daap._tcp",                         "Digital Audio Access Protocol (iTunes)" },
-       { "_eppc._tcp",                         "Remote AppleEvents" },
-       { "_ftp._tcp",                          "File Transfer Protocol" },
-       { "_home-sharing._tcp",         "Home Sharing" },
-       { "_homekit._tcp",                      "HomeKit" },
-       { "_http._tcp",                         "World Wide Web HTML-over-HTTP" },
-       { "_https._tcp",                        "HTTP over SSL/TLS" },
-       { "_ipp._tcp",                          "Internet Printing Protocol" },
-       { "_ldap._tcp",                         "Lightweight Directory Access Protocol" },
-       { "_mediaremotetv._tcp",        "Media Remote" },
-       { "_net-assistant._tcp",        "Apple Remote Desktop" },
-       { "_od-master._tcp",            "OpenDirectory Master" },
-       { "_nfs._tcp",                          "Network File System" },
-       { "_presence._tcp",                     "Peer-to-peer messaging / Link-Local Messaging" },
-       { "_pdl-datastream._tcp",       "Printer Page Description Language Data Stream" },
-       { "_raop._tcp",                         "Remote Audio Output Protocol" },
-       { "_rfb._tcp",                          "Remote Frame Buffer" },
-       { "_scanner._tcp",                      "Bonjour Scanning" },
-       { "_smb._tcp",                          "Server Message Block over TCP/IP" },
-       { "_sftp-ssh._tcp",                     "Secure File Transfer Protocol over SSH" },
-       { "_sleep-proxy._udp",          "Sleep Proxy Server" },
-       { "_ssh._tcp",                          "SSH Remote Login Protocol" },
-       { "_teleport._tcp",                     "teleport" },
-       { "_tftp._tcp",                         "Trivial File Transfer Protocol" },
-       { "_workstation._tcp",          "Workgroup Manager" },
-       { "_webdav._tcp",                       "World Wide Web Distributed Authoring and Versioning (WebDAV)" },
-       { "_webdavs._tcp",                      "WebDAV over SSL/TLS" }
-};
-
-static const char *    ServiceTypeDescription( const char *inName )
-{
-       const ServiceType *                             serviceType;
-       const ServiceType * const               end = kServiceTypes + countof( kServiceTypes );
-       
-       for( serviceType = kServiceTypes; serviceType < end; ++serviceType )
-       {
-               if( ( stricmp_prefix( inName, serviceType->name ) == 0 ) )
-               {
-                       const size_t            len = strlen( serviceType->name );
-                       
-                       if( ( inName[ len ] == '\0' ) || ( strcmp( &inName[ len ], "." ) == 0 ) )
-                       {
-                               return( serviceType->description );
-                       }
-               }
-       }
-       return( NULL );
-}
-
-//===========================================================================================================================
-//     SocketContextCreate
-//===========================================================================================================================
-
-static OSStatus        SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext )
-{
-       OSStatus                        err;
-       SocketContext *         context;
-       
-       context = (SocketContext *) calloc( 1, sizeof( *context ) );
-       require_action( context, exit, err = kNoMemoryErr );
-       
-       context->refCount               = 1;
-       context->sock                   = inSock;
-       context->userContext    = inUserContext;
-       
-       *outContext = context;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     SocketContextRetain
-//===========================================================================================================================
-
-static SocketContext * SocketContextRetain( SocketContext *inContext )
-{
-       ++inContext->refCount;
-       return( inContext );
-}
-
-//===========================================================================================================================
-//     SocketContextRelease
-//===========================================================================================================================
-
-static void    SocketContextRelease( SocketContext *inContext )
-{
-       if( --inContext->refCount == 0 )
-       {
-               ForgetSocket( &inContext->sock );
-               free( inContext );
-       }
-}
-
-//===========================================================================================================================
-//     SocketContextCancelHandler
-//===========================================================================================================================
-
-static void    SocketContextCancelHandler( void *inContext )
-{
-       SocketContextRelease( (SocketContext *) inContext );
-}
-
-//===========================================================================================================================
-//     StringToInt32
-//===========================================================================================================================
-
-static OSStatus        StringToInt32( const char *inString, int32_t *outValue )
-{
-       OSStatus                err;
-       long                    value;
-       char *                  endPtr;
-       
-       value = strtol( inString, &endPtr, 0 );
-       require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
-       require_action_quiet( ( value >= INT32_MIN ) && ( value <= INT32_MAX ), exit, err = kRangeErr );
-       
-       *outValue = (int32_t) value;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     StringToUInt32
-//===========================================================================================================================
-
-static OSStatus        StringToUInt32( const char *inString, uint32_t *outValue )
-{
-       OSStatus                err;
-       uint32_t                value;
-       char *                  endPtr;
-       
-       value = (uint32_t) strtol( inString, &endPtr, 0 );
-       require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
-       
-       *outValue = value;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-//     StringToPID
-//===========================================================================================================================
-
-static OSStatus        StringToPID( const char *inString, pid_t *outPID )
-{
-       OSStatus                err;
-       long long               value;
-       char *                  endPtr;
-       
-       set_errno_compat( 0 );
-       value = strtoll( inString, &endPtr, 0 );
-       err = errno_compat();
-       require_noerr_quiet( err, exit );
-       require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kMalformedErr );
-       require_action_quiet( value == (pid_t) value, exit, err = kRangeErr );
-       
-       *outPID = (pid_t) value;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-#endif
-
-//===========================================================================================================================
-//     StringToARecordData
-//===========================================================================================================================
-
-static OSStatus        StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
-       OSStatus                        err;
-       uint32_t *                      addrPtr;
-       const size_t            addrLen = sizeof( *addrPtr );
-       const char *            end;
-       
-       addrPtr = (uint32_t *) malloc( addrLen );
-       require_action( addrPtr, exit, err = kNoMemoryErr );
-       
-       err = StringToIPv4Address( inString, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix, addrPtr,
-               NULL, NULL, NULL, &end );
-       if( !err && ( *end != '\0' ) ) err = kMalformedErr;
-       require_noerr_quiet( err, exit );
-       
-       *addrPtr = HostToBig32( *addrPtr );
-       
-       *outPtr = (uint8_t *) addrPtr;
-       addrPtr = NULL;
-       *outLen = addrLen;
-       
-exit:
-       FreeNullSafe( addrPtr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     StringToAAAARecordData
-//===========================================================================================================================
-
-static OSStatus        StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
-       OSStatus                        err;
-       uint8_t *                       addrPtr;
-       const size_t            addrLen = 16;
-       const char *            end;
-       
-       addrPtr = (uint8_t *) malloc( addrLen );
-       require_action( addrPtr, exit, err = kNoMemoryErr );
-       
-       err = StringToIPv6Address( inString,
-               kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
-               addrPtr, NULL, NULL, NULL, &end );
-       if( !err && ( *end != '\0' ) ) err = kMalformedErr;
-       require_noerr_quiet( err, exit );
-       
-       *outPtr = addrPtr;
-       addrPtr = NULL;
-       *outLen = addrLen;
-       
-exit:
-       FreeNullSafe( addrPtr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     StringToDomainName
-//===========================================================================================================================
-
-static OSStatus        StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
-       OSStatus                err;
-       uint8_t *               namePtr;
-       size_t                  nameLen;
-       uint8_t *               end;
-       uint8_t                 nameBuf[ kDomainNameLengthMax ];
-       
-       err = DomainNameFromString( nameBuf, inString, &end );
-       require_noerr_quiet( err, exit );
-       
-       nameLen = (size_t)( end - nameBuf );
-       namePtr = memdup( nameBuf, nameLen );
-       require_action( namePtr, exit, err = kNoMemoryErr );
-       
-       *outPtr = namePtr;
-       namePtr = NULL;
-       if( outLen ) *outLen = nameLen;
-       
-exit:
-       return( err );
-}
-
-#if( TARGET_OS_DARWIN )
-//===========================================================================================================================
-//     GetDefaultDNSServer
-//===========================================================================================================================
-
-static OSStatus        GetDefaultDNSServer( sockaddr_ip *outAddr )
-{
-       OSStatus                                err;
-       dns_config_t *                  config;
-       struct sockaddr *               addr;
-       int32_t                                 i;
-       
-       config = dns_configuration_copy();
-       require_action( config, exit, err = kUnknownErr );
-       
-       addr = NULL;
-       for( i = 0; i < config->n_resolver; ++i )
-       {
-               const dns_resolver_t * const            resolver = config->resolver[ i ];
-               
-               if( !resolver->domain && ( resolver->n_nameserver > 0 ) )
-               {
-                       addr = resolver->nameserver[ 0 ];
-                       break;
-               }
-       }
-       require_action_quiet( addr, exit, err = kNotFoundErr );
-       
-       SockAddrCopy( addr, outAddr );
-       err = kNoErr;
-       
-exit:
-       if( config ) dns_configuration_free( config );
-       return( err );
-}
-#endif
-
-//===========================================================================================================================
-//     GetMDNSMulticastAddrV4
-//===========================================================================================================================
-
-static void    _MDNSMulticastAddrV4Init( void *inContext );
-
-static const struct sockaddr * GetMDNSMulticastAddrV4( void )
-{
-       static struct sockaddr_in               sMDNSMulticastAddrV4;
-       static dispatch_once_t                  sMDNSMulticastAddrV4InitOnce = 0;
-       
-       dispatch_once_f( &sMDNSMulticastAddrV4InitOnce, &sMDNSMulticastAddrV4, _MDNSMulticastAddrV4Init);
-       return( (const struct sockaddr *) &sMDNSMulticastAddrV4 );
-}
-
-static void    _MDNSMulticastAddrV4Init( void *inContext )
-{
-       struct sockaddr_in * const              addr = (struct sockaddr_in *) inContext;
-       
-       memset( addr, 0, sizeof( *addr ) );
-       SIN_LEN_SET( addr );
-       addr->sin_family                = AF_INET;
-       addr->sin_port                  = htons( kMDNSPort );
-       addr->sin_addr.s_addr   = htonl( 0xE00000FB );  // The mDNS IPv4 multicast address is 224.0.0.251
-}
-
-//===========================================================================================================================
-//     GetMDNSMulticastAddrV6
-//===========================================================================================================================
-
-static void    _MDNSMulticastAddrV6Init( void *inContext );
-
-static const struct sockaddr * GetMDNSMulticastAddrV6( void )
-{
-       static struct sockaddr_in6              sMDNSMulticastAddrV6;
-       static dispatch_once_t                  sMDNSMulticastAddrV6InitOnce = 0;
-       
-       dispatch_once_f( &sMDNSMulticastAddrV6InitOnce, &sMDNSMulticastAddrV6, _MDNSMulticastAddrV6Init);
-       return( (const struct sockaddr *) &sMDNSMulticastAddrV6 );
-}
-
-static void    _MDNSMulticastAddrV6Init( void *inContext )
-{
-       struct sockaddr_in6 * const             addr = (struct sockaddr_in6 *) inContext;
-       
-       memset( addr, 0, sizeof( *addr ) );
-       SIN6_LEN_SET( addr );
-       addr->sin6_family       = AF_INET6;
-       addr->sin6_port         = htons( kMDNSPort );
-       addr->sin6_addr.s6_addr[  0 ] = 0xFF;   // The mDNS IPv6 multicast address is FF02::FB.
-       addr->sin6_addr.s6_addr[  1 ] = 0x02;
-       addr->sin6_addr.s6_addr[ 15 ] = 0xFB;
-}
-
-//===========================================================================================================================
-//     GetAnyMDNSInterface
-//===========================================================================================================================
-
-static OSStatus        GetAnyMDNSInterface( char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex )
-{
-       OSStatus                                        err;
-       struct ifaddrs *                        ifaList;
-       const struct ifaddrs *          ifa;
-       const struct ifaddrs *          ifa2;
-       const char *                            ifname          = NULL;
-       const unsigned int                      checkFlags      = IFF_UP | IFF_MULTICAST | IFF_LOOPBACK | IFF_POINTOPOINT;
-       const unsigned int                      wantFlags       = IFF_UP | IFF_MULTICAST;
-       int                                                     wantFamily;
-       NetTransportType                        type;
-       
-       ifaList = NULL;
-       err = getifaddrs( &ifaList );
-       err = map_global_noerr_errno( err );
-       require_noerr( err, exit );
-       
-       for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
-       {
-               if( ( ifa->ifa_flags & checkFlags ) != wantFlags )      continue;
-               if( !ifa->ifa_addr || !ifa->ifa_name )                          continue;
-               if( ( ifa->ifa_addr->sa_family != AF_INET ) &&
-                       ( ifa->ifa_addr->sa_family != AF_INET6 ) )              continue;
-               
-               err = SocketGetInterfaceInfo( kInvalidSocketRef, ifa->ifa_name, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &type );
-               check_noerr( err );
-               if( err || ( type == kNetTransportType_AWDL ) )         continue;
-               
-               if( !ifname ) ifname = ifa->ifa_name;
-               wantFamily = ( ifa->ifa_addr->sa_family == AF_INET ) ? AF_INET6 : AF_INET;
-               
-               for( ifa2 = ifa->ifa_next; ifa2; ifa2 = ifa2->ifa_next )
-               {
-                       if( ( ifa2->ifa_flags & checkFlags ) != wantFlags )     continue;
-                       if( !ifa2->ifa_addr || !ifa2->ifa_name )                        continue;
-                       if( ifa2->ifa_addr->sa_family != wantFamily )           continue;
-                       if( strcmp( ifa2->ifa_name, ifa->ifa_name ) == 0 )      break;
-               }
-               if( ifa2 )
-               {
-                       ifname = ifa->ifa_name;
-                       break;
-               }
-       }
-       require_action_quiet( ifname, exit, err = kNotFoundErr );
-       
-       if( inNameBuf ) strlcpy( inNameBuf, ifname, IF_NAMESIZE + 1 );
-       if( outIndex )  *outIndex = if_nametoindex( ifname );
-       
-exit:
-       if( ifaList ) freeifaddrs( ifaList );
-       return( err );
-}
-
-//===========================================================================================================================
-//     CreateMulticastSocket
-//===========================================================================================================================
-
-static OSStatus
-       CreateMulticastSocket(
-               const struct sockaddr * inAddr,
-               int                                             inPort,
-               const char *                    inIfName,
-               uint32_t                                inIfIndex,
-               Boolean                                 inJoin,
-               int *                                   outPort,
-               SocketRef *                             outSock )
-{
-       OSStatus                err;
-       SocketRef               sock    = kInvalidSocketRef;
-       const int               family  = inAddr->sa_family;
-       int                             port;
-       
-       require_action_quiet( ( family == AF_INET ) ||( family == AF_INET6 ), exit, err = kUnsupportedErr );
-       
-       err = ServerSocketOpen( family, SOCK_DGRAM, IPPROTO_UDP, inPort, &port, kSocketBufferSize_DontSet, &sock );
-       require_noerr_quiet( err, exit );
-       
-       err = SocketSetMulticastInterface( sock, inIfName, inIfIndex );
-       require_noerr_quiet( err, exit );
-       
-       if( family == AF_INET )
-       {
-               err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
-               err = map_socket_noerr_errno( sock, err );
-               require_noerr_quiet( err, exit );
-       }
-       else
-       {
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
-               err = map_socket_noerr_errno( sock, err );
-               require_noerr_quiet( err, exit );
-       }
-       
-       if( inJoin )
-       {
-               err = SocketJoinMulticast( sock, inAddr, inIfName, inIfIndex );
-               require_noerr_quiet( err, exit );
-       }
-       
-       if( outPort ) *outPort = port;
-       *outSock = sock;
-       sock = kInvalidSocketRef;
-       
-exit:
-       ForgetSocket( &sock );
-       return( err );
-}
-
-//===========================================================================================================================
-//     DecimalTextToUInt32
-//===========================================================================================================================
-
-static OSStatus        DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr )
-{
-       OSStatus                        err;
-       uint64_t                        value;
-       const char *            ptr = inSrc;
-       
-       require_action_quiet( ( ptr < inEnd ) && isdigit_safe( *ptr ), exit, err = kMalformedErr );
-       
-       value = (uint64_t)( *ptr++ - '0' );
-       if( value == 0 )
-       {
-               if( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
-               {
-                       err = kMalformedErr;
-                       goto exit;
-               }
-       }
-       else
-       {
-               while( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
-               {
-                       value = ( value * 10 ) + (uint64_t)( *ptr++ - '0' );
-                       require_action_quiet( value <= UINT32_MAX, exit, err = kRangeErr );
-               }
-       }
-       
-       *outValue = (uint32_t) value;
-       if( outPtr ) *outPtr = ptr;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     CheckIntegerArgument
-//===========================================================================================================================
-
-static OSStatus        CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax )
-{
-       if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
-       
-       FPrintF( stderr, "error: Invalid %s: %d. Valid range is [%d, %d].\n", inArgName, inArgValue, inMin, inMax );
-       return( kRangeErr );
-}
-
-//===========================================================================================================================
-//     CheckDoubleArgument
-//===========================================================================================================================
-
-static OSStatus        CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax )
-{
-       if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
-       
-       FPrintF( stderr, "error: Invalid %s: %.1f. Valid range is [%.1f, %.1f].\n", inArgName, inArgValue, inMin, inMax );
-       return( kRangeErr );
-}
-
-//===========================================================================================================================
-//     CheckRootUser
-//===========================================================================================================================
-
-static OSStatus        CheckRootUser( void )
-{
-       if( geteuid() == 0 ) return( kNoErr );
-       
-       FPrintF( stderr, "error: This command must to be run as root.\n" );
-       return( kPermissionErr );
-}
-
-//===========================================================================================================================
-//     SpawnCommand
-//
-//     Note: Based on systemf() from CoreUtils framework.
-//===========================================================================================================================
-
-extern char **         environ;
-
-static OSStatus        SpawnCommand( pid_t *outPID, const char *inFormat, ... )
-{
-       OSStatus                err;
-       va_list                 args;
-       char *                  command;
-       char *                  argv[ 4 ];
-       pid_t                   pid;
-       
-       command = NULL;
-       va_start( args, inFormat );
-       VASPrintF( &command, inFormat, args );
-       va_end( args );
-       require_action( command, exit, err = kUnknownErr );
-       
-       argv[ 0 ] = "/bin/sh";
-       argv[ 1 ] = "-c";
-       argv[ 2 ] = command;
-       argv[ 3 ] = NULL;
-       err = posix_spawn( &pid, argv[ 0 ], NULL, NULL, argv, environ );
-       free( command );
-       require_noerr_quiet( err, exit );
-       
-       if( outPID ) *outPID = pid;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     OutputPropertyList
-//===========================================================================================================================
-
-static OSStatus
-       OutputPropertyList(
-               CFPropertyListRef       inPList,
-               OutputFormatType        inType,
-               Boolean                         inAppendNewline,
-               const char *            inOutputFilePath )
-{
-       OSStatus                err;
-       CFDataRef               results = NULL;
-       FILE *                  file    = NULL;
-       
-       // Convert plist to a specific format.
-       
-       switch( inType )
-       {
-               case kOutputFormatType_JSON:
-                       results = CFCreateJSONData( inPList, kJSONFlags_None, NULL );
-                       require_action( results, exit, err = kUnknownErr );
-                       break;
-               
-               case kOutputFormatType_XML:
-                       results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListXMLFormat_v1_0, 0, NULL );
-                       require_action( results, exit, err = kUnknownErr );
-                       break;
-               
-               case kOutputFormatType_Binary:
-                       results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListBinaryFormat_v1_0, 0, NULL );
-                       require_action( results, exit, err = kUnknownErr );
-                       break;
-               
-               default:
-                       err = kTypeErr;
-                       goto exit;
-       }
-       
-       // Write formatted results to file or stdout.
-       
-       if( inOutputFilePath )
-       {
-               file = fopen( inOutputFilePath, "wb" );
-               err = map_global_value_errno( file, file );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               file = stdout;
-       }
-       
-       err = WriteANSIFile( file, CFDataGetBytePtr( results ), (size_t) CFDataGetLength( results ) );
-       require_noerr_quiet( err, exit );
-       
-       // Write a trailing newline for JSON-formatted results if requested.
-       
-       if( ( inType == kOutputFormatType_JSON ) && inAppendNewline )
-       {
-               err = WriteANSIFile( file, "\n", 1 );
-               require_noerr_quiet( err, exit );
-       }
-       
-exit:
-       if( file && ( file != stdout ) ) fclose( file );
-       CFReleaseNullSafe( results );
-       return( err );
-}
-
-//===========================================================================================================================
-//     DNSRecordFixedFieldsSet
-//===========================================================================================================================
-
-static void
-       DNSRecordFixedFieldsSet(
-               DNSRecordFixedFields *  inFields,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint32_t                                inTTL,
-               uint16_t                                inRDLength )
-{
-       WriteBig16( inFields->type,             inType );
-       WriteBig16( inFields->class,    inClass );
-       WriteBig32( inFields->ttl,              inTTL );
-       WriteBig16( inFields->rdlength, inRDLength );
-}
-
-//===========================================================================================================================
-//     SRVRecordDataFixedFieldsGet
-//===========================================================================================================================
-
-static void
-       SRVRecordDataFixedFieldsGet(
-               const SRVRecordDataFixedFields *        inFields,
-               unsigned int *                                          outPriority,
-               unsigned int *                                          outWeight,
-               unsigned int *                                          outPort )
-{
-       if( outPriority )       *outPriority    = ReadBig16( inFields->priority );
-       if( outWeight )         *outWeight              = ReadBig16( inFields->weight );
-       if( outPort )           *outPort                = ReadBig16( inFields->port );
-}
-
-//===========================================================================================================================
-//     SRVRecordDataFixedFieldsSet
-//===========================================================================================================================
-
-static void
-       SRVRecordDataFixedFieldsSet(
-               SRVRecordDataFixedFields *      inFields,
-               uint16_t                                        inPriority,
-               uint16_t                                        inWeight,
-               uint16_t                                        inPort )
-{
-       WriteBig16( inFields->priority, inPriority );
-       WriteBig16( inFields->weight,   inWeight );
-       WriteBig16( inFields->port,             inPort );
-}
-
-//===========================================================================================================================
-//     SOARecordDataFixedFieldsGet
-//===========================================================================================================================
-
-static void
-       SOARecordDataFixedFieldsGet(
-               const SOARecordDataFixedFields *        inFields,
-               uint32_t *                                                      outSerial,
-               uint32_t *                                                      outRefresh,
-               uint32_t *                                                      outRetry,
-               uint32_t *                                                      outExpire,
-               uint32_t *                                                      outMinimum )
-{
-       if( outSerial )         *outSerial      = ReadBig32( inFields->serial );
-       if( outRefresh )        *outRefresh     = ReadBig32( inFields->refresh );
-       if( outRetry )          *outRetry       = ReadBig32( inFields->retry );
-       if( outExpire )         *outExpire      = ReadBig32( inFields->expire );
-       if( outMinimum )        *outMinimum     = ReadBig32( inFields->minimum );
-}
-
-//===========================================================================================================================
-//     SOARecordDataFixedFieldsSet
-//===========================================================================================================================
-
-static void
-       SOARecordDataFixedFieldsSet(
-               SOARecordDataFixedFields *      inFields,
-               uint32_t                                        inSerial,
-               uint32_t                                        inRefresh,
-               uint32_t                                        inRetry,
-               uint32_t                                        inExpire,
-               uint32_t                                        inMinimum )
-{
-       WriteBig32( inFields->serial,   inSerial );
-       WriteBig32( inFields->refresh,  inRefresh );
-       WriteBig32( inFields->retry,    inRetry );
-       WriteBig32( inFields->expire,   inExpire );
-       WriteBig32( inFields->minimum,  inMinimum );
-}
-
-//===========================================================================================================================
-//     CreateSRVRecordDataFromString
-//===========================================================================================================================
-
-static OSStatus        CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen )
-{
-       OSStatus                        err;
-       DataBuffer                      dataBuf;
-       const char *            ptr;
-       int                                     i;
-       uint8_t *                       end;
-       uint8_t                         target[ kDomainNameLengthMax ];
-       
-       DataBuffer_Init( &dataBuf, NULL, 0, ( 3 * 2 ) + kDomainNameLengthMax );
-       
-       // Parse and set the priority, weight, and port values (all three are unsigned 16-bit values).
-       
-       ptr = inString;
-       for( i = 0; i < 3; ++i )
-       {
-               char *          next;
-               long            value;
-               uint8_t         buf[ 2 ];
-               
-               value = strtol( ptr, &next, 0 );
-               require_action_quiet( ( next != ptr ) && ( *next == ',' ), exit, err = kMalformedErr );
-               require_action_quiet( ( value >= 0 ) && ( value <= UINT16_MAX ), exit, err = kRangeErr );
-               ptr = next + 1;
-               
-               WriteBig16( buf, value );
-               
-               err = DataBuffer_Append( &dataBuf, buf, sizeof( buf ) );
-               require_noerr( err, exit );
-       }
-       
-       // Set the target domain name.
-       
-       err = DomainNameFromString( target, ptr, &end );
-    require_noerr_quiet( err, exit );
-       
-       err = DataBuffer_Append( &dataBuf, target, (size_t)( end - target ) );
-       require_noerr( err, exit );
-       
-       err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
-       require_noerr( err, exit );
-       
-exit:
-       DataBuffer_Free( &dataBuf );
-       return( err );
-}
-
-//===========================================================================================================================
-//     CreateTXTRecordDataFromString
-//===========================================================================================================================
-
-static OSStatus        CreateTXTRecordDataFromString(const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen )
-{
-       OSStatus                        err;
-       DataBuffer                      dataBuf;
-       const char *            src;
-       uint8_t                         txtStr[ 256 ];  // Buffer for single TXT string: 1 length byte + up to 255 bytes of data.
-       
-       DataBuffer_Init( &dataBuf, NULL, 0, kDNSRecordDataLengthMax );
-       
-       src = inString;
-       for( ;; )
-       {
-               uint8_t *                                       dst = &txtStr[ 1 ];
-               const uint8_t * const           lim = &txtStr[ 256 ];
-               int                                                     c;
-               
-               while( *src && ( *src != inDelimiter ) )
-               {
-                       if( ( c = *src++ ) == '\\' )
-                       {
-                               require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
-                               c = *src++;
-                       }
-                       require_action_quiet( dst < lim, exit, err = kOverrunErr );
-                       *dst++ = (uint8_t) c;
-               }
-               txtStr[ 0 ] = (uint8_t)( dst - &txtStr[ 1 ] );
-               err = DataBuffer_Append( &dataBuf, txtStr, 1 + txtStr[ 0 ] );
-               require_noerr( err, exit );
-               
-               if( *src == '\0' ) break;
-               ++src;
-       }
-       
-       err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
-       require_noerr( err, exit );
-       
-exit:
-       DataBuffer_Free( &dataBuf );
-       return( err );
-}
-
-//===========================================================================================================================
-//     CreateNSECRecordData
-//===========================================================================================================================
-
-DECLARE_QSORT_NUMERIC_COMPARATOR( _QSortCmpUnsigned );
-DEFINE_QSORT_NUMERIC_COMPARATOR( unsigned int, _QSortCmpUnsigned )
-
-#define kNSECBitmapMaxLength           32      // 32 bytes (256 bits). See <https://tools.ietf.org/html/rfc4034#section-4.1.2>.
-
-static OSStatus
-       CreateNSECRecordData(
-               const uint8_t * inNextDomainName,
-               uint8_t **              outPtr,
-               size_t *                outLen,
-               unsigned int    inTypeCount,
-               ... )
-{
-       OSStatus                        err;
-       va_list                         args;
-       DataBuffer                      rdataDB;
-       unsigned int *          array   = NULL;
-       unsigned int            i, type, maxBit, currBlock, bitmapLen;
-       uint8_t                         fields[ 2 + kNSECBitmapMaxLength ];
-       uint8_t * const         bitmap  = &fields[ 2 ];
-       
-       va_start( args, inTypeCount );
-       DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
-       
-       // Append Next Domain Name.
-       
-       err = DataBuffer_Append( &rdataDB, inNextDomainName, DomainNameLength( inNextDomainName ) );
-       require_noerr( err, exit );
-       
-       // Append Type Bit Maps.
-       
-       maxBit = 0;
-       memset( bitmap, 0, kNSECBitmapMaxLength );
-       if( inTypeCount > 0 )
-       {
-               array = (unsigned int *) malloc( inTypeCount * sizeof_element( array ) );
-               require_action( array, exit, err = kNoMemoryErr );
-               
-               for( i = 0; i < inTypeCount; ++i )
-               {
-                       type = va_arg( args, unsigned int );
-                       require_action_quiet( type <= UINT16_MAX, exit, err = kRangeErr );
-                       array[ i ] = type;
-               }
-               qsort( array, inTypeCount, sizeof_element( array ), _QSortCmpUnsigned );
-               
-               currBlock = array[ 0 ] / 256;
-               for( i = 0; i < inTypeCount; ++i )
-               {
-                       const unsigned int              block   = array[ i ] / 256;
-                       const unsigned int              bit             = array[ i ] % 256;
-                       
-                       if( block != currBlock )
-                       {
-                               bitmapLen       = BitArray_MaxBytes( maxBit + 1 );
-                               fields[ 0 ] = (uint8_t) currBlock;
-                               fields[ 1 ] = (uint8_t) bitmapLen;
-                               
-                               err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
-                               require_noerr( err, exit );
-                               
-                               maxBit          = 0;
-                               currBlock       = block;
-                               memset( bitmap, 0, bitmapLen );
-                       }
-                       BitArray_SetBit( bitmap, bit );
-                       if( bit > maxBit ) maxBit = bit;
-               }
-       }
-       else
-       {
-               currBlock = 0;
-       }
-       
-       bitmapLen       = BitArray_MaxBytes( maxBit + 1 );
-       fields[ 0 ] = (uint8_t) currBlock;
-       fields[ 1 ] = (uint8_t) bitmapLen;
-       
-       err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
-       require_noerr( err, exit );
-       
-       err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
-       require_noerr( err, exit );
-       
-exit:
-       va_end( args );
-       DataBuffer_Free( &rdataDB );
-       FreeNullSafe( array );
-       return( err );
-}
-
-//===========================================================================================================================
-//     AppendSOARecord
-//===========================================================================================================================
-
-static OSStatus
-       _AppendSOARecordData(
-               DataBuffer *    inDB,
-               const uint8_t * inMName,
-               const uint8_t * inRName,
-               uint32_t                inSerial,
-               uint32_t                inRefresh,
-               uint32_t                inRetry,
-               uint32_t                inExpire,
-               uint32_t                inMinimumTTL,
-               size_t *                outLen );
-
-static OSStatus
-       AppendSOARecord(
-               DataBuffer *    inDB,
-               const uint8_t * inNamePtr,
-               size_t                  inNameLen,
-               uint16_t                inType,
-               uint16_t                inClass,
-               uint32_t                inTTL,
-               const uint8_t * inMName,
-               const uint8_t * inRName,
-               uint32_t                inSerial,
-               uint32_t                inRefresh,
-               uint32_t                inRetry,
-               uint32_t                inExpire,
-               uint32_t                inMinimumTTL,
-               size_t *                outLen )
-{
-       OSStatus                err;
-       size_t                  rdataLen;
-       size_t                  rdlengthOffset = 0;
-       uint8_t *               rdlengthPtr;
-       
-       if( inDB )
-       {
-               err = _DataBuffer_AppendDNSRecord( inDB, inNamePtr, inNameLen, inType, inClass, inTTL, NULL, 0 );
-               require_noerr( err, exit );
-               
-               rdlengthOffset = DataBuffer_GetLen( inDB ) - 2;
-       }
-       
-       err = _AppendSOARecordData( inDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, &rdataLen );
-       require_noerr( err, exit );
-       
-       if( inDB )
-       {
-               rdlengthPtr = DataBuffer_GetPtr( inDB ) + rdlengthOffset;
-               WriteBig16( rdlengthPtr, rdataLen );
-       }
-       
-       if( outLen ) *outLen = inNameLen + sizeof( DNSRecordFixedFields ) + rdataLen;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-static OSStatus
-       _AppendSOARecordData(
-               DataBuffer *    inDB,
-               const uint8_t * inMName,
-               const uint8_t * inRName,
-               uint32_t                inSerial,
-               uint32_t                inRefresh,
-               uint32_t                inRetry,
-               uint32_t                inExpire,
-               uint32_t                inMinimumTTL,
-               size_t *                outLen )
-{
-       OSStatus                                                err;
-       SOARecordDataFixedFields                fields;
-       const size_t                                    mnameLen = DomainNameLength( inMName );
-       const size_t                                    rnameLen = DomainNameLength( inRName );
-       
-       if( inDB )
-       {
-               err = DataBuffer_Append( inDB, inMName, mnameLen );
-               require_noerr( err, exit );
-               
-               err = DataBuffer_Append( inDB, inRName, rnameLen );
-               require_noerr( err, exit );
-               
-               SOARecordDataFixedFieldsSet( &fields, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL );
-               err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
-               require_noerr( err, exit );
-       }
-       if( outLen ) *outLen = mnameLen + rnameLen + sizeof( fields );
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     CreateSOARecordData
-//===========================================================================================================================
-
-static OSStatus
-       CreateSOARecordData(
-               const uint8_t * inMName,
-               const uint8_t * inRName,
-               uint32_t                inSerial,
-               uint32_t                inRefresh,
-               uint32_t                inRetry,
-               uint32_t                inExpire,
-               uint32_t                inMinimumTTL,
-               uint8_t **              outPtr,
-               size_t *                outLen )
-{
-       OSStatus                err;
-       DataBuffer              rdataDB;
-       
-       DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
-       
-       err = _AppendSOARecordData( &rdataDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, NULL );
-       require_noerr( err, exit );
-       
-       err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
-       require_noerr( err, exit );
-       
-exit:
-       DataBuffer_Free( &rdataDB );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _DataBuffer_AppendDNSQuestion
-//===========================================================================================================================
-
-static OSStatus
-       _DataBuffer_AppendDNSQuestion(
-               DataBuffer *    inDB,
-               const uint8_t * inNamePtr,
-               size_t                  inNameLen,
-               uint16_t                inType,
-               uint16_t                inClass )
-{
-       OSStatus                                        err;
-       DNSQuestionFixedFields          fields;
-       
-       err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
-       require_noerr( err, exit );
-       
-       DNSQuestionFixedFieldsInit( &fields, inType, inClass );
-       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
-       require_noerr( err, exit );
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _DataBuffer_AppendDNSRecord
-//===========================================================================================================================
-
-static OSStatus
-       _DataBuffer_AppendDNSRecord(
-               DataBuffer *    inDB,
-               const uint8_t * inNamePtr,
-               size_t                  inNameLen,
-               uint16_t                inType,
-               uint16_t                inClass,
-               uint32_t                inTTL,
-               const uint8_t * inRDataPtr,
-               size_t                  inRDataLen )
-{
-       OSStatus                                        err;
-       DNSRecordFixedFields            fields;
-       
-       require_action_quiet( inRDataLen < kDNSRecordDataLengthMax, exit, err = kSizeErr );
-       
-       err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
-       require_noerr( err, exit );
-       
-       DNSRecordFixedFieldsSet( &fields, inType, inClass, inTTL, (uint16_t) inRDataLen );
-       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
-       require_noerr( err, exit );
-       
-       if( inRDataPtr )
-       {
-               err = DataBuffer_Append( inDB, inRDataPtr, inRDataLen );
-               require_noerr( err, exit );
-       }
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _NanoTime64ToDateString
-//===========================================================================================================================
-
-static char *  _NanoTime64ToDateString( NanoTime64 inTime, char *inBuf, size_t inMaxLen )
-{
-       struct  timeval         tv;
-       
-       NanoTimeToTimeVal( inTime, &tv );
-       return( MakeFractionalDateString( &tv, inBuf, inMaxLen ) );
-}
-
-//===========================================================================================================================
-//     MDNSColliderCreate
-//===========================================================================================================================
-
-typedef enum
-{
-       kMDNSColliderOpCode_Invalid                     = 0,
-       kMDNSColliderOpCode_Send                        = 1,
-       kMDNSColliderOpCode_Wait                        = 2,
-       kMDNSColliderOpCode_SetProbeActions     = 3,
-       kMDNSColliderOpCode_LoopPush            = 4,
-       kMDNSColliderOpCode_LoopPop                     = 5,
-       kMDNSColliderOpCode_Exit                        = 6
-       
-}      MDNSColliderOpCode;
-
-typedef struct
-{
-       MDNSColliderOpCode              opcode;
-       uint32_t                                operand;
-       
-}      MDNSCInstruction;
-
-#define kMaxLoopDepth          16
-
-struct MDNSColliderPrivate
-{
-       CFRuntimeBase                                   base;                                                   // CF object base.
-       dispatch_queue_t                                queue;                                                  // Queue for collider's events.
-       dispatch_source_t                               readSourceV4;                                   // Read dispatch source for IPv4 socket.
-       dispatch_source_t                               readSourceV6;                                   // Read dispatch source for IPv6 socket.
-       SocketRef                                               sockV4;                                                 // IPv4 UDP socket for mDNS.
-       SocketRef                                               sockV6;                                                 // IPv6 UDP socket for mDNS.
-       uint8_t *                                               target;                                                 // Record name being targeted. (malloced)
-       uint8_t *                                               responsePtr;                                    // Response message pointer. (malloced)
-       size_t                                                  responseLen;                                    // Response message length.
-       uint8_t *                                               probePtr;                                               // Probe query message pointer. (malloced)
-       size_t                                                  probeLen;                                               // Probe query message length.
-       unsigned int                                    probeCount;                                             // Count of probe queries received for collider's record.
-       uint32_t                                                probeActionMap;                                 // Bitmap of actions to take for 
-       MDNSCInstruction *                              program;                                                // Program to execute.
-       uint32_t                                                pc;                                                             // Program's program counter.
-       uint32_t                                                loopCounts[ kMaxLoopDepth ];    // Stack of loop counters.
-       uint32_t                                                loopDepth;                                              // Current loop depth.
-       dispatch_source_t                               waitTimer;                                              // Timer for program's wait commands.
-       uint32_t                                                interfaceIndex;                                 // Interface over which to send and receive mDNS msgs.
-       MDNSColliderStopHandler_f               stopHandler;                                    // User's stop handler.
-       void *                                                  stopContext;                                    // User's stop handler context.
-       MDNSColliderProtocols                   protocols;                                              // Protocols to use, i.e., IPv4, IPv6.
-       Boolean                                                 stopped;                                                // True if the collider has been stopped.
-       uint8_t                                                 msgBuf[ kMDNSMessageSizeMax ];  // mDNS message buffer.
-};
-
-static void            _MDNSColliderStop( MDNSColliderRef inCollider, OSStatus inError );
-static void            _MDNSColliderReadHandler( void *inContext );
-static void            _MDNSColliderExecuteProgram( void *inContext );
-static OSStatus        _MDNSColliderSendResponse( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
-static OSStatus        _MDNSColliderSendProbe( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
-
-CF_CLASS_DEFINE( MDNSCollider );
-
-ulog_define_ex( "com.apple.dnssdutil", MDNSCollider, kLogLevelInfo, kLogFlags_None, "MDNSCollider", NULL );
-#define mc_ulog( LEVEL, ... )          ulog( &log_category_from_name( MDNSCollider ), (LEVEL), __VA_ARGS__ )
-
-static OSStatus        MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider )
-{
-       OSStatus                        err;
-       MDNSColliderRef         obj = NULL;
-       
-       CF_OBJECT_CREATE( MDNSCollider, obj, err, exit );
-       
-       ReplaceDispatchQueue( &obj->queue, inQueue );
-       obj->sockV4 = kInvalidSocketRef;
-       obj->sockV6 = kInvalidSocketRef;
-       
-       *outCollider = obj;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSColliderFinalize
-//===========================================================================================================================
-
-static void    _MDNSColliderFinalize( CFTypeRef inObj )
-{
-       MDNSColliderRef const           me = (MDNSColliderRef) inObj;
-       
-       check( !me->waitTimer );
-       check( !me->readSourceV4 );
-       check( !me->readSourceV6 );
-       check( !IsValidSocket( me->sockV4 ) );
-       check( !IsValidSocket( me->sockV6 ) );
-       ForgetMem( &me->target );
-       ForgetMem( &me->responsePtr );
-       ForgetMem( &me->probePtr );
-       ForgetMem( &me->program );
-       dispatch_forget( &me->queue );
-}
-
-//===========================================================================================================================
-//     MDNSColliderStart
-//===========================================================================================================================
-
-static void    _MDNSColliderStart( void *inContext );
-
-static OSStatus        MDNSColliderStart( MDNSColliderRef me )
-{
-       OSStatus                err;
-       
-       require_action_quiet( me->target,         exit, err = kNotPreparedErr );
-       require_action_quiet( me->responsePtr,    exit, err = kNotPreparedErr );
-       require_action_quiet( me->probePtr,       exit, err = kNotPreparedErr );
-       require_action_quiet( me->program,        exit, err = kNotPreparedErr );
-       require_action_quiet( me->interfaceIndex, exit, err = kNotPreparedErr );
-       require_action_quiet( me->protocols,      exit, err = kNotPreparedErr );
-       
-       CFRetain( me );
-       dispatch_async_f( me->queue, me, _MDNSColliderStart );
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-static void    _MDNSColliderStart( void *inContext )
-{
-       OSStatus                                        err;
-       MDNSColliderRef const           me              = (MDNSColliderRef) inContext;
-       SocketRef                                       sock    = kInvalidSocketRef;
-       SocketContext *                         sockCtx = NULL;
-       
-       if( me->protocols & kMDNSColliderProtocol_IPv4 )
-       {
-               err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
-               require_noerr( err, exit );
-               
-               err = SocketContextCreate( sock, me, &sockCtx );
-               require_noerr( err, exit );
-               sock = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
-                       sockCtx, &me->readSourceV4 );
-               require_noerr( err, exit );
-               me->sockV4 = sockCtx->sock;
-               sockCtx = NULL;
-               
-               dispatch_resume( me->readSourceV4 );
-       }
-       
-       if( me->protocols & kMDNSColliderProtocol_IPv6 )
-       {
-               err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
-               require_noerr( err, exit );
-               
-               err = SocketContextCreate( sock, me, &sockCtx );
-               require_noerr( err, exit );
-               sock = kInvalidSocketRef;
-               
-               err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
-                       sockCtx, &me->readSourceV6 );
-               require_noerr( err, exit );
-               me->sockV6 = sockCtx->sock;
-               sockCtx = NULL;
-               
-               dispatch_resume( me->readSourceV6 );
-       }
-       
-       _MDNSColliderExecuteProgram( me );
-       err = kNoErr;
-       
-exit:
-       ForgetSocket( &sock );
-       ForgetSocketContext( &sockCtx );
-       if( err ) _MDNSColliderStop( me, err );
-}
-
-//===========================================================================================================================
-//     MDNSColliderStop
-//===========================================================================================================================
-
-static void    _MDNSColliderUserStop( void *inContext );
-
-static void    MDNSColliderStop( MDNSColliderRef me )
-{
-       CFRetain( me );
-       dispatch_async_f( me->queue, me, _MDNSColliderUserStop );
-}
-
-static void    _MDNSColliderUserStop( void *inContext )
-{
-       MDNSColliderRef const           me = (MDNSColliderRef) inContext;
-       
-       _MDNSColliderStop( me, kCanceledErr );
-       CFRelease( me );
-}
-
-//===========================================================================================================================
-//     MDNSColliderSetProtocols
-//===========================================================================================================================
-
-static void    MDNSColliderSetProtocols( MDNSColliderRef me, MDNSColliderProtocols inProtocols )
-{
-       me->protocols = inProtocols;
-}
-
-//===========================================================================================================================
-//     MDNSColliderSetInterfaceIndex
-//===========================================================================================================================
-
-static void    MDNSColliderSetInterfaceIndex( MDNSColliderRef me, uint32_t inInterfaceIndex )
-{
-       me->interfaceIndex = inInterfaceIndex;
-}
-
-//===========================================================================================================================
-//     MDNSColliderSetProgram
-//===========================================================================================================================
-
-#define kMDNSColliderProgCmd_Done              "done"
-#define kMDNSColliderProgCmd_Loop              "loop"
-#define kMDNSColliderProgCmd_Send              "send"
-#define kMDNSColliderProgCmd_Probes            "probes"
-#define kMDNSColliderProgCmd_Wait              "wait"
-
-typedef uint32_t               MDNSColliderProbeAction;
-
-#define kMDNSColliderProbeAction_None                                  0
-#define kMDNSColliderProbeAction_Respond                               1
-#define kMDNSColliderProbeAction_RespondUnicast                        2
-#define kMDNSColliderProbeAction_RespondMulticast              3
-#define kMDNSColliderProbeAction_Probe                                 4
-#define kMDNSColliderProbeAction_MaxValue                              kMDNSColliderProbeAction_Probe
-
-#define kMDNSColliderProbeActionBits_Count                     3
-#define kMDNSColliderProbeActionBits_Mask                      ( ( 1U << kMDNSColliderProbeActionBits_Count ) - 1 )
-#define kMDNSColliderProbeActionMaxProbeCount          ( 32 / kMDNSColliderProbeActionBits_Count )
-
-check_compile_time( kMDNSColliderProbeAction_MaxValue <= kMDNSColliderProbeActionBits_Mask );
-
-static OSStatus        _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap );
-
-static OSStatus        MDNSColliderSetProgram( MDNSColliderRef me, const char *inProgramStr )
-{
-       OSStatus                                err;
-       uint32_t                                insCount;
-       unsigned int                    loopDepth;
-       const char *                    cmd;
-       const char *                    end;
-       const char *                    next;
-       MDNSCInstruction *              program = NULL;
-       uint32_t                                loopStart[ kMaxLoopDepth ];
-       
-       insCount = 0;
-       for( cmd = inProgramStr; *cmd; cmd = next )
-       {
-               for( end = cmd; *end && ( *end != ';' ); ++end ) {}
-               require_action_quiet( end != cmd, exit, err = kMalformedErr );
-               next = ( *end == ';' ) ? ( end + 1 ) : end;
-               ++insCount;
-       }
-       
-       program = (MDNSCInstruction *) calloc( insCount + 1, sizeof( *program ) );
-       require_action( program, exit, err = kNoMemoryErr );
-       
-       insCount        = 0;
-       loopDepth       = 0;
-       for( cmd = inProgramStr; *cmd; cmd = next )
-       {
-               size_t                                                  cmdLen;
-               const char *                                    ptr;
-               const char *                                    arg;
-               size_t                                                  argLen;
-               uint32_t                                                value;
-               MDNSCInstruction * const                ins = &program[ insCount ];
-               
-               while( isspace_safe( *cmd ) ) ++cmd;
-               for( end = cmd; *end && ( *end != ';' ); ++end ) {}
-               next = ( *end == ';' ) ? ( end + 1 ) : end;
-               
-               for( ptr = cmd; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
-               cmdLen = (size_t)( ptr - cmd );
-               
-               // Done statement
-               
-               if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Done ) == 0 )
-               {
-                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
-                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
-                       
-                       require_action_quiet( loopDepth > 0, exit, err = kMalformedErr );
-                       
-                       ins->opcode             = kMDNSColliderOpCode_LoopPop;
-                       ins->operand    = loopStart[ --loopDepth ];
-               }
-               
-               // Loop command
-               
-               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Loop ) == 0 )
-               {
-                       for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
-                       err = DecimalTextToUInt32( arg, end, &value, &ptr );
-                       require_noerr_quiet( err, exit );
-                       require_action_quiet( value > 0, exit, err = kValueErr );
-                       
-                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
-                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
-                       
-                       ins->opcode     = kMDNSColliderOpCode_LoopPush;
-                       ins->operand    = value;
-                       
-                       require_action_quiet( loopDepth < kMaxLoopDepth, exit, err = kNoSpaceErr );
-                       loopStart[ loopDepth++ ] = insCount + 1;
-               }
-               
-               // Probes command
-               
-               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Probes ) == 0 )
-               {
-                       for( arg = ptr; ( arg < end ) &&  isspace_safe( *arg ); ++arg ) {}
-                       for( ptr = arg; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
-                       argLen = (size_t)( ptr - arg );
-                       if( argLen > 0 )
-                       {
-                               err = _MDNSColliderParseProbeActionString( arg, argLen, &value );
-                               require_noerr_quiet( err, exit );
-                       }
-                       else
-                       {
-                               value = 0;
-                       }
-                       
-                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
-                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
-                       
-                       ins->opcode     = kMDNSColliderOpCode_SetProbeActions;
-                       ins->operand    = value;
-               }
-               
-               // Send command
-               
-               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Send ) == 0 )
-               {
-                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
-                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
-                       
-                       ins->opcode = kMDNSColliderOpCode_Send;
-               }
-               
-               // Wait command
-               
-               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Wait ) == 0 )
-               {
-                       for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
-                       err = DecimalTextToUInt32( arg, end, &value, &ptr );
-                       require_noerr_quiet( err, exit );
-                       
-                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
-                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
-                       
-                       ins->opcode             = kMDNSColliderOpCode_Wait;
-                       ins->operand    = value;
-               }
-               
-               // Unrecognized command
-               
-               else
-               {
-                       err = kCommandErr;
-                       goto exit;
-               }
-               ++insCount;
-       }
-       require_action_quiet( loopDepth == 0, exit, err = kMalformedErr );
-       
-       program[ insCount ].opcode = kMDNSColliderOpCode_Exit;
-       
-       FreeNullSafe( me->program );
-       me->program = program;
-       program = NULL;
-       err = kNoErr;
-       
-exit:
-       FreeNullSafe( program );
-       return( err );
-}
-
-static OSStatus        _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap )
-{
-       OSStatus                                err;
-       const char *                    ptr;
-       const char * const              end = &inString[ inLen ];
-       uint32_t                                bitmap;
-       int                                             index;
-       
-       bitmap  = 0;
-       index   = 0;
-       ptr             = inString;
-       while( ptr < end )
-       {
-               int                                                     c, count;
-               MDNSColliderProbeAction         action;
-               
-               c = *ptr++;
-               if( isdigit_safe( c ) )
-               {
-                       count = 0;
-                       do
-                       {
-                               count = ( count * 10 ) + ( c - '0' );
-                               require_action_quiet( count <= ( kMDNSColliderProbeActionMaxProbeCount - index ), exit, err = kCountErr );
-                               require_action_quiet( ptr < end, exit, err = kUnderrunErr );
-                               c = *ptr++;
-                               
-                       }       while( isdigit_safe( c ) );
-                       require_action_quiet( count > 0, exit, err = kCountErr );
-               }
-               else
-               {
-                       require_action_quiet( index < kMDNSColliderProbeActionMaxProbeCount, exit, err = kMalformedErr );
-                       count = 1;
-               }
-               
-               switch( c )
-               {
-                       case 'n':       action = kMDNSColliderProbeAction_None;                         break;
-                       case 'r':       action = kMDNSColliderProbeAction_Respond;                      break;
-                       case 'u':       action = kMDNSColliderProbeAction_RespondUnicast;       break;
-                       case 'm':       action = kMDNSColliderProbeAction_RespondMulticast;     break;
-                       case 'p':       action = kMDNSColliderProbeAction_Probe;                        break;
-                       default:        err = kMalformedErr;                                                            goto exit;
-               }
-               if( ptr < end )
-               {
-                       c = *ptr++;
-                       require_action_quiet( ( c == '-' ) && ( ptr < end ), exit, err = kMalformedErr );
-               }
-               while( count-- > 0 )
-               {
-                       bitmap |= ( action << ( index * kMDNSColliderProbeActionBits_Count ) );
-                       ++index;
-               }
-       }
-       
-       *outBitmap = bitmap;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     MDNSColliderSetStopHandler
-//===========================================================================================================================
-
-static void    MDNSColliderSetStopHandler( MDNSColliderRef me, MDNSColliderStopHandler_f inStopHandler, void *inStopContext )
-{
-       me->stopHandler = inStopHandler;
-       me->stopContext = inStopContext;
-}
-
-//===========================================================================================================================
-//     MDNSColliderSetRecord
-//===========================================================================================================================
-
-#define kMDNSColliderDummyStr                  "\x16" "mdnscollider-sent-this" kLocalStr
-#define kMDNSColliderDummyName                 ( (const uint8_t *) kMDNSColliderDummyStr )
-#define kMDNSColliderDummyNameLen              sizeof( kMDNSColliderDummyStr )
-
-static OSStatus
-       MDNSColliderSetRecord(
-               MDNSColliderRef me,
-               const uint8_t * inName,
-               uint16_t                inType,
-               const void *    inRDataPtr,
-               size_t                  inRDataLen )
-{
-       OSStatus                err;
-       DataBuffer              msgDB;
-       DNSHeader               header;
-       uint8_t *               targetPtr       = NULL;
-       size_t                  targetLen;
-       uint8_t *               responsePtr     = NULL;
-       size_t                  responseLen;
-       uint8_t *               probePtr        = NULL;
-       size_t                  probeLen;
-       
-       DataBuffer_Init( &msgDB, NULL, 0, kMDNSMessageSizeMax );
-       
-       err = DomainNameDup( inName, &targetPtr, &targetLen );
-       require_noerr_quiet( err, exit );
-       
-       // Create response message.
-       
-       memset( &header, 0, sizeof( header ) );
-       DNSHeaderSetFlags( &header, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
-       DNSHeaderSetAnswerCount( &header, 1 );
-       
-       err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
-       require_noerr( err, exit );
-       
-       err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN | kRRClassCacheFlushBit,
-               1976, inRDataPtr, inRDataLen );
-       require_noerr( err, exit );
-       
-       err = DataBuffer_Detach( &msgDB, &responsePtr, &responseLen );
-       require_noerr( err, exit );
-       
-       // Create probe message.
-       
-       memset( &header, 0, sizeof( header ) );
-       DNSHeaderSetQuestionCount( &header, 2 );
-       DNSHeaderSetAuthorityCount( &header, 1 );
-       
-       err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
-       require_noerr( err, exit );
-       
-       err = _DataBuffer_AppendDNSQuestion( &msgDB, targetPtr, targetLen, kDNSServiceType_ANY, kDNSServiceClass_IN );
-       require_noerr( err, exit );
-       
-       err = _DataBuffer_AppendDNSQuestion( &msgDB, kMDNSColliderDummyName, kMDNSColliderDummyNameLen,
-               kDNSServiceType_NULL, kDNSServiceClass_IN );
-       require_noerr( err, exit );
-       
-       err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN,
-               1976, inRDataPtr, inRDataLen );
-       require_noerr( err, exit );
-       
-       err = DataBuffer_Detach( &msgDB, &probePtr, &probeLen );
-       require_noerr( err, exit );
-       
-       FreeNullSafe( me->target );
-       me->target = targetPtr;
-       targetPtr = NULL;
-       
-       FreeNullSafe( me->responsePtr );
-       me->responsePtr = responsePtr;
-       me->responseLen = responseLen;
-       responsePtr = NULL;
-       
-       FreeNullSafe( me->probePtr );
-       me->probePtr = probePtr;
-       me->probeLen = probeLen;
-       probePtr = NULL;
-       
-exit:
-       DataBuffer_Free( &msgDB );
-       FreeNullSafe( targetPtr );
-       FreeNullSafe( responsePtr );
-       FreeNullSafe( probePtr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSColliderStop
-//===========================================================================================================================
-
-static void    _MDNSColliderStop( MDNSColliderRef me, OSStatus inError )
-{
-       dispatch_source_forget( &me->waitTimer );
-       dispatch_source_forget( &me->readSourceV4 );
-       dispatch_source_forget( &me->readSourceV6 );
-       me->sockV4 = kInvalidSocketRef;
-       me->sockV6 = kInvalidSocketRef;
-       
-       if( !me->stopped )
-       {
-               me->stopped = true;
-               if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
-               CFRelease( me );
-       }
-}
-
-//===========================================================================================================================
-//     _MDNSColliderReadHandler
-//===========================================================================================================================
-
-static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber );
-static const char *                            _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction );
-
-static void    _MDNSColliderReadHandler( void *inContext )
-{
-       OSStatus                                        err;
-       struct timeval                          now;
-       SocketContext * const           sockCtx = (SocketContext *) inContext;
-       MDNSColliderRef const           me              = (MDNSColliderRef) sockCtx->userContext;
-       size_t                                          msgLen;
-       sockaddr_ip                                     sender;
-       const DNSHeader *                       hdr;
-       const uint8_t *                         ptr;
-       const struct sockaddr *         dest;
-       int                                                     probeFound, probeIsQU;
-       unsigned int                            qCount, i;
-       MDNSColliderProbeAction         action;
-       
-       gettimeofday( &now, NULL );
-       
-       err = SocketRecvFrom( sockCtx->sock, me->msgBuf, sizeof( me->msgBuf ), &msgLen, &sender, sizeof( sender ),
-               NULL, NULL, NULL, NULL );
-       require_noerr( err, exit );
-       
-       require_quiet( msgLen >= kDNSHeaderLength, exit );
-       hdr = (const DNSHeader *) me->msgBuf;
-       
-       probeFound      = false;
-       probeIsQU       = false;
-       qCount = DNSHeaderGetQuestionCount( hdr );
-       ptr = (const uint8_t *) &hdr[ 1 ];
-       for( i = 0; i < qCount; ++i )
-       {
-               uint16_t                qtype, qclass;
-               uint8_t                 qname[ kDomainNameLengthMax ];
-               
-               err = DNSMessageExtractQuestion( me->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
-               require_noerr_quiet( err, exit );
-               
-               if( ( qtype == kDNSServiceType_NULL ) && ( qclass == kDNSServiceClass_IN ) &&
-                       DomainNameEqual( qname, kMDNSColliderDummyName ) )
-               {
-                       probeFound = false;
-                       break;
-               }
-               
-               if( qtype != kDNSServiceType_ANY ) continue;
-               if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
-               if( !DomainNameEqual( qname, me->target ) ) continue;
-               
-               if( !probeFound )
-               {
-                       probeFound      = true;
-                       probeIsQU       = ( qclass & kQClassUnicastResponseBit ) ? true : false;
-               }
-       }
-       require_quiet( probeFound, exit );
-       
-       ++me->probeCount;
-       action = _MDNSColliderGetProbeAction( me->probeActionMap, me->probeCount );
-       
-       mc_ulog( kLogLevelInfo, "Received probe from %##a at %{du:time} (action: %s):\n\n%#1{du:dnsmsg}",
-               &sender, &now, _MDNSColliderProbeActionToString( action ), me->msgBuf, msgLen );
-       
-       if( ( action == kMDNSColliderProbeAction_Respond )                      ||
-               ( action == kMDNSColliderProbeAction_RespondUnicast )   ||
-               ( action == kMDNSColliderProbeAction_RespondMulticast ) )
-       {
-               if( ( ( action == kMDNSColliderProbeAction_Respond ) && probeIsQU ) ||
-                       (   action == kMDNSColliderProbeAction_RespondUnicast ) )
-               {
-                       dest = &sender.sa;
-               }
-               else if( ( ( action == kMDNSColliderProbeAction_Respond ) && !probeIsQU ) ||
-                                (   action == kMDNSColliderProbeAction_RespondMulticast ) )
-               {
-                       dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
-               }
-               
-               err = _MDNSColliderSendResponse( me, sockCtx->sock, dest );
-               require_noerr( err, exit );
-       }
-       else if( action == kMDNSColliderProbeAction_Probe )
-       {
-               dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
-               
-               err = _MDNSColliderSendProbe( me, sockCtx->sock, dest );
-               require_noerr( err, exit );
-       }
-       
-exit:
-       return;
-}
-
-static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber )
-{
-       MDNSColliderProbeAction         action;
-       
-       if( ( inProbeNumber >= 1 ) && ( inProbeNumber <= kMDNSColliderProbeActionMaxProbeCount ) )
-       {
-               action = ( inBitmap >> ( ( inProbeNumber - 1 ) * kMDNSColliderProbeActionBits_Count ) ) &
-                       kMDNSColliderProbeActionBits_Mask;
-       }
-       else
-       {
-               action = kMDNSColliderProbeAction_None;
-       }
-       return( action );
-}
-
-static const char *    _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction )
-{
-       switch( inAction )
-       {
-               case kMDNSColliderProbeAction_None:                             return( "None" );
-               case kMDNSColliderProbeAction_Respond:                  return( "Respond" );
-               case kMDNSColliderProbeAction_RespondUnicast:   return( "Respond (unicast)" );
-               case kMDNSColliderProbeAction_RespondMulticast: return( "Respond (multicast)" );
-               case kMDNSColliderProbeAction_Probe:                    return( "Probe" );
-               default:                                                                                return( "???" );
-       }
-}
-
-//===========================================================================================================================
-//     _MDNSColliderExecuteProgram
-//===========================================================================================================================
-
-static void    _MDNSColliderExecuteProgram( void *inContext )
-{
-       OSStatus                                        err;
-       MDNSColliderRef const           me = (MDNSColliderRef) inContext;
-       int                                                     stop;
-       
-       dispatch_forget( &me->waitTimer );
-       
-       stop = false;
-       for( ;; )
-       {
-               const MDNSCInstruction * const          ins = &me->program[ me->pc++ ];
-               uint32_t                                                        waitMs;
-               
-               switch( ins->opcode )
-               {
-                       case kMDNSColliderOpCode_Send:
-                               if( IsValidSocket( me->sockV4 ) )
-                               {
-                                       err = _MDNSColliderSendResponse( me, me->sockV4, GetMDNSMulticastAddrV4() );
-                                       require_noerr( err, exit );
-                               }
-                               if( IsValidSocket( me->sockV6 ) )
-                               {
-                                       err = _MDNSColliderSendResponse( me, me->sockV6, GetMDNSMulticastAddrV6() );
-                                       require_noerr( err, exit );
-                               }
-                               break;
-                       
-                       case kMDNSColliderOpCode_Wait:
-                               waitMs = ins->operand;
-                               if( waitMs > 0 )
-                               {
-                                       err = DispatchTimerOneShotCreate( dispatch_time_milliseconds( waitMs ), 1, me->queue,
-                                               _MDNSColliderExecuteProgram, me, &me->waitTimer );
-                                       require_noerr( err, exit );
-                                       dispatch_resume( me->waitTimer );
-                                       goto exit;
-                               }
-                               break;
-                       
-                       case kMDNSColliderOpCode_SetProbeActions:
-                               me->probeCount          = 0;
-                               me->probeActionMap      = ins->operand;
-                               break;
-                       
-                       case kMDNSColliderOpCode_LoopPush:
-                               check( me->loopDepth < kMaxLoopDepth );
-                               me->loopCounts[ me->loopDepth++ ] = ins->operand;
-                               break;
-                       
-                       case kMDNSColliderOpCode_LoopPop:
-                               check( me->loopDepth > 0 );
-                               if( --me->loopCounts[ me->loopDepth - 1 ] > 0 )
-                               {
-                                       me->pc = ins->operand;
-                               }
-                               else
-                               {
-                                       --me->loopDepth;
-                               }
-                               break;
-                       
-                       case kMDNSColliderOpCode_Exit:
-                               stop = true;
-                               err     = kNoErr;
-                               goto exit;
-                       
-                       default:
-                               dlogassert( "Unhandled opcode %u\n", ins->opcode );
-                               err = kCommandErr;
-                               goto exit;
-               }
-       }
-       
-exit:
-       if( err || stop ) _MDNSColliderStop( me, err );
-}
-
-//===========================================================================================================================
-//     _MDNSColliderSendResponse
-//===========================================================================================================================
-
-static OSStatus        _MDNSColliderSendResponse( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
-{
-       OSStatus                err;
-       ssize_t                 n;
-       
-       n = sendto( inSock, (char *) me->responsePtr, me->responseLen, 0, inDest, SockAddrGetSize( inDest ) );
-       err = map_socket_value_errno( inSock, n == (ssize_t) me->responseLen, n );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _MDNSColliderSendProbe
-//===========================================================================================================================
-
-static OSStatus        _MDNSColliderSendProbe( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
-{
-       OSStatus                err;
-       ssize_t                 n;
-       
-       n = sendto( inSock, (char *) me->probePtr, me->probeLen, 0, inDest, SockAddrGetSize( inDest ) );
-       err = map_socket_value_errno( inSock, n == (ssize_t) me->probeLen, n );
-       return( err );
-}
-
-//===========================================================================================================================
-//     ServiceBrowserCreate
-//===========================================================================================================================
-
-typedef struct SBDomain                                        SBDomain;
-typedef struct SBServiceType                   SBServiceType;
-typedef struct SBServiceBrowse                 SBServiceBrowse;
-typedef struct SBServiceInstance               SBServiceInstance;
-typedef struct SBIPAddress                             SBIPAddress;
-
-struct ServiceBrowserPrivate
-{
-       CFRuntimeBase                                   base;                           // CF object base.
-       dispatch_queue_t                                queue;                          // Queue for service browser's events.
-       DNSServiceRef                                   connection;                     // Shared connection for DNS-SD ops.
-       DNSServiceRef                                   domainsQuery;           // Query for recommended browsing domains.
-       char *                                                  domain;                         // If non-null, then browsing is limited to this domain.
-       StringListItem *                                serviceTypeList;        // If non-null, then browsing is limited to these service types.
-       ServiceBrowserCallback_f                userCallback;           // User's callback. Called when browsing stops.
-       void *                                                  userContext;            // User's callback context.
-       SBDomain *                                              domainList;                     // List of domains and their browse results.
-       dispatch_source_t                               stopTimer;                      // Timer to stop browsing after browseTimeSecs.
-       uint32_t                                                ifIndex;                        // If non-zero, then browsing is limited to this interface.
-       unsigned int                                    browseTimeSecs;         // Amount of time to spend browsing in seconds.
-       Boolean                                                 includeAWDL;            // True if the IncludeAWDL flag should be used for DNS-SD ops that
-                                                                                                               // use the "any" interface.
-};
-
-struct SBDomain
-{
-       SBDomain *                              next;                   // Next domain object in list.
-       ServiceBrowserRef               browser;                // Pointer to parent service browser.
-       char *                                  name;                   // Name of the domain.
-       DNSServiceRef                   servicesQuery;  // Query for services (_services._dns-sd._udp.<domain> PTR record) in domain.
-       SBServiceType *                 typeList;               // List of service types to browse for in this domain.
-};
-
-struct SBServiceType
-{
-       SBServiceType *                 next;           // Next service type object in list.
-       char *                                  name;           // Name of the service type.
-       SBServiceBrowse *               browseList;     // List of browses for this service type.
-};
-
-struct SBServiceBrowse
-{
-       SBServiceBrowse *               next;                   // Next browse object in list.
-       ServiceBrowserRef               browser;                // Pointer to parent service browser.
-       DNSServiceRef                   browse;                 // Reference to DNSServiceBrowse op.
-       SBServiceInstance *             instanceList;   // List of service instances that were discovered by this browse.
-       uint64_t                                startTicks;             // Value of UpTicks() when the browse op began.
-       uint32_t                                ifIndex;                // If non-zero, then the browse is limited to this interface.
-};
-
-struct SBServiceInstance
-{
-       SBServiceInstance *             next;                           // Next service instance object in list.
-       ServiceBrowserRef               browser;                        // Pointer to parent service browser.
-       char *                                  name;                           // Name of the service instance.
-       uint32_t                                ifIndex;                        // Index of interface over which this service instance was discovered.
-       uint64_t                                discoverTimeUs;         // Time it took to discover this service instance in microseconds.
-       DNSServiceRef                   resolve;                        // Reference to DNSServiceResolve op for this service instance.
-       uint64_t                                resolveStartTicks;      // Value of UpTicks() when the DNSServiceResolve op began.
-       uint64_t                                resolveTimeUs;          // Time it took to resolve this service instance.
-       char *                                  hostname;                       // Service instance's hostname. Result of DNSServiceResolve.
-       uint16_t                                port;                           // Service instance's port number. Result of DNSServiceResolve.
-       uint8_t *                               txtPtr;                         // Service instance's TXT record data. Result of DNSServiceResolve.
-       size_t                                  txtLen;                         // Length of service instance's TXT record data.
-       DNSServiceRef                   getAddrInfo;            // Reference to DNSServiceGetAddrInfo op for service instance's hostname.
-       uint64_t                                gaiStartTicks;          // Value of UpTicks() when the DNSServiceGetAddrInfo op began.
-       SBIPAddress *                   ipaddrList;                     // List of IP addresses that the hostname resolved to.
-};
-
-struct SBIPAddress
-{
-       SBIPAddress *           next;                   // Next IP address object in list.
-       sockaddr_ip                     sip;                    // IPv4 or IPv6 address.
-       uint64_t                        resolveTimeUs;  // Time it took to resolve this IP address in microseconds.
-};
-
-typedef struct
-{
-       SBRDomain *             domainList;     // List of domains in which services were found.
-       int32_t                 refCount;       // This object's reference count.
-       
-}      ServiceBrowserResultsPrivate;
-
-static void            _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError );
-static OSStatus        _ServiceBrowserAddDomain( ServiceBrowserRef inBrowser, const char *inDomain );
-static OSStatus        _ServiceBrowserRemoveDomain( ServiceBrowserRef inBrowser, const char *inName );
-static void            _ServiceBrowserTimerHandler( void *inContext );
-static void DNSSD_API
-       _ServiceBrowserDomainsQueryCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static void DNSSD_API
-       _ServiceBrowserServicesQueryCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static void DNSSD_API
-       _ServiceBrowserBrowseCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inRegType,
-               const char *            inDomain,
-               void *                          inContext );
-static void DNSSD_API
-       _ServiceBrowserResolveCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               uint16_t                                inTXTLen,
-               const unsigned char *   inTXTPtr,
-               void *                                  inContext );
-static void DNSSD_API
-       _ServiceBrowserGAICallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext );
-static OSStatus
-       _ServiceBrowserAddServiceType(
-               ServiceBrowserRef       inBrowser,
-               SBDomain *                      inDomain,
-               const char *            inName,
-               uint32_t                        inIfIndex );
-static OSStatus
-       _ServiceBrowserRemoveServiceType(
-               ServiceBrowserRef       inBrowser,
-               SBDomain *                      inDomain,
-               const char *            inName,
-               uint32_t                        inIfIndex );
-static OSStatus
-       _ServiceBrowserAddServiceInstance(
-               ServiceBrowserRef       inBrowser,
-               SBServiceBrowse *       inBrowse,
-               uint32_t                        inIfIndex,
-               const char *            inName,
-               const char *            inRegType,
-               const char *            inDomain,
-               uint64_t                        inDiscoverTimeUs );
-static OSStatus
-       _ServiceBrowserRemoveServiceInstance(
-               ServiceBrowserRef       inBrowser,
-               SBServiceBrowse *       inBrowse,
-               const char *            inName,
-               uint32_t                        inIfIndex );
-static OSStatus
-       _ServiceBrowserAddIPAddress(
-               ServiceBrowserRef               inBrowser,
-               SBServiceInstance *             inInstance,
-               const struct sockaddr * inSockAddr,
-               uint64_t                                inResolveTimeUs );
-static OSStatus
-       _ServiceBrowserRemoveIPAddress(
-               ServiceBrowserRef               inBrowser,
-               SBServiceInstance *             inInstance,
-               const struct sockaddr * inSockAddr );
-static OSStatus        _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults );
-static OSStatus        _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain );
-static void            _SBDomainFree( SBDomain *inDomain );
-static OSStatus        _SBServiceTypeCreate( const char *inName, SBServiceType **outType );
-static void            _SBServiceTypeFree( SBServiceType *inType );
-static OSStatus        _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse );
-static void            _SBServiceBrowseFree( SBServiceBrowse *inBrowse );
-static OSStatus
-       _SBServiceInstanceCreate(
-               const char *                    inName,
-               uint32_t                                inIfIndex,
-               uint64_t                                inDiscoverTimeUs,
-               ServiceBrowserRef               inBrowser,
-               SBServiceInstance **    outInstance );
-static void            _SBServiceInstanceFree( SBServiceInstance *inInstance );
-static OSStatus
-       _SBIPAddressCreate(
-               const struct sockaddr * inSockAddr,
-               uint64_t                                inResolveTimeUs,
-               SBIPAddress **                  outIPAddress );
-static void            _SBIPAddressFree( SBIPAddress *inIPAddress );
-static void            _SBIPAddressFreeList( SBIPAddress *inList );
-static OSStatus        _SBRDomainCreate( const char *inName, SBRDomain **outDomain );
-static void            _SBRDomainFree( SBRDomain *inDomain );
-static OSStatus        _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType );
-static void            _SBRServiceTypeFree( SBRServiceType *inType );
-static OSStatus
-       _SBRServiceInstanceCreate(
-               const char *                    inName,
-               uint32_t                                inInterfaceIndex,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               const uint8_t *                 inTXTPtr,
-               size_t                                  inTXTLen,
-               uint64_t                                inDiscoverTimeUs,
-               uint64_t                                inResolveTimeUs,
-               SBRServiceInstance **   outInstance );
-static void            _SBRServiceInstanceFree( SBRServiceInstance *inInstance );
-static OSStatus
-       _SBRIPAddressCreate(
-               const struct sockaddr * inSockAddr,
-               uint64_t                                inResolveTimeUs,
-               SBRIPAddress **                 outIPAddress );
-static void            _SBRIPAddressFree( SBRIPAddress *inIPAddress );
-
-#define ForgetSBIPAddressList( X )             ForgetCustom( X, _SBIPAddressFreeList )
-
-CF_CLASS_DEFINE( ServiceBrowser );
-
-static OSStatus
-       ServiceBrowserCreate(
-               dispatch_queue_t        inQueue,
-               uint32_t                        inInterfaceIndex,
-               const char *            inDomain,
-               unsigned int            inBrowseTimeSecs,
-               Boolean                         inIncludeAWDL,
-               ServiceBrowserRef *     outBrowser )
-{
-       OSStatus                                err;
-       ServiceBrowserRef               obj;
-       
-       CF_OBJECT_CREATE( ServiceBrowser, obj, err, exit );
-       
-       ReplaceDispatchQueue( &obj->queue, inQueue );
-       obj->ifIndex            = inInterfaceIndex;
-       if( inDomain )
-       {
-               obj->domain = strdup( inDomain );
-               require_action( obj->domain, exit, err = kNoMemoryErr );
-       }
-       obj->browseTimeSecs     = inBrowseTimeSecs;
-       obj->includeAWDL        = inIncludeAWDL;
-       
-       *outBrowser = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       CFReleaseNullSafe( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserFinalize
-//===========================================================================================================================
-
-static void    _ServiceBrowserFinalize( CFTypeRef inObj )
-{
-       ServiceBrowserRef const         me = (ServiceBrowserRef) inObj;
-       StringListItem *                        serviceType;
-       
-       dispatch_forget( &me->queue );
-       check( !me->connection );
-       check( !me->domainsQuery );
-       ForgetMem( &me->domain );
-       while( ( serviceType = me->serviceTypeList ) != NULL )
-       {
-               me->serviceTypeList = serviceType->next;
-               ForgetMem( &serviceType->str );
-               free( serviceType );
-       }
-       check( !me->domainList );
-       check( !me->stopTimer );
-}
-
-//===========================================================================================================================
-//     ServiceBrowserStart
-//===========================================================================================================================
-
-static void    _ServiceBrowserStart( void *inContext );
-
-static void    ServiceBrowserStart( ServiceBrowserRef me )
-{
-       CFRetain( me );
-       dispatch_async_f( me->queue, me, _ServiceBrowserStart );
-}
-
-static void    _ServiceBrowserStart( void *inContext )
-{
-       OSStatus                                        err;
-       ServiceBrowserRef const         me = (ServiceBrowserRef) inContext;
-       
-       err = DNSServiceCreateConnection( &me->connection );
-       require_noerr( err, exit );
-       
-       err = DNSServiceSetDispatchQueue( me->connection, me->queue );
-       require_noerr( err, exit );
-       
-       if( me->domain )
-       {
-               err = _ServiceBrowserAddDomain( me, me->domain );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               DNSServiceRef           sdRef;
-               
-               sdRef = me->connection;
-               err = DNSServiceQueryRecord( &sdRef, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexLocalOnly,
-                       "b._dns-sd._udp.local.", kDNSServiceType_PTR, kDNSServiceClass_IN, _ServiceBrowserDomainsQueryCallback, me );
-               require_noerr( err, exit );
-               
-               me->domainsQuery = sdRef;
-       }
-       
-       err = DispatchTimerCreate( dispatch_time_seconds( me->browseTimeSecs ), DISPATCH_TIME_FOREVER,
-               100 * kNanosecondsPerMillisecond, me->queue, _ServiceBrowserTimerHandler, NULL, me, &me->stopTimer );
-       require_noerr( err, exit );
-       dispatch_resume( me->stopTimer );
-       
-exit:
-       if( err ) _ServiceBrowserStop( me, err );
-}
-
-//===========================================================================================================================
-//     ServiceBrowserAddServiceType
-//===========================================================================================================================
-
-static OSStatus        ServiceBrowserAddServiceType( ServiceBrowserRef me, const char *inServiceType )
-{
-       OSStatus                                err;
-       StringListItem *                item;
-       StringListItem **               itemPtr;
-       StringListItem *                newItem = NULL;
-       
-       for( itemPtr = &me->serviceTypeList; ( item = *itemPtr ) != NULL; itemPtr = &item->next )
-       {
-               if( strcmp( item->str, inServiceType ) == 0 ) break;
-       }
-       if( !item )
-       {
-               newItem = (StringListItem *) calloc( 1, sizeof( *newItem ) );
-               require_action( newItem, exit, err = kNoMemoryErr );
-               
-               newItem->str = strdup( inServiceType );
-               require_action( newItem->str, exit, err = kNoMemoryErr );
-               
-               *itemPtr = newItem;
-               newItem = NULL;
-       }
-       err = kNoErr;
-       
-exit:
-       FreeNullSafe( newItem );
-       return( err );
-}
-
-//===========================================================================================================================
-//     ServiceBrowserSetCallback
-//===========================================================================================================================
-
-static void    ServiceBrowserSetCallback( ServiceBrowserRef me, ServiceBrowserCallback_f inCallback, void *inContext )
-{
-       me->userCallback        = inCallback;
-       me->userContext         = inContext;
-}
-
-//===========================================================================================================================
-//     ServiceBrowserResultsRetain
-//===========================================================================================================================
-
-static void    ServiceBrowserResultsRetain( ServiceBrowserResults *inResults )
-{
-       ServiceBrowserResultsPrivate * const            results = (ServiceBrowserResultsPrivate *) inResults;
-       
-       atomic_add_32( &results->refCount, 1 );
-}
-
-//===========================================================================================================================
-//     ServiceBrowserResultsRelease
-//===========================================================================================================================
-
-static void    ServiceBrowserResultsRelease( ServiceBrowserResults *inResults )
-{
-       ServiceBrowserResultsPrivate * const            results = (ServiceBrowserResultsPrivate *) inResults;
-       SBRDomain *                                                                     domain;
-       
-       if( atomic_add_and_fetch_32( &results->refCount, -1 ) == 0 )
-       {
-               while( ( domain = inResults->domainList ) != NULL )
-               {
-                       inResults->domainList = domain->next;
-                       _SBRDomainFree( domain );
-               }
-               free( inResults );
-       }
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserStop
-//===========================================================================================================================
-
-static void    _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError )
-{
-       OSStatus                                err;
-       SBDomain *                              d;
-       SBServiceType *                 t;
-       SBServiceBrowse *               b;
-       SBServiceInstance *             i;
-       
-       dispatch_source_forget( &me->stopTimer );
-       DNSServiceForget( &me->domainsQuery );
-       for( d = me->domainList; d; d = d->next )
-       {
-               DNSServiceForget( &d->servicesQuery );
-               for( t = d->typeList; t; t = t->next )
-               {
-                       for( b = t->browseList; b; b = b->next )
-                       {
-                               DNSServiceForget( &b->browse );
-                               for( i = b->instanceList; i; i = i->next )
-                               {
-                                       DNSServiceForget( &i->resolve );
-                                       DNSServiceForget( &i->getAddrInfo );
-                               }
-                       }
-               }
-       }
-       DNSServiceForget( &me->connection );
-       
-       if( me->userCallback )
-       {
-               ServiceBrowserResults *         results = NULL;
-               
-               err = _ServiceBrowserCreateResults( me, &results );
-               if( !err ) err = inError;
-               
-               me->userCallback( results, err, me->userContext );
-               me->userCallback        = NULL;
-               me->userContext         = NULL;
-               if( results ) ServiceBrowserResultsRelease( results );
-       }
-       
-       while( ( d = me->domainList ) != NULL )
-       {
-               me->domainList = d->next;
-               _SBDomainFree( d );
-       }
-       CFRelease( me );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserAddDomain
-//===========================================================================================================================
-
-static OSStatus        _ServiceBrowserAddDomain( ServiceBrowserRef me, const char *inDomain )
-{
-       OSStatus                err;
-       SBDomain *              domain;
-       SBDomain **             domainPtr;
-       SBDomain *              newDomain = NULL;
-       
-       for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
-       {
-               if( strcasecmp( domain->name, inDomain ) == 0 ) break;
-       }
-       require_action_quiet( !domain, exit, err = kDuplicateErr );
-       
-       err = _SBDomainCreate( inDomain, me, &newDomain );
-       require_noerr_quiet( err, exit );
-       
-       if( me->serviceTypeList )
-       {
-               const StringListItem *          item;
-               
-               for( item = me->serviceTypeList; item; item = item->next )
-               {
-                       err = _ServiceBrowserAddServiceType( me, newDomain, item->str, me->ifIndex );
-                       if( err == kDuplicateErr ) err = kNoErr;
-                       require_noerr( err, exit );
-               }
-       }
-       else
-       {
-               char *                          recordName;
-               DNSServiceFlags         flags;
-               DNSServiceRef           sdRef;
-               
-               ASPrintF( &recordName, "_services._dns-sd._udp.%s", newDomain->name );
-               require_action( recordName, exit, err = kNoMemoryErr );
-               
-               flags = kDNSServiceFlagsShareConnection;
-               if( ( me->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
-               
-               sdRef = newDomain->browser->connection;
-               err = DNSServiceQueryRecord( &sdRef, flags, me->ifIndex, recordName, kDNSServiceType_PTR, kDNSServiceClass_IN,
-                       _ServiceBrowserServicesQueryCallback, newDomain );
-               free( recordName );
-               require_noerr( err, exit );
-               
-               newDomain->servicesQuery = sdRef;
-       }
-       
-       *domainPtr      = newDomain;
-       newDomain       = NULL;
-       err = kNoErr;
-       
-exit:
-       if( newDomain ) _SBDomainFree( newDomain );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserRemoveDomain
-//===========================================================================================================================
-
-static OSStatus        _ServiceBrowserRemoveDomain( ServiceBrowserRef me, const char *inName )
-{
-       OSStatus                err;
-       SBDomain *              domain;
-       SBDomain **             domainPtr;
-       
-       for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
-       {
-               if( strcasecmp( domain->name, inName ) == 0 ) break;
-       }
-       
-       if( domain )
-       {
-               *domainPtr = domain->next;
-               _SBDomainFree( domain );
-               err = kNoErr;
-       }
-       else
-       {
-               err = kNotFoundErr;
-       }
-       
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserTimerHandler
-//===========================================================================================================================
-
-static void    _ServiceBrowserTimerHandler( void *inContext )
-{
-       ServiceBrowserRef const         me = (ServiceBrowserRef) inContext;
-       
-       _ServiceBrowserStop( me, kNoErr );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserDomainsQueryCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _ServiceBrowserDomainsQueryCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       ServiceBrowserRef const         me = (ServiceBrowserRef) inContext;
-       OSStatus                                        err;
-       char                                            domainStr[ kDNSServiceMaxDomainName ];
-       
-       Unused( inSDRef );
-       Unused( inInterfaceIndex );
-       Unused( inFullName );
-       Unused( inType );
-       Unused( inClass );
-       Unused( inTTL );
-       
-       require_noerr( inError, exit );
-       
-       err = DomainNameToString( inRDataPtr, ( (const uint8_t *) inRDataPtr ) + inRDataLen, domainStr, NULL );
-       require_noerr( err, exit );
-       
-       if( inFlags & kDNSServiceFlagsAdd )
-       {
-               err = _ServiceBrowserAddDomain( me, domainStr );
-               if( err == kDuplicateErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = _ServiceBrowserRemoveDomain( me, domainStr );
-               if( err == kNotFoundErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserServicesQueryCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _ServiceBrowserServicesQueryCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               uint16_t                                inType,
-               uint16_t                                inClass,
-               uint16_t                                inRDataLen,
-               const void *                    inRDataPtr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       OSStatus                                        err;
-       SBDomain * const                        domain  = (SBDomain *) inContext;
-       ServiceBrowserRef const         me              = domain->browser;
-       const uint8_t *                         src;
-       const uint8_t *                         end;
-       uint8_t *                                       dst;
-       int                                                     i;
-       uint8_t                                         serviceType[ 2 * ( 1 + kDomainLabelLengthMax ) + 1 ];
-       char                                            serviceTypeStr[ kDNSServiceMaxDomainName ];
-       
-       Unused( inSDRef );
-       Unused( inFullName );
-       Unused( inTTL );
-       Unused( inType );
-       Unused( inClass );
-       
-       require_noerr( inError, exit );
-       
-       check( inType  == kDNSServiceType_PTR );
-       check( inClass == kDNSServiceClass_IN );
-       
-       // The first two labels of the domain name in the RDATA describe a service type.
-       // See <https://tools.ietf.org/html/rfc6763#section-9>.
-       
-       src = (const uint8_t *) inRDataPtr;
-       end = src + inRDataLen;
-       dst = serviceType;
-       for( i = 0; i < 2; ++i )
-       {
-               size_t          labelLen;
-               
-               require_action_quiet( ( end - src ) > 0, exit, err = kUnderrunErr );
-               
-               labelLen = *src;
-               require_action_quiet( ( labelLen > 0 ) && ( labelLen <= kDomainLabelLengthMax ), exit, err = kMalformedErr );
-               require_action_quiet( ( (size_t)( end - src ) ) >= ( 1 + labelLen ), exit, err = kUnderrunErr );
-               
-               memcpy( dst, src, 1 + labelLen );
-               src += 1 + labelLen;
-               dst += 1 + labelLen;
-       }
-       *dst = 0;
-       
-       err = DomainNameToString( serviceType, NULL, serviceTypeStr, NULL );
-       require_noerr( err, exit );
-       
-       if( inFlags & kDNSServiceFlagsAdd )
-       {
-               err = _ServiceBrowserAddServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
-               if( err == kDuplicateErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = _ServiceBrowserRemoveServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
-               if( err == kNotFoundErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserBrowseCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _ServiceBrowserBrowseCallback(
-               DNSServiceRef           inSDRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inError,
-               const char *            inName,
-               const char *            inRegType,
-               const char *            inDomain,
-               void *                          inContext )
-{
-       OSStatus                                        err;
-       const uint64_t                          nowTicks        = UpTicks();
-       SBServiceBrowse * const         browse          = (SBServiceBrowse *) inContext;
-       ServiceBrowserRef const         me                      = (ServiceBrowserRef) browse->browser;
-       
-       Unused( inSDRef );
-       
-       require_noerr( inError, exit );
-       
-       if( inFlags & kDNSServiceFlagsAdd )
-       {
-               err = _ServiceBrowserAddServiceInstance( me, browse, inInterfaceIndex, inName, inRegType, inDomain,
-                       UpTicksToMicroseconds( nowTicks - browse->startTicks ) );
-               if( err == kDuplicateErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = _ServiceBrowserRemoveServiceInstance( me, browse, inName, inInterfaceIndex );
-               if( err == kNotFoundErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserResolveCallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _ServiceBrowserResolveCallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inFullName,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               uint16_t                                inTXTLen,
-               const unsigned char *   inTXTPtr,
-               void *                                  inContext )
-{
-       OSStatus                                                err;
-       const uint64_t                                  nowTicks        = UpTicks();
-       SBServiceInstance * const               instance        = (SBServiceInstance *) inContext;
-       ServiceBrowserRef const                 me                      = (ServiceBrowserRef) instance->browser;
-       
-       Unused( inSDRef );
-       Unused( inFlags );
-       Unused( inInterfaceIndex );
-       Unused( inFullName );
-       
-       require_noerr( inError, exit );
-       
-       if( !MemEqual( instance->txtPtr, instance->txtLen, inTXTPtr, inTXTLen ) )
-       {
-               FreeNullSafe( instance->txtPtr );
-               instance->txtPtr = memdup( inTXTPtr, inTXTLen );
-               require_action( instance->txtPtr, exit, err = kNoMemoryErr );
-               
-               instance->txtLen = inTXTLen;
-       }
-       
-       instance->port = ntohs( inPort );
-       
-       if( !instance->hostname || ( strcasecmp( instance->hostname, inHostname ) != 0 ) )
-       {
-               DNSServiceRef           sdRef;
-               
-               if( !instance->hostname ) instance->resolveTimeUs = UpTicksToMicroseconds( nowTicks - instance->resolveStartTicks );
-               
-               err = ReplaceString( &instance->hostname, NULL, inHostname, kSizeCString );
-               require_noerr( err, exit );
-               
-               DNSServiceForget( &instance->getAddrInfo );
-               ForgetSBIPAddressList( &instance->ipaddrList );
-               
-               sdRef = me->connection;
-               instance->gaiStartTicks = UpTicks();
-               err = DNSServiceGetAddrInfo( &sdRef, kDNSServiceFlagsShareConnection, instance->ifIndex,
-                       kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, instance->hostname, _ServiceBrowserGAICallback, instance );
-               require_noerr( err, exit );
-               
-               instance->getAddrInfo = sdRef;
-       }
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserGAICallback
-//===========================================================================================================================
-
-static void DNSSD_API
-       _ServiceBrowserGAICallback(
-               DNSServiceRef                   inSDRef,
-               DNSServiceFlags                 inFlags,
-               uint32_t                                inInterfaceIndex,
-               DNSServiceErrorType             inError,
-               const char *                    inHostname,
-               const struct sockaddr * inSockAddr,
-               uint32_t                                inTTL,
-               void *                                  inContext )
-{
-       OSStatus                                                err;
-       const uint64_t                                  nowTicks        = UpTicks();
-       SBServiceInstance * const               instance        = (SBServiceInstance *) inContext;
-       ServiceBrowserRef const                 me                      = (ServiceBrowserRef) instance->browser;
-       
-       Unused( inSDRef );
-       Unused( inInterfaceIndex );
-       Unused( inHostname );
-       Unused( inTTL );
-       
-       require_noerr( inError, exit );
-       
-       if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
-       {
-               dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
-               goto exit;
-       }
-       
-       if( inFlags & kDNSServiceFlagsAdd )
-       {
-               err = _ServiceBrowserAddIPAddress( me, instance, inSockAddr,
-                       UpTicksToMicroseconds( nowTicks - instance->gaiStartTicks ) );
-               if( err == kDuplicateErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = _ServiceBrowserRemoveIPAddress( me, instance, inSockAddr );
-               if( err == kNotFoundErr ) err = kNoErr;
-               require_noerr( err, exit );
-       }
-       
-exit:
-       return;
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserAddServiceType
-//===========================================================================================================================
-
-static OSStatus
-       _ServiceBrowserAddServiceType(
-               ServiceBrowserRef       me,
-               SBDomain *                      inDomain,
-               const char *            inName,
-               uint32_t                        inIfIndex )
-{
-       OSStatus                                err;
-       SBServiceType *                 type;
-       SBServiceType **                typePtr;
-       SBServiceType *                 newType         = NULL;
-       SBServiceBrowse *               browse;
-       SBServiceBrowse **              browsePtr;
-       SBServiceBrowse *               newBrowse       = NULL;
-       DNSServiceRef                   sdRef;
-       DNSServiceFlags                 flags;
-       
-       for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
-       {
-               if( strcasecmp( type->name, inName ) == 0 ) break;
-       }
-       if( !type )
-       {
-               err = _SBServiceTypeCreate( inName, &newType );
-               require_noerr_quiet( err, exit );
-               
-               type = newType;
-       }
-       
-       for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
-       {
-               if( browse->ifIndex == inIfIndex ) break;
-       }
-       require_action_quiet( !browse, exit, err = kDuplicateErr );
-       
-       err = _SBServiceBrowseCreate( inIfIndex, me, &newBrowse );
-       require_noerr_quiet( err, exit );
-       
-       flags = kDNSServiceFlagsShareConnection;
-       if( ( newBrowse->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
-       
-       sdRef = me->connection;
-       newBrowse->startTicks = UpTicks();
-       err = DNSServiceBrowse( &sdRef, flags, newBrowse->ifIndex, type->name, inDomain->name, _ServiceBrowserBrowseCallback,
-               newBrowse );
-       require_noerr( err, exit );
-       
-       newBrowse->browse = sdRef;
-       *browsePtr      = newBrowse;
-       newBrowse       = NULL;
-       
-       if( newType )
-       {
-               *typePtr        = newType;
-               newType         = NULL;
-       }
-       
-exit:
-       if( newBrowse ) _SBServiceBrowseFree( newBrowse );
-       if( newType )   _SBServiceTypeFree( newType );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserRemoveServiceType
-//===========================================================================================================================
-
-static OSStatus
-       _ServiceBrowserRemoveServiceType(
-               ServiceBrowserRef       me,
-               SBDomain *                      inDomain,
-               const char *            inName,
-               uint32_t                        inIfIndex )
-{
-       OSStatus                                err;
-       SBServiceType *                 type;
-       SBServiceType **                typePtr;
-       SBServiceBrowse *               browse;
-       SBServiceBrowse **              browsePtr;
-       
-       Unused( me );
-       
-       for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
-       {
-               if( strcasecmp( type->name, inName ) == 0 ) break;
-       }
-       require_action_quiet( type, exit, err = kNotFoundErr );
-       
-       for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
-       {
-               if( browse->ifIndex == inIfIndex ) break;
-       }
-       require_action_quiet( browse, exit, err = kNotFoundErr );
-       
-       *browsePtr = browse->next;
-       _SBServiceBrowseFree( browse );
-       if( !type->browseList )
-       {
-               *typePtr = type->next;
-               _SBServiceTypeFree( type );
-       }
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserAddServiceInstance
-//===========================================================================================================================
-
-static OSStatus
-       _ServiceBrowserAddServiceInstance(
-               ServiceBrowserRef       me,
-               SBServiceBrowse *       inBrowse,
-               uint32_t                        inIfIndex,
-               const char *            inName,
-               const char *            inRegType,
-               const char *            inDomain,
-               uint64_t                        inDiscoverTimeUs )
-{
-       OSStatus                                        err;
-       DNSServiceRef                           sdRef;
-       SBServiceInstance *                     instance;
-       SBServiceInstance **            instancePtr;
-       SBServiceInstance *                     newInstance     = NULL;
-       
-       for( instancePtr = &inBrowse->instanceList; ( instance = *instancePtr ) != NULL; instancePtr = &instance->next )
-       {
-               if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
-       }
-       require_action_quiet( !instance, exit, err = kDuplicateErr );
-       
-       err = _SBServiceInstanceCreate( inName, inIfIndex, inDiscoverTimeUs, me, &newInstance );
-       require_noerr_quiet( err, exit );
-       
-       sdRef = me->connection;
-       newInstance->resolveStartTicks = UpTicks();
-       err = DNSServiceResolve( &sdRef, kDNSServiceFlagsShareConnection, newInstance->ifIndex, inName, inRegType, inDomain,
-               _ServiceBrowserResolveCallback, newInstance );
-       require_noerr( err, exit );
-       
-       newInstance->resolve = sdRef;
-       *instancePtr    = newInstance;
-       newInstance             = NULL;
-       
-exit:
-       if( newInstance ) _SBServiceInstanceFree( newInstance );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserRemoveServiceInstance
-//===========================================================================================================================
-
-static OSStatus
-       _ServiceBrowserRemoveServiceInstance(
-               ServiceBrowserRef       me,
-               SBServiceBrowse *       inBrowse,
-               const char *            inName,
-               uint32_t                        inIfIndex )
-{
-       OSStatus                                        err;
-       SBServiceInstance *                     instance;
-       SBServiceInstance **            ptr;
-       
-       Unused( me );
-       
-       for( ptr = &inBrowse->instanceList; ( instance = *ptr ) != NULL; ptr = &instance->next )
-       {
-               if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
-       }
-       require_action_quiet( instance, exit, err = kNotFoundErr );
-       
-       *ptr = instance->next;
-       _SBServiceInstanceFree( instance );
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserAddIPAddress
-//===========================================================================================================================
-
-static OSStatus
-       _ServiceBrowserAddIPAddress(
-               ServiceBrowserRef               me,
-               SBServiceInstance *             inInstance,
-               const struct sockaddr * inSockAddr,
-               uint64_t                                inResolveTimeUs )
-{
-       OSStatus                        err;
-       SBIPAddress *           ipaddr;
-       SBIPAddress **          ipaddrPtr;
-       SBIPAddress *           newIPAddr = NULL;
-       
-       Unused( me );
-       
-       if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
-       {
-               dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
-               err = kTypeErr;
-               goto exit;
-       }
-       
-       for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
-       {
-               if( SockAddrCompareAddr( &ipaddr->sip, inSockAddr ) == 0 ) break;
-       }
-       require_action_quiet( !ipaddr, exit, err = kDuplicateErr );
-       
-       err = _SBIPAddressCreate( inSockAddr, inResolveTimeUs, &newIPAddr );
-       require_noerr_quiet( err, exit );
-       
-       *ipaddrPtr = newIPAddr;
-       newIPAddr = NULL;
-       err = kNoErr;
-       
-exit:
-       if( newIPAddr ) _SBIPAddressFree( newIPAddr );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserRemoveIPAddress
-//===========================================================================================================================
-
-static OSStatus
-       _ServiceBrowserRemoveIPAddress(
-               ServiceBrowserRef               me,
-               SBServiceInstance *             inInstance,
-               const struct sockaddr * inSockAddr )
-{
-       OSStatus                        err;
-       SBIPAddress *           ipaddr;
-       SBIPAddress **          ipaddrPtr;
-       
-       Unused( me );
-       
-       for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
-       {
-               if( SockAddrCompareAddr( &ipaddr->sip.sa, inSockAddr ) == 0 ) break;
-       }
-       require_action_quiet( ipaddr, exit, err = kNotFoundErr );
-       
-       *ipaddrPtr = ipaddr->next;
-       _SBIPAddressFree( ipaddr );
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _ServiceBrowserCreateResults
-//===========================================================================================================================
-
-static OSStatus        _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults )
-{
-       OSStatus                                                        err;
-       SBDomain *                                                      d;
-       SBServiceType *                                         t;
-       SBServiceBrowse *                                       b;
-       SBServiceInstance *                                     i;
-       SBIPAddress *                                           a;
-       ServiceBrowserResultsPrivate *          results;
-       SBRDomain **                                            domainPtr;
-       
-       results = (ServiceBrowserResultsPrivate *) calloc( 1, sizeof( *results ) );
-       require_action( results, exit, err = kNoMemoryErr );
-       
-       results->refCount = 1;
-       
-       domainPtr = &results->domainList;
-       for( d = me->domainList; d; d = d->next )
-       {
-               SBRDomain *                             domain;
-               SBRServiceType **               typePtr;
-               
-               err = _SBRDomainCreate( d->name, &domain );
-               require_noerr_quiet( err, exit );
-               *domainPtr = domain;
-                domainPtr = &domain->next;
-               
-               typePtr = &domain->typeList;
-               for( t = d->typeList; t; t = t->next )
-               {
-                       SBRServiceType *                        type;
-                       SBRServiceInstance **           instancePtr;
-                       
-                       err = _SBRServiceTypeCreate( t->name, &type );
-                       require_noerr_quiet( err, exit );
-                       *typePtr = type;
-                        typePtr = &type->next;
-                       
-                       instancePtr = &type->instanceList;
-                       for( b = t->browseList; b; b = b->next )
-                       {
-                               for( i = b->instanceList; i; i = i->next )
-                               {
-                                       SBRServiceInstance *            instance;
-                                       SBRIPAddress **                         ipaddrPtr;
-                                       
-                                       err = _SBRServiceInstanceCreate( i->name, i->ifIndex, i->hostname, i->port, i->txtPtr, i->txtLen,
-                                               i->discoverTimeUs, i->resolveTimeUs, &instance );
-                                       require_noerr_quiet( err, exit );
-                                       *instancePtr = instance;
-                                        instancePtr = &instance->next;
-                                       
-                                       ipaddrPtr = &instance->ipaddrList;
-                                       for( a = i->ipaddrList; a; a = a->next )
-                                       {
-                                               SBRIPAddress *          ipaddr;
-                                               
-                                               err = _SBRIPAddressCreate( &a->sip.sa, a->resolveTimeUs, &ipaddr );
-                                               require_noerr_quiet( err, exit );
-                                               
-                                               *ipaddrPtr = ipaddr;
-                                                ipaddrPtr = &ipaddr->next;
-                                       }
-                               }
-                       }
-               }
-       }
-       
-       *outResults = (ServiceBrowserResults *) results;
-       results = NULL;
-       err = kNoErr;
-       
-exit:
-       if( results ) ServiceBrowserResultsRelease( (ServiceBrowserResults *) results );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBDomainCreate
-//===========================================================================================================================
-
-static OSStatus        _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain )
-{
-       OSStatus                err;
-       SBDomain *              obj;
-       
-       obj = (SBDomain *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name = strdup( inName );
-       require_action( obj->name, exit, err = kNoMemoryErr );
-       
-       obj->browser = inBrowser;
-       
-       *outDomain = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) _SBDomainFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBDomainFree
-//===========================================================================================================================
-
-static void    _SBDomainFree( SBDomain *inDomain )
-{
-       SBServiceType *         type;
-       
-       ForgetMem( &inDomain->name );
-       DNSServiceForget( &inDomain->servicesQuery );
-       while( ( type = inDomain->typeList ) != NULL )
-       {
-               inDomain->typeList = type->next;
-               _SBServiceTypeFree( type );
-       }
-       free( inDomain );
-}
-
-//===========================================================================================================================
-//     _SBServiceTypeCreate
-//===========================================================================================================================
-
-static OSStatus        _SBServiceTypeCreate( const char *inName, SBServiceType **outType )
-{
-       OSStatus                        err;
-       SBServiceType *         obj;
-       
-       obj = (SBServiceType *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name = strdup( inName );
-       require_action( obj->name, exit, err = kNoMemoryErr );
-       
-       *outType = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) _SBServiceTypeFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBServiceTypeFree
-//===========================================================================================================================
-
-static void    _SBServiceTypeFree( SBServiceType *inType )
-{
-       SBServiceBrowse *               browse;
-       
-       ForgetMem( &inType->name );
-       while( ( browse = inType->browseList ) != NULL )
-       {
-               inType->browseList = browse->next;
-               _SBServiceBrowseFree( browse );
-       }
-       free( inType );
-}
-
-//===========================================================================================================================
-//     _SBServiceBrowseCreate
-//===========================================================================================================================
-
-static OSStatus        _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse )
-{
-       OSStatus                                err;
-       SBServiceBrowse *               obj;
-       
-       obj = (SBServiceBrowse *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->ifIndex = inIfIndex;
-       obj->browser = inBrowser;
-       *outBrowse = obj;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBServiceBrowseFree
-//===========================================================================================================================
-
-static void    _SBServiceBrowseFree( SBServiceBrowse *inBrowse )
-{
-       SBServiceInstance *             instance;
-       
-       DNSServiceForget( &inBrowse->browse );
-       while( ( instance = inBrowse->instanceList ) != NULL )
-       {
-               inBrowse->instanceList = instance->next;
-               _SBServiceInstanceFree( instance );
-       }
-       free( inBrowse );
-}
-
-//===========================================================================================================================
-//     _SBServiceInstanceCreate
-//===========================================================================================================================
-
-static OSStatus
-       _SBServiceInstanceCreate(
-               const char *                    inName,
-               uint32_t                                inIfIndex,
-               uint64_t                                inDiscoverTimeUs,
-               ServiceBrowserRef               inBrowser,
-               SBServiceInstance **    outInstance )
-{
-       OSStatus                                err;
-       SBServiceInstance *             obj;
-       
-       obj = (SBServiceInstance *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name = strdup( inName );
-       require_action( obj->name, exit, err = kNoMemoryErr );
-       
-       obj->ifIndex            = inIfIndex;
-       obj->discoverTimeUs     = inDiscoverTimeUs;
-       obj->browser            = inBrowser;
-       
-       *outInstance = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) _SBServiceInstanceFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBServiceInstanceFree
-//===========================================================================================================================
-
-static void    _SBServiceInstanceFree( SBServiceInstance *inInstance )
-{
-       ForgetMem( &inInstance->name );
-       DNSServiceForget( &inInstance->resolve );
-       ForgetMem( &inInstance->hostname );
-       ForgetMem( &inInstance->txtPtr );
-       DNSServiceForget( &inInstance->getAddrInfo );
-       ForgetSBIPAddressList( &inInstance->ipaddrList );
-       free( inInstance );
-}
-
-//===========================================================================================================================
-//     _SBIPAddressCreate
-//===========================================================================================================================
-
-static OSStatus        _SBIPAddressCreate( const struct sockaddr *inSockAddr, uint64_t inResolveTimeUs, SBIPAddress **outIPAddress )
-{
-       OSStatus                        err;
-       SBIPAddress *           obj;
-       
-       obj = (SBIPAddress *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       SockAddrCopy( inSockAddr, &obj->sip );
-       obj->resolveTimeUs = inResolveTimeUs;
-       
-       *outIPAddress = obj;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBIPAddressFree
-//===========================================================================================================================
-
-static void _SBIPAddressFree( SBIPAddress *inIPAddress )
-{
-       free( inIPAddress );
-}
-
-//===========================================================================================================================
-//     _SBIPAddressFreeList
-//===========================================================================================================================
-
-static void    _SBIPAddressFreeList( SBIPAddress *inList )
-{
-       SBIPAddress *           ipaddr;
-       
-       while( ( ipaddr = inList ) != NULL )
-       {
-               inList = ipaddr->next;
-               _SBIPAddressFree( ipaddr );
-       }
-}
-
-//===========================================================================================================================
-//     _SBRDomainCreate
-//===========================================================================================================================
-
-static OSStatus        _SBRDomainCreate( const char *inName, SBRDomain **outDomain )
-{
-       OSStatus                err;
-       SBRDomain *             obj;
-       
-       obj = (SBRDomain *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name = strdup( inName );
-       require_action( obj->name, exit, err = kNoMemoryErr );
-       
-       *outDomain = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) _SBRDomainFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBRDomainFree
-//===========================================================================================================================
-
-static void    _SBRDomainFree( SBRDomain *inDomain )
-{
-       SBRServiceType *                type;
-       
-       ForgetMem( &inDomain->name );
-       while( ( type = inDomain->typeList ) != NULL )
-       {
-               inDomain->typeList = type->next;
-               _SBRServiceTypeFree( type );
-       }
-       free( inDomain );
-}
-
-//===========================================================================================================================
-//     _SBRServiceTypeCreate
-//===========================================================================================================================
-
-static OSStatus        _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType )
-{
-       OSStatus                                err;
-       SBRServiceType *                obj;
-       
-       obj = (SBRServiceType *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name = strdup( inName );
-       require_action( obj->name, exit, err = kNoMemoryErr );
-       
-       *outType = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) _SBRServiceTypeFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBRServiceTypeFree
-//===========================================================================================================================
-
-static void    _SBRServiceTypeFree( SBRServiceType *inType )
-{
-       SBRServiceInstance *            instance;
-       
-       ForgetMem( &inType->name );
-       while( ( instance = inType->instanceList ) != NULL )
-       {
-               inType->instanceList = instance->next;
-               _SBRServiceInstanceFree( instance );
-       }
-       free( inType );
-}
-
-//===========================================================================================================================
-//     _SBRServiceInstanceCreate
-//===========================================================================================================================
-
-static OSStatus
-       _SBRServiceInstanceCreate(
-               const char *                    inName,
-               uint32_t                                inInterfaceIndex,
-               const char *                    inHostname,
-               uint16_t                                inPort,
-               const uint8_t *                 inTXTPtr,
-               size_t                                  inTXTLen,
-               uint64_t                                inDiscoverTimeUs,
-               uint64_t                                inResolveTimeUs,
-               SBRServiceInstance **   outInstance )
-{
-       OSStatus                                        err;
-       SBRServiceInstance *            obj;
-       
-       obj = (SBRServiceInstance *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       obj->name = strdup( inName );
-       require_action( obj->name, exit, err = kNoMemoryErr );
-       
-       if( inHostname )
-       {
-               obj->hostname = strdup( inHostname );
-               require_action( obj->hostname, exit, err = kNoMemoryErr );
-       }
-       if( inTXTLen > 0 )
-       {
-               obj->txtPtr = (uint8_t *) memdup( inTXTPtr, inTXTLen );
-               require_action( obj->txtPtr, exit, err = kNoMemoryErr );
-               obj->txtLen = inTXTLen;
-       }
-       obj->discoverTimeUs     = inDiscoverTimeUs;
-       obj->resolveTimeUs      = inResolveTimeUs;
-       obj->ifIndex            = inInterfaceIndex;
-       obj->port                       = inPort;
-       
-       *outInstance = obj;
-       obj = NULL;
-       err = kNoErr;
-       
-exit:
-       if( obj ) _SBRServiceInstanceFree( obj );
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBRServiceInstanceFree
-//===========================================================================================================================
-
-static void    _SBRServiceInstanceFree( SBRServiceInstance *inInstance )
-{
-       SBRIPAddress *          ipaddr;
-       
-       ForgetMem( &inInstance->name );
-       ForgetMem( &inInstance->hostname );
-       ForgetMem( &inInstance->txtPtr );
-       while( ( ipaddr = inInstance->ipaddrList ) != NULL )
-       {
-               inInstance->ipaddrList = ipaddr->next;
-               _SBRIPAddressFree( ipaddr );
-       }
-       free( inInstance );
-}
-
-//===========================================================================================================================
-//     _SBRIPAddressCreate
-//===========================================================================================================================
-
-static OSStatus
-       _SBRIPAddressCreate(
-               const struct sockaddr * inSockAddr,
-               uint64_t                                inResolveTimeUs,
-               SBRIPAddress **                 outIPAddress )
-{
-       OSStatus                        err;
-       SBRIPAddress *          obj;
-       
-       obj = (SBRIPAddress *) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = kNoMemoryErr );
-       
-       SockAddrCopy( inSockAddr, &obj->sip );
-       obj->resolveTimeUs = inResolveTimeUs;
-       
-       *outIPAddress = obj;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     _SBRIPAddressFree
-//===========================================================================================================================
-
-static void    _SBRIPAddressFree( SBRIPAddress *inIPAddress )
-{
-       free( inIPAddress );
-}
-
-//===========================================================================================================================
-//     SocketWriteAll
-//
-//     Note: This was copied from CoreUtils because the SocketWriteAll function is currently not exported in the framework.
-//===========================================================================================================================
-
-OSStatus       SocketWriteAll( SocketRef inSock, const void *inData, size_t inSize, int32_t inTimeoutSecs )
-{
-       OSStatus                        err;
-       const uint8_t *         src;
-       const uint8_t *         end;
-       fd_set                          writeSet;
-       struct timeval          timeout;
-       ssize_t                         n;
-       
-       FD_ZERO( &writeSet );
-       src = (const uint8_t *) inData;
-       end = src + inSize;
-       while( src < end )
-       {
-               FD_SET( inSock, &writeSet );
-               timeout.tv_sec  = inTimeoutSecs;
-               timeout.tv_usec = 0;
-               n = select( (int)( inSock + 1 ), NULL, &writeSet, NULL, &timeout );
-               if( n == 0 ) { err = kTimeoutErr; goto exit; }
-               err = map_socket_value_errno( inSock, n > 0, n );
-               require_noerr( err, exit );
-               
-               n = send( inSock, (char *) src, (size_t)( end - src ), 0 );
-               err = map_socket_value_errno( inSock, n >= 0, n );
-               if( err == EINTR ) continue;
-               require_noerr( err, exit );
-               
-               src += n;
-       }
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     ParseIPv4Address
-//
-//     Warning: "inBuffer" may be modified even in error cases.
-//
-//     Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-static OSStatus        ParseIPv4Address( const char *inStr, uint8_t inBuffer[ 4 ], const char **outStr )
-{
-       OSStatus                err;
-       uint8_t *               dst;
-       int                             segments;
-       int                             sawDigit;
-       int                             c;
-       int                             v;
-       
-       check( inBuffer );
-       check( outStr );
-       
-       dst              = inBuffer;
-       *dst     = 0;
-       sawDigit = 0;
-       segments = 0;
-       for( ; ( c = *inStr ) != '\0'; ++inStr )
-       {
-               if( isdigit_safe( c ) )
-               {
-                       v = ( *dst * 10 ) + ( c - '0' );
-                       require_action_quiet( v <= 255, exit, err = kRangeErr );
-                       *dst = (uint8_t) v;
-                       if( !sawDigit )
-                       {
-                               ++segments;
-                               require_action_quiet( segments <= 4, exit, err = kOverrunErr );
-                               sawDigit = 1;
-                       }
-               }
-               else if( ( c == '.' ) && sawDigit )
-               {
-                       require_action_quiet( segments < 4, exit, err = kMalformedErr );
-                       *++dst = 0;
-                       sawDigit = 0;
-               }
-               else
-               {
-                       break;
-               }
-       }
-       require_action_quiet( segments == 4, exit, err = kUnderrunErr );
-       
-       *outStr = inStr;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     StringToIPv4Address
-//
-//     Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-OSStatus
-       StringToIPv4Address( 
-               const char *                    inStr, 
-               StringToIPAddressFlags  inFlags, 
-               uint32_t *                              outIP, 
-               int *                                   outPort, 
-               uint32_t *                              outSubnet, 
-               uint32_t *                              outRouter, 
-               const char **                   outStr )
-{
-       OSStatus                        err;
-       uint8_t                         buf[ 4 ];
-       int                                     c;
-       uint32_t                        ip;
-       int                                     hasPort;
-       int                                     port;
-       int                                     hasPrefix;
-       int                                     prefix;
-       uint32_t                        subnetMask;
-       uint32_t                        router;
-       
-       require_action( inStr, exit, err = kParamErr );
-       
-       // Parse the address-only part of the address (e.g. "1.2.3.4").
-       
-       err = ParseIPv4Address( inStr, buf, &inStr );
-       require_noerr_quiet( err, exit );
-       ip = (uint32_t)( ( buf[ 0 ] << 24 ) | ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ] );
-       c = *inStr;
-       
-       // Parse the port (if any).
-       
-       hasPort = 0;
-       port    = 0;
-       if( c == ':' )
-       {
-               require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
-               while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
-               require_action_quiet( port <= 65535, exit, err = kRangeErr );
-               hasPort = 1;
-       }
-       
-       // Parse the prefix length (if any).
-       
-       hasPrefix  = 0;
-       prefix     = 0;
-       subnetMask = 0;
-       router     = 0;
-       if( c == '/' )
-       {
-               require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
-               while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
-               require_action_quiet( ( prefix >= 0 ) && ( prefix <= 32 ), exit, err = kRangeErr );
-               hasPrefix = 1;
-               
-               subnetMask = ( prefix > 0 ) ? ( UINT32_C( 0xFFFFFFFF ) << ( 32 - prefix ) ) : 0;
-               router     = ( ip & subnetMask ) | 1;
-       }
-       
-       // Return the results. Only fill in port/prefix/router results if the info was found to allow for defaults.
-       
-       if( outIP )                                      *outIP         = ip;
-       if( outPort   && hasPort )       *outPort       = port;
-       if( outSubnet && hasPrefix ) *outSubnet = subnetMask;
-       if( outRouter && hasPrefix ) *outRouter = router;
-       if( outStr )                             *outStr        = inStr;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     ParseIPv6Address
-//
-//     Note: Parsed according to the rules specified in RFC 3513.
-//     Warning: "inBuffer" may be modified even in error cases.
-//
-//     Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-static OSStatus        ParseIPv6Address( const char *inStr, int inAllowV4Mapped, uint8_t inBuffer[ 16 ], const char **outStr )
-{
-                                                                                                       // Table to map uppercase hex characters - '0' to their numeric values.
-                                                                                                       // 0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?  @  A   B   C   D   E   F
-       static const uint8_t            kASCIItoHexTable[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
-       OSStatus                                        err;
-       const char *                            ptr;
-       uint8_t *                                       dst;
-       uint8_t *                                       lim;
-       uint8_t *                                       colonPtr;
-       int                                                     c;
-       int                                                     sawDigit;
-       unsigned int                            v;
-       int                                                     i;
-       int                                                     n;
-       
-       // Pre-zero the address to simplify handling of compressed addresses (e.g. "::1").
-       
-       for( i = 0; i < 16; ++i ) inBuffer[ i ] = 0;
-       
-       // Special case leading :: (e.g. "::1") to simplify processing later.
-       
-       if( *inStr == ':' )
-       {
-               ++inStr;
-               require_action_quiet( *inStr == ':', exit, err = kMalformedErr );
-       }
-       
-       // Parse the address.
-       
-       ptr              = inStr;
-       dst              = inBuffer;
-       lim              = dst + 16;
-       colonPtr = NULL;
-       sawDigit = 0;
-       v                = 0;
-       while( ( ( c = *inStr++ ) != '\0' ) && ( c != '%' ) && ( c != '/' ) && ( c != ']' ) )
-       {
-               if(   ( c >= 'a' ) && ( c <= 'f' ) ) c -= ( 'a' - 'A' );
-               if( ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) ) )
-               {
-                       c -= '0';
-                       check( c < (int) countof( kASCIItoHexTable ) );
-                       v = ( v << 4 ) | kASCIItoHexTable[ c ];
-                       require_action_quiet( v <= 0xFFFF, exit, err = kRangeErr );
-                       sawDigit = 1;
-                       continue;
-               }
-               if( c == ':' )
-               {
-                       ptr = inStr;
-                       if( !sawDigit )
-                       {
-                               require_action_quiet( !colonPtr, exit, err = kMalformedErr );
-                               colonPtr = dst;
-                               continue;
-                       }
-                       require_action_quiet( *inStr != '\0', exit, err = kUnderrunErr );
-                       require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
-                       *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
-                       *dst++ = (uint8_t)(   v        & 0xFF );
-                       sawDigit = 0;
-                       v = 0;
-                       continue;
-               }
-               
-               // Handle IPv4-mapped/compatible addresses (e.g. ::FFFF:1.2.3.4).
-               
-               if( inAllowV4Mapped && ( c == '.' ) && ( ( dst + 4 ) <= lim ) )
-               {
-                       err = ParseIPv4Address( ptr, dst, &inStr );
-                       require_noerr_quiet( err, exit );
-                       dst += 4;
-                       sawDigit = 0;
-                       ++inStr; // Increment because the code below expects the end to be at "inStr - 1".
-               }
-               break;
-       }
-       if( sawDigit )
-       {
-               require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
-               *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
-               *dst++ = (uint8_t)(   v        & 0xFF );
-       }
-       check( dst <= lim );
-       if( colonPtr )
-       {
-               require_action_quiet( dst < lim, exit, err = kOverrunErr );
-               n = (int)( dst - colonPtr );
-               for( i = 1; i <= n; ++i )
-               {
-                       lim[ -i ] = colonPtr[ n - i ];
-                       colonPtr[ n - i ] = 0;
-               }
-               dst = lim;
-       }
-       require_action_quiet( dst == lim, exit, err = kUnderrunErr );
-       
-       *outStr = inStr - 1;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     ParseIPv6Scope
-//
-//     Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-static OSStatus        ParseIPv6Scope( const char *inStr, uint32_t *outScope, const char **outStr )
-{
-#if( TARGET_OS_POSIX )
-       OSStatus                        err;
-       char                            scopeStr[ 64 ];
-       char *                          dst;
-       char *                          lim;
-       int                                     c;
-       uint32_t                        scope;
-       const char *            ptr;
-       
-       // Copy into a local NULL-terminated string since that is what if_nametoindex expects.
-       
-       dst = scopeStr;
-       lim = dst + ( countof( scopeStr ) - 1 );
-       while( ( ( c = *inStr ) != '\0' ) && ( c != ':' ) && ( c != '/' ) && ( c != ']' ) && ( dst < lim ) )
-       {
-               *dst++ = *inStr++;
-       }
-       *dst = '\0';
-       check( dst <= lim );
-       
-       // First try to map as a name and if that fails, treat it as a numeric scope.
-       
-       scope = if_nametoindex( scopeStr );
-       if( scope == 0 )
-       {
-               for( ptr = scopeStr; ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr )
-               {
-                       scope = ( scope * 10 ) + ( ( (uint8_t) c ) - '0' );
-               }
-               require_action_quiet( c == '\0', exit, err = kMalformedErr );
-               require_action_quiet( ( ptr != scopeStr ) && ( ( (int)( ptr - scopeStr ) ) <= 10 ), exit, err = kMalformedErr );
-       }
-       
-       *outScope = scope;
-       *outStr   = inStr;
-       err = kNoErr;
-       
-exit:
-       return( err );
-#else
-       OSStatus                        err;
-       uint32_t                        scope;
-       const char *            start;
-       int                                     c;
-       
-       scope = 0;
-       for( start = inStr; ( ( c = *inStr ) >= '0' ) && ( c <= '9' ); ++inStr )
-       {
-               scope = ( scope * 10 ) + ( c - '0' );
-       }
-       require_action_quiet( ( inStr != start ) && ( ( (int)( inStr - start ) ) <= 10 ), exit, err = kMalformedErr );
-       
-       *outScope = scope;
-       *outStr   = inStr;
-       err = kNoErr;
-       
-exit:
-       return( err );
-#endif
-}
-
-//===========================================================================================================================
-//     StringToIPv6Address
-//
-//     Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
-//===========================================================================================================================
-
-OSStatus
-       StringToIPv6Address( 
-               const char *                    inStr, 
-               StringToIPAddressFlags  inFlags, 
-               uint8_t                                 outIPv6[ 16 ], 
-               uint32_t *                              outScope, 
-               int *                                   outPort, 
-               int *                                   outPrefix, 
-               const char **                   outStr )
-{
-       OSStatus                err;
-       uint8_t                 ipv6[ 16 ];
-       int                             c;
-       int                             hasScope;
-       uint32_t                scope;
-       int                             hasPort;
-       int                             port;
-       int                             hasPrefix;
-       int                             prefix;
-       int                             hasBracket;
-       int                             i;
-       
-       require_action( inStr, exit, err = kParamErr );
-       
-       if( *inStr == '[' ) ++inStr; // Skip a leading bracket for []-wrapped addresses (e.g. "[::1]:80").
-       
-       // Parse the address-only part of the address (e.g. "1::1").
-       
-       err = ParseIPv6Address( inStr, !( inFlags & kStringToIPAddressFlagsNoIPv4Mapped ), ipv6, &inStr );
-       require_noerr_quiet( err, exit );
-       c = *inStr;
-       
-       // Parse the scope, port, or prefix length.
-       
-       hasScope        = 0;
-       scope           = 0;
-       hasPort         = 0;
-       port            = 0;
-       hasPrefix       = 0;
-       prefix          = 0;
-       hasBracket      = 0;
-       for( ;; )
-       {
-               if( c == '%' )          // Scope (e.g. "%en0" or "%5")
-               {
-                       require_action_quiet( !hasScope, exit, err = kMalformedErr );
-                       require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoScope ), exit, err = kUnexpectedErr );
-                       ++inStr;
-                       err = ParseIPv6Scope( inStr, &scope, &inStr );
-                       require_noerr_quiet( err, exit );
-                       hasScope = 1;
-                       c = *inStr;
-               }
-               else if( c == ':' )     // Port (e.g. ":80")
-               {
-                       require_action_quiet( !hasPort, exit, err = kMalformedErr );
-                       require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
-                       while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
-                       require_action_quiet( port <= 65535, exit, err = kRangeErr );
-                       hasPort = 1;
-               }
-               else if( c == '/' )     // Prefix Length (e.g. "/64")
-               {
-                       require_action_quiet( !hasPrefix, exit, err = kMalformedErr );
-                       require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
-                       while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
-                       require_action_quiet( ( prefix >= 0 ) && ( prefix <= 128 ), exit, err = kRangeErr );
-                       hasPrefix = 1;
-               }
-               else if( c == ']' )
-               {
-                       require_action_quiet( !hasBracket, exit, err = kMalformedErr );
-                       hasBracket = 1;
-                       c = *( ++inStr );
-               }
-               else
-               {
-                       break;
-               }
-       }
-       
-       // Return the results. Only fill in scope/port/prefix results if the info was found to allow for defaults.
-       
-       if( outIPv6 )                            for( i = 0; i < 16; ++i ) outIPv6[ i ] = ipv6[ i ];
-       if( outScope  && hasScope )  *outScope  = scope;
-       if( outPort   && hasPort )   *outPort   = port;
-       if( outPrefix && hasPrefix ) *outPrefix = prefix;
-       if( outStr )                             *outStr        = inStr;
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     StringArray_Free
-//
-//     Note: This was copied from CoreUtils because the StringArray_Free function is currently not exported in the framework.
-//===========================================================================================================================
-
-void   StringArray_Free( char **inArray, size_t inCount )
-{
-       size_t          i;
-       
-       for( i = 0; i < inCount; ++i )
-       {
-               free( inArray[ i ] );
-       }
-       if( inCount > 0 ) free( inArray );
-}
-
-//===========================================================================================================================
-//     ParseQuotedEscapedString
-//
-//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-Boolean
-       ParseQuotedEscapedString( 
-               const char *    inSrc, 
-               const char *    inEnd, 
-               const char *    inDelimiters, 
-               char *                  inBuf, 
-               size_t                  inMaxLen, 
-               size_t *                outCopiedLen, 
-               size_t *                outTotalLen, 
-               const char **   outSrc )
-{
-       const unsigned char *           src;
-       const unsigned char *           end;
-       unsigned char *                         dst;
-       unsigned char *                         lim;
-       unsigned char                           c;
-       unsigned char                           c2;
-       size_t                                          totalLen;
-       Boolean                                         singleQuote;
-       Boolean                                         doubleQuote;
-       
-       if( inEnd == NULL ) inEnd = inSrc + strlen( inSrc );
-       src = (const unsigned char *) inSrc;
-       end = (const unsigned char *) inEnd;
-       dst = (unsigned char *) inBuf;
-       lim = dst + inMaxLen;
-       while( ( src < end ) && isspace_safe( *src ) ) ++src; // Skip leading spaces.
-       if( src >= end ) return( false );
-       
-       // Parse each argument from the string.
-       //
-       // See <http://resources.mpi-inf.mpg.de/departments/rg1/teaching/unixffb-ss98/quoting-guide.html> for details.
-       
-       totalLen = 0;
-       singleQuote = false;
-       doubleQuote = false;
-       while( src < end )
-       {
-               c = *src++;
-               if( singleQuote )
-               {
-                       // Single quotes protect everything (even backslashes, newlines, etc.) except single quotes.
-                       
-                       if( c == '\'' )
-                       {
-                               singleQuote = false;
-                               continue;
-                       }
-               }
-               else if( doubleQuote )
-               {
-                       // Double quotes protect everything except double quotes and backslashes. A backslash can be 
-                       // used to protect " or \ within double quotes. A backslash-newline pair disappears completely.
-                       // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
-                       // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
-                       // A backslash that does not precede ", \, x, X, or a newline is taken literally.
-                       
-                       if( c == '"' )
-                       {
-                               doubleQuote = false;
-                               continue;
-                       }
-                       else if( c == '\\' )
-                       {
-                               if( src < end )
-                               {
-                                       c2 = *src;
-                                       if( ( c2 == '"' ) || ( c2 == '\\' ) )
-                                       {
-                                               ++src;
-                                               c = c2;
-                                       }
-                                       else if( c2 == '\n' )
-                                       {
-                                               ++src;
-                                               continue;
-                                       }
-                                       else if( ( c2 == 'x' ) || ( c2 == 'X' ) )
-                                       {
-                                               ++src;
-                                               c = c2;
-                                               if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
-                                               {
-                                                       c = HexPairToByte( src );
-                                                       src += 2;
-                                               }
-                                       }
-                                       else if( isoctal_safe( c2 ) )
-                                       {
-                                               if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
-                                               {
-                                                       c = OctalTripleToByte( src );
-                                                       src += 3;
-                                               }
-                                       }
-                               }
-                       }
-               }
-               else if( strchr( inDelimiters, c ) )
-               {
-                       break;
-               }
-               else if( c == '\\' )
-               {
-                       // A backslash protects the next character, except a newline, x, X and 2 hex bytes or 3 octal bytes. 
-                       // A backslash followed by a newline disappears completely.
-                       // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
-                       // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
-                       
-                       if( src < end )
-                       {
-                               c = *src;
-                               if( c == '\n' )
-                               {
-                                       ++src;
-                                       continue;
-                               }
-                               else if( ( c == 'x' ) || ( c == 'X' ) )
-                               {
-                                       ++src;
-                                       if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
-                                       {
-                                               c = HexPairToByte( src );
-                                               src += 2;
-                                       }
-                               }
-                               else if( isoctal_safe( c ) )
-                               {
-                                       if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
-                                       {
-                                               c = OctalTripleToByte( src );
-                                               src += 3;
-                                       }
-                                       else
-                                       {
-                                               ++src;
-                                       }
-                               }
-                               else
-                               {
-                                       ++src;
-                               }
-                       }
-               }
-               else if( c == '\'' )
-               {
-                       singleQuote = true;
-                       continue;
-               }
-               else if( c == '"' )
-               {
-                       doubleQuote = true;
-                       continue;
-               }
-               
-               if( dst < lim )
-               {
-                       if( inBuf ) *dst = c;
-                       ++dst;
-               }
-               ++totalLen;
-       }
-       
-       if( outCopiedLen )      *outCopiedLen   = (size_t)( dst - ( (unsigned char *) inBuf ) );
-       if( outTotalLen )       *outTotalLen    = totalLen;
-       if( outSrc )            *outSrc                 = (const char *) src;
-       return( true );
-}
-
-//===========================================================================================================================
-//     _ServerSocketOpenEx2
-//
-//     Note: Based on ServerSocketOpenEx() from CoreUtils. Added parameter to not use SO_REUSEPORT.
-//===========================================================================================================================
-
-static OSStatus
-       _ServerSocketOpenEx2( 
-               int                             inFamily, 
-               int                             inType, 
-               int                             inProtocol, 
-               const void *    inAddr, 
-               int                             inPort, 
-               int *                   outPort, 
-               int                             inRcvBufSize, 
-               Boolean                 inNoPortReuse,
-               SocketRef *             outSock )
-{
-       OSStatus                err;
-       int                             port;
-       SocketRef               sock;
-       int                             name;
-       int                             option;
-       sockaddr_ip             sip;
-       socklen_t               len;
-       
-       port = ( inPort < 0 ) ? -inPort : inPort; // Negated port number means "try this port, but allow dynamic".
-       
-       sock = socket( inFamily, inType, inProtocol );
-       err = map_socket_creation_errno( sock );
-       require_noerr_quiet( err, exit );
-       
-#if( defined( SO_NOSIGPIPE ) )
-       setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, (socklen_t) sizeof( int ) );
-#endif
-       
-       err = SocketMakeNonBlocking( sock );
-       require_noerr( err, exit );
-       
-       // Set receive buffer size. This has to be done on the listening socket *before* listen is called because
-       // accept does not return until after the window scale option is exchanged during the 3-way handshake. 
-       // Since accept returns a new socket, the only way to use a larger window scale option is to set the buffer
-       // size on the listening socket since SO_RCVBUF is inherited by the accepted socket. See UNPv1e3 Section 7.5.
-       
-       err = SocketSetBufferSize( sock, SO_RCVBUF, inRcvBufSize );
-       check_noerr( err );
-       
-       // Allow port or address reuse because we may bind separate IPv4 and IPv6 sockets to the same port.
-       
-       if( ( inType != SOCK_DGRAM ) || !inNoPortReuse )
-       {
-               option = 1;
-               name = ( inType == SOCK_DGRAM ) ? SO_REUSEPORT : SO_REUSEADDR;
-               err = setsockopt( sock, SOL_SOCKET, name, (char *) &option, (socklen_t) sizeof( option ) );
-               err = map_socket_noerr_errno( sock, err );
-               require_noerr( err, exit );
-       }
-       
-       if( inFamily == AF_INET )
-       {
-               // Bind to the port. If it fails, retry with a dynamic port.
-               
-               memset( &sip.v4, 0, sizeof( sip.v4 ) );
-               SIN_LEN_SET( &sip.v4 );
-               sip.v4.sin_family               = AF_INET;
-               sip.v4.sin_port                 = htons( (uint16_t) port );
-               sip.v4.sin_addr.s_addr  = inAddr ? *( (const uint32_t *) inAddr ) : htonl( INADDR_ANY );
-               err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
-               err = map_socket_noerr_errno( sock, err );
-               if( err && ( inPort < 0 ) )
-               {
-                       sip.v4.sin_port = 0;
-                       err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
-                       err = map_socket_noerr_errno( sock, err );
-               }
-               require_noerr( err, exit );
-       }
-#if( defined( AF_INET6 ) )
-       else if( inFamily == AF_INET6 )
-       {
-               // Restrict this socket to IPv6 only because we're going to use a separate socket for IPv4.
-               
-               option = 1;
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, (socklen_t) sizeof( option ) );
-               err = map_socket_noerr_errno( sock, err );
-               require_noerr( err, exit );
-               
-               // Bind to the port. If it fails, retry with a dynamic port.
-               
-               memset( &sip.v6, 0, sizeof( sip.v6 ) );
-               SIN6_LEN_SET( &sip.v6 );
-               sip.v6.sin6_family      = AF_INET6;
-               sip.v6.sin6_port        = htons( (uint16_t) port );
-               sip.v6.sin6_addr        = inAddr ? *( (const struct in6_addr *) inAddr ) : in6addr_any; 
-               err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
-               err = map_socket_noerr_errno( sock, err );
-               if( err && ( inPort < 0 ) )
-               {
-                       sip.v6.sin6_port = 0;
-                       err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
-                       err = map_socket_noerr_errno( sock, err );
-               }
-               require_noerr( err, exit );
-       }
-#endif
-       else
-       {
-               dlogassert( "Unsupported family: %d", inFamily );
-               err = kUnsupportedErr;
-               goto exit;
-       }
-       
-       if( inType == SOCK_STREAM )
-       {
-               err = listen( sock, SOMAXCONN );
-               err = map_socket_noerr_errno( sock, err );
-               if( err )
-               {
-                       err = listen( sock, 5 );
-                       err = map_socket_noerr_errno( sock, err );
-                       require_noerr( err, exit );
-               }
-       }
-       
-       if( outPort )
-       {
-               len = (socklen_t) sizeof( sip );
-               err = getsockname( sock, &sip.sa, &len );
-               err = map_socket_noerr_errno( sock, err );
-               require_noerr( err, exit );
-               
-               *outPort = SockAddrGetPort( &sip );
-       }
-       *outSock = sock;
-       sock = kInvalidSocketRef;
-       
-exit:
-       ForgetSocket( &sock );
-       return( err );
-}
-
-//===========================================================================================================================
-//     memdup
-//
-//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-void * memdup( const void *inPtr, size_t inLen )
-{
-       void *          mem;
-       
-       mem = malloc( ( inLen > 0 ) ? inLen : 1 ); // If inLen is 0, use 1 since malloc( 0 ) is not well defined.
-       require( mem, exit );
-       if( inLen > 0 ) memcpy( mem, inPtr, inLen );
-       
-exit:
-       return( mem );
-}
-
-#if( !TARGET_OS_WINDOWS )
-//===========================================================================================================================
-//     memicmp
-//
-//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-int    memicmp( const void *inP1, const void *inP2, size_t inLen )
-{
-       const unsigned char *           p1;
-       const unsigned char *           e1;
-       const unsigned char *           p2;
-       int                                                     c1;
-       int                                                     c2;
-       
-       p1 = (const unsigned char *) inP1;
-       e1 = p1 + inLen;
-       p2 = (const unsigned char *) inP2;
-       while( p1 < e1 )
-       {
-               c1 = *p1++;
-               c2 = *p2++;
-               c1 = tolower( c1 );
-               c2 = tolower( c2 );
-               if( c1 < c2 ) return( -1 );
-               if( c1 > c2 ) return(  1 );
-       }
-       return( 0 );
-}
-#endif
-
-//===========================================================================================================================
-//     FNV1
-//
-//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
-//===========================================================================================================================
-
-uint32_t       FNV1( const void *inData, size_t inSize )
-{
-       const uint8_t *                         src = (const uint8_t *) inData;
-       const uint8_t * const           end = src + inSize;
-       uint32_t                                        hash;
-       
-       hash = 0x811c9dc5U;
-       while( src != end )
-       {
-               hash *= 0x01000193;
-               hash ^= *src++;
-       }
-       return( hash );
-}
diff --git a/Clients/dnssdutil/DNSMessage.c b/Clients/dnssdutil/DNSMessage.c
new file mode 100644 (file)
index 0000000..68561ee
--- /dev/null
@@ -0,0 +1,444 @@
+/*
+       Copyright (c) 2016-2019 Apple Inc. All rights reserved.
+*/
+
+#include "DNSMessage.h"
+
+//===========================================================================================================================
+
+#define IsCompressionByte( X )         ( ( ( X ) & 0xC0 ) == 0xC0 )
+
+OSStatus
+       DNSMessageExtractDomainName(
+               const uint8_t *         inMsgPtr,
+               size_t                          inMsgLen,
+               const uint8_t *         inPtr,
+               uint8_t                         outName[ kDomainNameLengthMax ],
+               const uint8_t **        outPtr )
+{
+       OSStatus                                        err;
+       const uint8_t *                         label;
+       uint8_t                                         labelLen;
+       const uint8_t *                         nextLabel;
+       const uint8_t * const           msgEnd  = inMsgPtr + inMsgLen;
+       uint8_t *                                       dst             = outName;
+       const uint8_t * const           dstLim  = outName ? ( outName + kDomainNameLengthMax ) : NULL;
+       const uint8_t *                         nameEnd = NULL;
+       
+       require_action_quiet( ( inPtr >= inMsgPtr ) && ( inPtr < msgEnd ), exit, err = kRangeErr );
+       
+       for( label = inPtr; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
+       {
+               if( labelLen <= kDomainLabelLengthMax )
+               {
+                       nextLabel = label + 1 + labelLen;
+                       require_action_quiet( nextLabel < msgEnd, exit, err = kUnderrunErr );
+                       if( dst )
+                       {
+                               require_action_quiet( ( dstLim - dst ) > ( 1 + labelLen ), exit, err = kOverrunErr );
+                               memcpy( dst, label, 1 + labelLen );
+                               dst += ( 1 + labelLen );
+                       }
+               }
+               else if( IsCompressionByte( labelLen ) )
+               {
+                       uint16_t                offset;
+                       
+                       require_action_quiet( ( msgEnd - label ) >= 2, exit, err = kUnderrunErr );
+                       if( !nameEnd )
+                       {
+                               nameEnd = label + 2;
+                               if( !dst ) break;
+                       }
+                       offset = (uint16_t)( ( ( label[ 0 ] & 0x3F ) << 8 ) | label[ 1 ] );
+                       nextLabel = inMsgPtr + offset;
+                       require_action_quiet( nextLabel < msgEnd, exit, err = kUnderrunErr );
+                       require_action_quiet( !IsCompressionByte( nextLabel[ 0 ] ), exit, err = kMalformedErr );
+               }
+               else
+               {
+                       err = kMalformedErr;
+                       goto exit;
+               }
+       }
+       
+       if( dst ) *dst = 0;
+       if( !nameEnd ) nameEnd = label + 1;
+       
+       if( outPtr ) *outPtr = nameEnd;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+       DNSMessageExtractDomainNameString(
+               const void *            inMsgPtr,
+               size_t                          inMsgLen,
+               const void *            inPtr,
+               char                            inBuf[ kDNSServiceMaxDomainName ],
+               const uint8_t **        outPtr )
+{
+       OSStatus                        err;
+       const uint8_t *         nextPtr;
+       uint8_t                         domainName[ kDomainNameLengthMax ];
+       
+       err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, domainName, &nextPtr );
+       require_noerr_quiet( err, exit );
+       
+       err = DomainNameToString( domainName, NULL, inBuf, NULL );
+       require_noerr_quiet( err, exit );
+       
+       if( outPtr ) *outPtr = nextPtr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+       DNSMessageExtractQuestion(
+               const uint8_t *         inMsgPtr,
+               size_t                          inMsgLen,
+               const uint8_t *         inPtr,
+               uint8_t                         outName[ kDomainNameLengthMax ],
+               uint16_t *                      outType,
+               uint16_t *                      outClass,
+               const uint8_t **        outPtr )
+{
+       OSStatus                                                                err;
+       const uint8_t * const                                   msgEnd = &inMsgPtr[ inMsgLen ];
+       const uint8_t *                                                 ptr;
+       const dns_fixed_fields_question *               fields;
+       
+       err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, outName, &ptr );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( (size_t)( msgEnd - ptr ) >= sizeof( dns_fixed_fields_question ), exit, err = kUnderrunErr );
+       
+       fields = (const dns_fixed_fields_question *) ptr;
+       if( outType )  *outType  = dns_fixed_fields_question_get_type( fields );
+       if( outClass ) *outClass = dns_fixed_fields_question_get_class( fields );
+       if( outPtr )   *outPtr   = (const uint8_t *) &fields[ 1 ];
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+       DNSMessageExtractRecord(
+               const uint8_t *         inMsgPtr,
+               size_t                          inMsgLen,
+               const uint8_t *         inPtr,
+               uint8_t                         outName[ kDomainNameLengthMax ],
+               uint16_t *                      outType,
+               uint16_t *                      outClass,
+               uint32_t *                      outTTL,
+               const uint8_t **        outRDataPtr,
+               size_t *                        outRDataLen,
+               const uint8_t **        outPtr )
+{
+       OSStatus                                                        err;
+       const uint8_t * const                           msgEnd = inMsgPtr + inMsgLen;
+       const uint8_t *                                         ptr;
+       const dns_fixed_fields_record *         fields;
+       const uint8_t *                                         rdata;
+       size_t                                                          rdLength;
+       
+       err = DNSMessageExtractDomainName( inMsgPtr, inMsgLen, inPtr, outName, &ptr );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( (size_t)( msgEnd - ptr ) >= sizeof( *fields ), exit, err = kUnderrunErr );
+       
+       fields  = (const dns_fixed_fields_record *) ptr;
+       rdata   = ptr + sizeof( *fields );
+       
+       rdLength = dns_fixed_fields_record_get_rdlength( fields );
+       require_action_quiet( (size_t)( msgEnd - rdata ) >= rdLength , exit, err = kUnderrunErr );
+       
+       if( outType )           *outType                = dns_fixed_fields_record_get_type( fields );
+       if( outClass )          *outClass               = dns_fixed_fields_record_get_class( fields );
+       if( outTTL )            *outTTL                 = dns_fixed_fields_record_get_ttl( fields );
+       if( outRDataPtr )       *outRDataPtr    = rdata;
+       if( outRDataLen )       *outRDataLen    = rdLength;
+       if( outPtr )            *outPtr                 = &rdata[ rdLength ];
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus       DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr )
+{
+       OSStatus                                err;
+       unsigned int                    questionCount, i;
+       const DNSHeader *               hdr;
+       const uint8_t *                 ptr;
+       
+       require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+       
+       hdr = (DNSHeader *) inMsgPtr;
+       questionCount = DNSHeaderGetQuestionCount( hdr );
+       
+       ptr = (const uint8_t *) &hdr[ 1 ];
+       for( i = 0; i < questionCount; ++i )
+       {
+               err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, NULL, NULL, NULL, &ptr );
+               require_noerr_quiet( err, exit );
+       }
+       
+       if( outPtr ) *outPtr = ptr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+       DNSMessageWriteQuery(
+               uint16_t                inMsgID,
+               uint16_t                inFlags,
+               const uint8_t * inQName,
+               uint16_t                inQType,
+               uint16_t                inQClass,
+               uint8_t                 outMsg[ STATIC_PARAM kDNSQueryMessageMaxLen ],
+               size_t *                outLen )
+{
+       OSStatus                                err;
+       DNSHeader * const               hdr = (DNSHeader *) outMsg;
+       uint8_t *                               ptr;
+       size_t                                  qnameLen;
+       size_t                                  msgLen;
+       
+       memset( hdr, 0, sizeof( *hdr ) );
+       DNSHeaderSetID( hdr, inMsgID );
+       DNSHeaderSetFlags( hdr, inFlags );
+       DNSHeaderSetQuestionCount( hdr, 1 );
+       
+       qnameLen = DomainNameLength( inQName );
+       require_action_quiet( qnameLen <= kDomainNameLengthMax, exit, err = kSizeErr );
+       
+       ptr = (uint8_t *) &hdr[ 1 ];
+       memcpy( ptr, inQName, qnameLen );
+       ptr += qnameLen;
+       
+       dns_fixed_fields_question_init( (dns_fixed_fields_question *) ptr, inQType, inQClass );
+       ptr += sizeof( dns_fixed_fields_question );
+       
+       msgLen = (size_t)( ptr - outMsg );
+       
+       if( outLen ) *outLen = msgLen;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus
+       DomainNameAppendString(
+               uint8_t                 inDomainName[ STATIC_PARAM kDomainNameLengthMax ],
+               const char *    inString,
+               uint8_t **              outEnd )
+{
+       OSStatus                                        err;
+       const char *                            src;
+       uint8_t *                                       root;
+       const uint8_t * const           nameLim = inDomainName + kDomainNameLengthMax;
+       
+       for( root = inDomainName; ( root < nameLim ) && *root; root += ( 1 + *root ) ) {}
+       require_action_quiet( root < nameLim, exit, err = kMalformedErr );
+       
+       // If the string is a single dot, denoting the root domain, then there are no non-empty labels.
+       
+       src = inString;
+       if( ( src[ 0 ] == '.' ) && ( src[ 1 ] == '\0' ) ) ++src;
+       while( *src )
+       {
+               uint8_t * const                         label           = root;
+               const uint8_t * const           labelLim        = Min( &label[ 1 + kDomainLabelLengthMax ], nameLim - 1 );
+               uint8_t *                                       dst;
+               int                                                     c;
+               size_t                                          labelLen;
+               
+               dst = &label[ 1 ];
+               while( *src && ( ( c = *src++ ) != '.' ) )
+               {
+                       if( c == '\\' )
+                       {
+                               require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
+                               c = *src++;
+                               if( isdigit_safe( c ) && isdigit_safe( src[ 0 ] ) && isdigit_safe( src[ 1 ] ) )
+                               {
+                                       const int               decimal = ( ( c - '0' ) * 100 ) + ( ( src[ 0 ] - '0' ) * 10 ) + ( src[ 1 ] - '0' );
+                                       
+                                       if( decimal <= 255 )
+                                       {
+                                               c = decimal;
+                                               src += 2;
+                                       }
+                               }
+                       }
+                       require_action_quiet( dst < labelLim, exit, err = kOverrunErr );
+                       *dst++ = (uint8_t) c;
+               }
+               
+               labelLen = (size_t)( dst - &label[ 1 ] );
+               require_action_quiet( labelLen > 0, exit, err = kMalformedErr );
+               
+               label[ 0 ] = (uint8_t) labelLen;
+               root = dst;
+               *root = 0;
+       }
+       
+       if( outEnd ) *outEnd = root + 1;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+OSStatus       DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen )
+{
+       OSStatus                        err;
+       uint8_t *                       namePtr;
+       const size_t            nameLen = DomainNameLength( inName );
+       
+       namePtr = (uint8_t *) malloc( nameLen );
+       require_action_quiet( namePtr, exit, err = kNoMemoryErr );
+       
+       if( inLower )
+       {
+               const uint8_t *         src;
+               uint8_t *                       dst;
+               unsigned int            len;
+               
+               src = inName;
+               dst = namePtr;
+               while( ( len = *src ) != 0 )
+               {
+                       *dst++ = *src++;
+                       while( len-- > 0 )
+                       {
+                               const int c = *src++;
+                               *dst++ = (uint8_t) tolower_safe( c );
+                       }
+               }
+               *dst = 0;
+       }
+       else
+       {
+               memcpy( namePtr, inName, nameLen );
+       }
+       
+       *outNamePtr = namePtr;
+       if( outNameLen ) *outNameLen = nameLen;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+Boolean        DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 )
+{
+       const uint8_t *         p1 = inName1;
+       const uint8_t *         p2 = inName2;
+       if( p1 == p2 ) return( true );
+       for( ;; )
+       {
+               int                     len1 = *p1++;
+               const int       len2 = *p2++;
+               if( len1 != len2 )      return( false );
+               if( len1 == 0 )         return( true );
+               while( len1-- > 0 )
+               {
+                       const int               c1 = *p1++;
+                       const int               c2 = *p2++;
+                       if( tolower_safe( c1 ) != tolower_safe( c2 ) ) return( false );
+               }
+       }
+}
+
+//===========================================================================================================================
+
+OSStatus
+       DomainNameFromString(
+               uint8_t                 outName[ STATIC_PARAM kDomainNameLengthMax ],
+               const char *    inString,
+               uint8_t **              outEnd )
+{
+       outName[ 0 ] = 0;
+       return( DomainNameAppendString( outName, inString, outEnd ) );
+}
+
+//===========================================================================================================================
+
+OSStatus
+       DomainNameToString(
+               const uint8_t *         inName,
+               const uint8_t *         inLimit,
+               char                            outString[ STATIC_PARAM kDNSServiceMaxDomainName ],
+               const uint8_t **        outPtr )
+{
+       OSStatus                        err;
+       const uint8_t *         label;
+       uint8_t                         labelLen;
+       const uint8_t *         nextLabel;
+       char *                          dst;
+       const uint8_t *         src;
+       
+       require_action_quiet( !inLimit || ( inName < inLimit ), exit, err = kUnderrunErr );
+       
+       // Convert each label up until the root label, i.e., the zero-length label.
+       
+       dst = outString;
+       for( label = inName; ( labelLen = label[ 0 ] ) != 0; label = nextLabel )
+       {
+               require_action_quiet( labelLen <= kDomainLabelLengthMax, exit, err = kMalformedErr );
+               
+               nextLabel = &label[ 1 + labelLen ];
+               require_action_quiet( ( nextLabel - inName ) < kDomainNameLengthMax, exit, err = kMalformedErr );
+               require_action_quiet( !inLimit || ( nextLabel < inLimit ), exit, err = kUnderrunErr );
+               
+               for( src = &label[ 1 ]; src < nextLabel; ++src )
+               {
+                       // Only allow 7-bit ASCII characters.
+                       if( ( *src >= 32 ) && ( *src <= 126 ) )
+                       {
+                               if( ( *src == '.' ) || ( *src == '\\' ) ||  ( *src == ' ' ) ) *dst++ = '\\';
+                               *dst++ = (char) *src;
+                       }
+                       else
+                       {
+                               *dst++ = '\\';
+                               *dst++ = '0' + (   *src / 100 );
+                               *dst++ = '0' + ( ( *src /  10 ) % 10 );
+                               *dst++ = '0' + (   *src         % 10 );
+                       }
+               }
+               *dst++ = '.';
+       }
+       
+       // At this point, label points to the root label.
+       // If the root label was the only label, then write a dot for it.
+       
+       if( label == inName ) *dst++ = '.';
+       *dst = '\0';
+       if( outPtr ) *outPtr = label + 1;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
diff --git a/Clients/dnssdutil/DNSMessage.h b/Clients/dnssdutil/DNSMessage.h
new file mode 100644 (file)
index 0000000..56ddeee
--- /dev/null
@@ -0,0 +1,461 @@
+/*
+       Copyright (c) 2016-2019 Apple Inc. All rights reserved.
+*/
+
+#ifndef        __DNSMessage_h
+#define        __DNSMessage_h
+
+#include <CoreUtils/CoreUtils.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @group          DNS domain name size limits
+       
+       @discussion See <https://tools.ietf.org/html/rfc1035#section-2.3.4>.
+*/
+#define kDomainLabelLengthMax          63
+#define kDomainNameLengthMax           256     // For compatibility with mDNS. See <https://tools.ietf.org/html/rfc6762#appendix-C>.
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @group          DNS message header
+*/
+typedef struct
+{
+       uint8_t         id[ 2 ];
+       uint8_t         flags[ 2 ];
+       uint8_t         questionCount[ 2 ];
+       uint8_t         answerCount[ 2 ];
+       uint8_t         authorityCount[ 2 ];
+       uint8_t         additionalCount[ 2 ];
+       
+}      DNSHeader;
+
+#define kDNSHeaderLength               12
+check_compile_time( sizeof( DNSHeader ) == kDNSHeaderLength );
+
+#define DNSHeaderGetID( HDR )                                  ReadBig16( ( HDR )->id )
+#define DNSHeaderGetFlags( HDR )                               ReadBig16( ( HDR )->flags )
+#define DNSHeaderGetQuestionCount( HDR )               ReadBig16( ( HDR )->questionCount )
+#define DNSHeaderGetAnswerCount( HDR )                 ReadBig16( ( HDR )->answerCount )
+#define DNSHeaderGetAuthorityCount( HDR )              ReadBig16( ( HDR )->authorityCount )
+#define DNSHeaderGetAdditionalCount( HDR )             ReadBig16( ( HDR )->additionalCount )
+
+#define DNSHeaderSetID( HDR, X )                                       WriteBig16( ( HDR )->id, (X) )
+#define DNSHeaderSetFlags( HDR, X )                                    WriteBig16( ( HDR )->flags, (X) )
+#define DNSHeaderSetQuestionCount( HDR, X )                    WriteBig16( ( HDR )->questionCount, (X) )
+#define DNSHeaderSetAnswerCount( HDR, X )                      WriteBig16( ( HDR )->answerCount, (X) )
+#define DNSHeaderSetAuthorityCount( HDR, X )           WriteBig16( ( HDR )->authorityCount, (X) )
+#define DNSHeaderSetAdditionalCount( HDR, X )          WriteBig16( ( HDR )->additionalCount, (X) )
+
+// Single-bit DNS header fields
+
+#define kDNSHeaderFlag_Response                                        ( 1U << 15 )    // QR (bit 15), Query (0)/Response (1)
+#define kDNSHeaderFlag_AuthAnswer                              ( 1U << 10 )    // AA (bit 10), Authoritative Answer
+#define kDNSHeaderFlag_Truncation                              ( 1U <<  9 )    // TC (bit  9), TrunCation
+#define kDNSHeaderFlag_RecursionDesired                        ( 1U <<  8 )    // RD (bit  8), Recursion Desired
+#define kDNSHeaderFlag_RecursionAvailable              ( 1U <<  7 )    // RA (bit  7), Recursion Available
+#define kDNSHeaderFlag_Z                                               ( 1U <<  6 )    //  Z (bit  6), Reserved (must be zero)
+#define kDNSHeaderFlag_AuthenticData                   ( 1U <<  5 )    // AD (bit  5), Authentic Data (RFC 2535, Section 6)
+#define kDNSHeaderFlag_CheckingDisabled                        ( 1U <<  4 )    // CD (bit  4), Checking Disabled (RFC 2535, Section 6)
+
+// OPCODE (bits 14-11), Operation Code
+
+#define DNSFlagsGetOpCode( FLAGS )             ( ( (FLAGS) >> 11 ) & 0x0FU )
+#define DNSFlagsSetOpCode( FLAGS, OPCODE ) \
+       do { (FLAGS) = ( (FLAGS) & ~0x7800U ) | ( ( (OPCODE) & 0x0FU ) << 11 ); } while( 0 )
+
+#define kDNSOpCode_Query                       0       // QUERY (standard query)
+#define kDNSOpCode_InverseQuery                1       // IQUERY (inverse query)
+#define kDNSOpCode_Status                      2       // STATUS
+#define kDNSOpCode_Notify                      4       // NOTIFY
+#define kDNSOpCode_Update                      5       // UPDATE
+
+// RCODE (bits 3-0), Response Code
+
+#define DNSFlagsGetRCode( FLAGS )              ( (FLAGS) & 0x0FU )
+#define DNSFlagsSetRCode( FLAGS, RCODE ) \
+       do { (FLAGS) = ( (FLAGS) & ~0x000FU ) | ( (RCODE) & 0x0FU ); } while( 0 )
+
+#define kDNSRCode_NoError                              0
+#define kDNSRCode_FormatError                  1
+#define kDNSRCode_ServerFailure                        2
+#define kDNSRCode_NXDomain                             3
+#define kDNSRCode_NotImplemented               4
+#define kDNSRCode_Refused                              5
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @group          Misc. DNS message data structures
+*/
+
+#define dns_fixed_fields_define_accessors( TYPE, FIELD, BIT_SIZE )     \
+       STATIC_INLINE uint ## BIT_SIZE ##_t                                                             \
+               dns_fixed_fields_ ## TYPE ## _get_ ## FIELD (                           \
+                       const dns_fixed_fields_ ## TYPE *       inFields )                      \
+       {                                                                                                                               \
+               return ReadBig ## BIT_SIZE ( inFields->FIELD );                         \
+       }                                                                                                                               \
+                                                                                                                                       \
+       STATIC_INLINE void                                                                                              \
+               dns_fixed_fields_ ## TYPE ## _set_ ## FIELD (                           \
+                       dns_fixed_fields_ ## TYPE *     inFields,                                       \
+                       uint ## BIT_SIZE ## _t          inValue )                                       \
+       {                                                                                                                               \
+               WriteBig ## BIT_SIZE ( inFields->FIELD, inValue );                      \
+       }                                                                                                                               \
+       check_compile_time( ( sizeof_field( dns_fixed_fields_ ## TYPE, FIELD ) * 8 ) == (BIT_SIZE) )
+
+// DNS question fixed-length fields (see <https://tools.ietf.org/html/rfc1035#section-4.1.2>)
+
+typedef struct
+{
+       uint8_t         type[ 2 ];
+       uint8_t         class[ 2 ];
+       
+}      dns_fixed_fields_question;
+
+check_compile_time( sizeof( dns_fixed_fields_question ) == 4 );
+
+dns_fixed_fields_define_accessors( question, type,  16 );
+dns_fixed_fields_define_accessors( question, class, 16 );
+
+STATIC_INLINE void
+       dns_fixed_fields_question_init(
+               dns_fixed_fields_question *     inFields,
+               uint16_t                                        inQType,
+               uint16_t                                        inQClass )
+{
+       dns_fixed_fields_question_set_type( inFields, inQType );
+       dns_fixed_fields_question_set_class( inFields, inQClass );
+}
+
+// DNS resource record fixed-length fields (see <https://tools.ietf.org/html/rfc1035#section-4.1.3>)
+
+typedef struct
+{
+       uint8_t         type[ 2 ];
+       uint8_t         class[ 2 ];
+       uint8_t         ttl[ 4 ];
+       uint8_t         rdlength[ 2 ];
+       
+}      dns_fixed_fields_record;
+
+check_compile_time( sizeof( dns_fixed_fields_record ) == 10 );
+
+dns_fixed_fields_define_accessors( record, type,     16 );
+dns_fixed_fields_define_accessors( record, class,    16 );
+dns_fixed_fields_define_accessors( record, ttl,      32 );
+dns_fixed_fields_define_accessors( record, rdlength, 16 );
+
+STATIC_INLINE void
+       dns_fixed_fields_record_init(
+               dns_fixed_fields_record *       inFields,
+               uint16_t                                        inType,
+               uint16_t                                        inClass,
+               uint32_t                                        inTTL,
+               uint16_t                                        inRDLength )
+{
+       dns_fixed_fields_record_set_type( inFields, inType );
+       dns_fixed_fields_record_set_class( inFields, inClass );
+       dns_fixed_fields_record_set_ttl( inFields, inTTL );
+       dns_fixed_fields_record_set_rdlength( inFields, inRDLength );
+}
+
+// DNS SRV record data fixed-length fields (see <https://tools.ietf.org/html/rfc2782>)
+
+typedef struct
+{
+       uint8_t         priority[ 2 ];
+       uint8_t         weight[ 2 ];
+       uint8_t         port[ 2 ];
+       
+}      dns_fixed_fields_srv;
+
+check_compile_time( sizeof( dns_fixed_fields_srv ) == 6 );
+
+dns_fixed_fields_define_accessors( srv, priority, 16 );
+dns_fixed_fields_define_accessors( srv, weight,   16 );
+dns_fixed_fields_define_accessors( srv, port,     16 );
+
+STATIC_INLINE void
+       dns_fixed_fields_srv_init(
+               dns_fixed_fields_srv *  inFields,
+               uint16_t                                inPriority,
+               uint16_t                                inWeight,
+               uint16_t                                inPort )
+{
+       dns_fixed_fields_srv_set_priority( inFields, inPriority );
+       dns_fixed_fields_srv_set_weight( inFields, inWeight );
+       dns_fixed_fields_srv_set_port( inFields, inPort );
+}
+
+// DNS SOA record data fixed-length fields (see <https://tools.ietf.org/html/rfc1035#section-3.3.13>)
+
+typedef struct
+{
+       uint8_t         serial[ 4 ];
+       uint8_t         refresh[ 4 ];
+       uint8_t         retry[ 4 ];
+       uint8_t         expire[ 4 ];
+       uint8_t         minimum[ 4 ];
+       
+}      dns_fixed_fields_soa;
+
+check_compile_time( sizeof( dns_fixed_fields_soa ) == 20 );
+
+dns_fixed_fields_define_accessors( soa, serial,  32 );
+dns_fixed_fields_define_accessors( soa, refresh, 32 );
+dns_fixed_fields_define_accessors( soa, retry,   32 );
+dns_fixed_fields_define_accessors( soa, expire,  32 );
+dns_fixed_fields_define_accessors( soa, minimum, 32 );
+
+STATIC_INLINE void
+       dns_fixed_fields_soa_init(
+               dns_fixed_fields_soa *  inFields,
+               uint32_t                                inSerial,
+               uint32_t                                inRefresh,
+               uint32_t                                inRetry,
+               uint32_t                                inExpire,
+               uint32_t                                inMinimum )
+{
+       dns_fixed_fields_soa_set_serial( inFields, inSerial );
+       dns_fixed_fields_soa_set_refresh( inFields, inRefresh );
+       dns_fixed_fields_soa_set_retry( inFields, inRetry );
+       dns_fixed_fields_soa_set_expire( inFields, inExpire );
+       dns_fixed_fields_soa_set_minimum( inFields, inMinimum );
+}
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Extracts a domain name from a DNS message.
+       
+       @param          inMsgPtr                Pointer to the beginning of the DNS message containing the domain name.
+       @param          inMsgLen                Length of the DNS message containing the domain name.
+       @param          inPtr                   Pointer to the domain name field.
+       @param          outName                 Buffer to write extracted domain name. (Optional)
+       @param          outPtr                  Gets set to point to the end of the domain name field. (Optional)
+*/
+OSStatus
+       DNSMessageExtractDomainName(
+               const uint8_t *         inMsgPtr,
+               size_t                          inMsgLen,
+               const uint8_t *         inPtr,
+               uint8_t                         outName[ kDomainNameLengthMax ],
+               const uint8_t **        outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Extracts a domain name from a DNS message as a C string.
+       
+       @param          inMsgPtr                Pointer to the beginning of the DNS message containing the domain name.
+       @param          inMsgLen                Length of the DNS message containing the domain name.
+       @param          inPtr                   Pointer to the domain name field.
+       @param          outName                 Buffer to write extracted domain name. (Optional)
+       @param          outPtr                  Gets set to point to the end of the domain name field. (Optional)
+*/
+OSStatus
+       DNSMessageExtractDomainNameString(
+               const void *            inMsgPtr,
+               size_t                          inMsgLen,
+               const void *            inPtr,
+               char                            outName[ kDNSServiceMaxDomainName ],
+               const uint8_t **        outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Extracts a question from a DNS message.
+       
+       @param          inMsgPtr                Pointer to the beginning of the DNS message containing a question.
+       @param          inMsgLen                Length of the DNS message containing the question.
+       @param          inPtr                   Pointer to the question.
+       @param          outName                 Buffer to write the question's QNAME. (Optional)
+       @param          outType                 Gets set to question's QTYPE value. (Optional)
+       @param          outClass                Gets set to question's QCLASS value. (Optional)
+       @param          outPtr                  Gets set to point to the end of the question. (Optional)
+*/
+OSStatus
+       DNSMessageExtractQuestion(
+               const uint8_t *         inMsgPtr,
+               size_t                          inMsgLen,
+               const uint8_t *         inPtr,
+               uint8_t                         outName[ kDomainNameLengthMax ],
+               uint16_t *                      outType,
+               uint16_t *                      outClass,
+               const uint8_t **        outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Extracts a resource record from a DNS message.
+       
+       @param          inMsgPtr                Pointer to the beginning of the DNS message containing the resource record.
+       @param          inMsgLen                Length of the DNS message containing the resource record.
+       @param          inPtr                   Pointer to the resource record.
+       @param          outName                 Buffer to write the resource record's NAME. (Optional)
+       @param          outType                 Gets set to resource record's TYPE value. (Optional)
+       @param          outClass                Gets set to resource record's CLASS value. (Optional)
+       @param          outTTL                  Gets set to resource record's TTL value. (Optional)
+       @param          outRDataPtr             Gets set to point to the resource record's RDATA. (Optional)
+       @param          outRDataLen             Gets set to the resource record's RDLENGTH. (Optional)
+       @param          outPtr                  Gets set to point to the end of the resource record. (Optional)
+*/
+OSStatus
+       DNSMessageExtractRecord(
+               const uint8_t *         inMsgPtr,
+               size_t                          inMsgLen,
+               const uint8_t *         inPtr,
+               uint8_t                         outName[ kDomainNameLengthMax ],
+               uint16_t *                      outType,
+               uint16_t *                      outClass,
+               uint32_t *                      outTTL,
+               const uint8_t **        outRDataPtr,
+               size_t *                        outRDataLen,
+               const uint8_t **        outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Returns pointer to the start of the answer section, i.e., the end of the question section, of a DNS message.
+       
+       @param          inMsgPtr                Pointer to the beginning of the DNS message.
+       @param          inMsgLen                Length of the DNS message.
+       @param          outPtr                  Gets set to point to the start of the answer section. (Optional)
+*/
+OSStatus       DNSMessageGetAnswerSection( const uint8_t *inMsgPtr, size_t inMsgLen, const uint8_t **outPtr );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Writes a DNS message compression label pointer.
+       
+       @param          inLabelPtr              Pointer to the two bytes to which to write the label pointer.
+       @param          inOffset                The label pointer's offset value. This offset is relative to the start of the DNS message.
+       
+       @discussion     See <https://tools.ietf.org/html/rfc1035#section-4.1.4>.
+*/
+STATIC_INLINE void     DNSMessageWriteLabelPointer( uint8_t inLabelPtr[ STATIC_PARAM 2 ], size_t inOffset )
+{
+       inLabelPtr[ 0 ] = (uint8_t)( ( ( inOffset >> 8 ) & 0x3F ) | 0xC0 );
+       inLabelPtr[ 1 ] = (uint8_t)(     inOffset        & 0xFF          );
+}
+
+#define kDNSCompressionOffsetMax               0x3FFF
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Writes a single-question DNS query message.
+       
+       @param          inMsgID                 The query message's ID.
+       @param          inFlags                 The query message's flags.
+       @param          inQName                 The question's QNAME in label format.
+       @param          inQType                 The question's QTYPE.
+       @param          inQClass                The question's QCLASS.
+       @param          outMsg                  Buffer to write DNS query message.
+       @param          outLen                  Gets set to the length of the DNS query message.
+       
+       @discussion     The duplicate domain name must be freed with free() when no longer needed.
+*/
+#define kDNSQueryMessageMaxLen         ( kDNSHeaderLength + kDomainNameLengthMax + sizeof( dns_fixed_fields_question ) )
+
+OSStatus
+       DNSMessageWriteQuery(
+               uint16_t                inMsgID,
+               uint16_t                inFlags,
+               const uint8_t * inQName,
+               uint16_t                inQType,
+               uint16_t                inQClass,
+               uint8_t                 outMsg[ STATIC_PARAM kDNSQueryMessageMaxLen ],
+               size_t *                outLen );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Appends a C string representing a textual sequence of labels to a domain name.
+       
+       @param          inName                  Pointer to the domain name.
+       @param          inString                Pointer to textual sequence of labels as a C string. (Optional)
+       @param          outEnd                  Gets set to point to the new end of the domain name if the append succeeded. (Optional)
+*/
+OSStatus
+       DomainNameAppendString(
+               uint8_t                 inName[ STATIC_PARAM kDomainNameLengthMax ],
+               const char *    inString,
+               uint8_t **              outEnd );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Creates a duplicate domain name.
+       
+       @param          inName                  The domain name to duplicate.
+       @param          inLower                 If true, uppercase letters in the duplicate are converted to lowercase.
+       @param          outNamePtr              Gets set to point to a dynamically allocated duplicate.
+       @param          outNameLen              Gets set to the length of the duplicate.
+       
+       @discussion     The duplicate domain name must be freed with free() when no longer needed.
+*/
+OSStatus       DomainNameDupEx( const uint8_t *inName, Boolean inLower, uint8_t **outNamePtr, size_t *outNameLen );
+
+#define DomainNameDup( IN_NAME, OUT_NAME, OUT_LEN )                            DomainNameDupEx( IN_NAME, false, OUT_NAME, OUT_LEN )
+#define DomainNameDupLower( IN_NAME, OUT_NAME, OUT_LEN )               DomainNameDupEx( IN_NAME, true, OUT_NAME, OUT_LEN )
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Compares two domain names in label format for case-insensitive equality.
+       
+       @param          inName1         Pointer to the first domain name.
+       @param          inName2         Pointer to the second domain name.
+       
+       @result         If the domain names are equal, returns true, otherwise, returns false.
+*/
+Boolean        DomainNameEqual( const uint8_t *inName1, const uint8_t *inName2 );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Converts a domain name's textual representation to a domain name in label format.
+       
+       @param          outName                 Buffer to write the domain name in label format.
+       @param          inString                Textual representation of a domain name as a C string.
+       @param          outEnd                  Gets set to point to the new end of the domain name if the append succeeded. (Optional)
+       
+       @discussion     The duplicate domain name must be freed with free() when no longer needed.
+*/
+OSStatus
+       DomainNameFromString(
+               uint8_t                 outName[ STATIC_PARAM kDomainNameLengthMax ],
+               const char *    inString,
+               uint8_t **              outEnd );
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Gets the next label in a domain name label sequence.
+       
+       @param          inLabel         Pointer to the current label.
+       
+       @result         If the current label is a root label, returns NULL. Otherwise, returns the next label.
+*/
+STATIC_INLINE const uint8_t *  DomainNameGetNextLabel( const uint8_t *inLabel )
+{
+       const int len = *inLabel;
+       return ( ( len == 0 ) ? NULL : &inLabel[ 1 + len ] );
+}
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Computes the length of a domain name in label format.
+       
+       @param          inName          The domain name.
+*/
+STATIC_INLINE size_t   DomainNameLength( const uint8_t *inName )
+{
+       const uint8_t *         label;
+       int                                     len;
+       
+       for( label = inName; ( len = *label ) != 0; label = &label[ 1 + len ] ) {}
+       return( (size_t)( label - inName ) + 1 );
+}
+
+//---------------------------------------------------------------------------------------------------------------------------
+/*!    @brief          Converts a domain name in label format to its textual representation as a C string.
+       
+       @param          inName          Pointer to the domain name.
+       @param          inLimit         Pointer to not exceed while parsing a potentially truncated domain name. (Optional)
+       @param          outString       Buffer to write the C string.
+       @param          outPtr          Gets set to point to the end of the domain name. (Optional)
+*/
+OSStatus
+       DomainNameToString(
+               const uint8_t *         inName,
+               const uint8_t *         inLimit,
+               char                            outString[ STATIC_PARAM kDNSServiceMaxDomainName ],
+               const uint8_t **        outPtr );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __DNSMessage_h
diff --git a/Clients/dnssdutil/dnssdutil-entitlements.plist b/Clients/dnssdutil/dnssdutil-entitlements.plist
new file mode 100644 (file)
index 0000000..8be5704
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.mDNSResponder.dnsproxy</key>
+       <true/>
+       <key>com.apple.mDNSResponder_Helper</key>
+       <true/>
+       <key>com.apple.security.network.client</key>
+       <true/>
+       <key>com.apple.security.network.server</key>
+       <true/>
+       <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
+       <true/>
+       <key>com.apple.SystemConfiguration.SCPreferences-write-access</key>
+       <array>
+               <string>preferences.plist</string>
+       </array>
+</dict>
+</plist>
diff --git a/Clients/dnssdutil/dnssdutil.c b/Clients/dnssdutil/dnssdutil.c
new file mode 100644 (file)
index 0000000..ef67036
--- /dev/null
@@ -0,0 +1,24123 @@
+/*
+       Copyright (c) 2016-2019 Apple Inc. All rights reserved.
+       
+       dnssdutil is a command-line utility for testing the DNS-SD API.
+*/
+
+#include "DNSMessage.h"
+
+#include <CoreUtils/CoreUtils.h>
+#include <dns_sd.h>
+#include <dns_sd_private.h>
+
+#include CF_RUNTIME_HEADER
+
+#if( TARGET_OS_DARWIN )
+       #include <CFNetwork/CFHost.h>
+       #include <CoreFoundation/CoreFoundation.h>
+       #include <SystemConfiguration/SCPrivate.h>
+       #include <dnsinfo.h>
+       #include <libproc.h>
+       #include <netdb.h>
+       #include <pcap.h>
+       #include <spawn.h>
+       #include <sys/proc_info.h>
+       #include <xpc/xpc.h>
+#endif
+
+#if( TARGET_OS_POSIX )
+       #include <sys/resource.h>
+#endif
+
+#if( !defined( DNSSDUTIL_INCLUDE_DNSCRYPT ) )
+       #define DNSSDUTIL_INCLUDE_DNSCRYPT              0
+#endif
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+       #include "tweetnacl.h"  // TweetNaCl from <https://tweetnacl.cr.yp.to/software.html>.
+#endif
+
+#if( !defined( MDNSRESPONDER_PROJECT ) )
+       #define MDNSRESPONDER_PROJECT           0
+#endif
+
+#if( MDNSRESPONDER_PROJECT )
+       #include <dns_services.h>
+       #include "mdns_private.h"
+#endif
+
+//===========================================================================================================================
+//     Versioning
+//===========================================================================================================================
+
+#define kDNSSDUtilNumVersion   NumVersionBuild( 2, 0, 0, kVersionStageBeta, 0 )
+
+#if( !MDNSRESPONDER_PROJECT && !defined( DNSSDUTIL_SOURCE_VERSION ) )
+       #define DNSSDUTIL_SOURCE_VERSION        "0.0.0"
+#endif
+
+#define kDNSSDUtilIdentifier           "com.apple.dnssdutil"
+
+//===========================================================================================================================
+//     DNS-SD
+//===========================================================================================================================
+
+// DNS-SD API flag descriptors
+
+#define kDNSServiceFlagsDescriptors            \
+       "\x00" "AutoTrigger\0"                          \
+       "\x01" "Add\0"                                          \
+       "\x02" "Default\0"                                      \
+       "\x03" "NoAutoRename\0"                         \
+       "\x04" "Shared\0"                                       \
+       "\x05" "Unique\0"                                       \
+       "\x06" "BrowseDomains\0"                        \
+       "\x07" "RegistrationDomains\0"          \
+       "\x08" "LongLivedQuery\0"                       \
+       "\x09" "AllowRemoteQuery\0"                     \
+       "\x0A" "ForceMulticast\0"                       \
+       "\x0B" "KnownUnique\0"                          \
+       "\x0C" "ReturnIntermediates\0"          \
+       "\x0D" "DenyConstrained\0"                      \
+       "\x0E" "ShareConnection\0"                      \
+       "\x0F" "SuppressUnusable\0"                     \
+       "\x10" "Timeout\0"                                      \
+       "\x11" "IncludeP2P\0"                           \
+       "\x12" "WakeOnResolve\0"                        \
+       "\x13" "BackgroundTrafficClass\0"       \
+       "\x14" "IncludeAWDL\0"                          \
+       "\x15" "Validate\0"                                     \
+       "\x16" "UnicastResponse\0"                      \
+       "\x17" "ValidateOptional\0"                     \
+       "\x18" "WakeOnlyService\0"                      \
+       "\x19" "ThresholdOne\0"                         \
+       "\x1A" "ThresholdFinder\0"                      \
+       "\x1B" "DenyCellular\0"                         \
+       "\x1C" "ServiceIndex\0"                         \
+       "\x1D" "DenyExpensive\0"                        \
+       "\x1E" "PathEvaluationDone\0"           \
+       "\x1F" "AllowExpiredAnswers\0"          \
+       "\x00"
+
+#define DNSServiceFlagsToAddRmvStr( FLAGS )            ( ( (FLAGS) & kDNSServiceFlagsAdd ) ? "Add" : "Rmv" )
+
+#define kDNSServiceProtocolDescriptors \
+       "\x00" "IPv4\0"                                         \
+       "\x01" "IPv6\0"                                         \
+       "\x04" "UDP\0"                                          \
+       "\x05" "TCP\0"                                          \
+       "\x00"
+
+#define kBadDNSServiceRef              ( (DNSServiceRef)(intptr_t) -1 )
+
+//===========================================================================================================================
+//     DNS
+//===========================================================================================================================
+
+#define kDNSPort                                       53
+#define kDNSMaxUDPMessageSize          512
+#define kDNSMaxTCPMessageSize          UINT16_MAX
+
+#define kDNSRecordDataLengthMax                UINT16_MAX
+
+//===========================================================================================================================
+//     mDNS
+//===========================================================================================================================
+
+#define kMDNSPort              5353
+
+#define kDefaultMDNSMessageID          0
+#define kDefaultMDNSQueryFlags         0
+
+#define kQClassUnicastResponseBit              ( 1U << 15 )
+#define kRRClassCacheFlushBit                  ( 1U << 15 )
+
+// Recommended Resource Record TTL values. See <https://tools.ietf.org/html/rfc6762#section-10>.
+
+#define kMDNSRecordTTL_Host                    120             // TTL for resource records related to a host name, e.g., A, AAAA, SRV, etc.
+#define kMDNSRecordTTL_Other           4500    // TTL for other resource records.
+
+// Maximum mDNS Message Size. See <https://tools.ietf.org/html/rfc6762#section-17>.
+
+#define kMDNSMessageSizeMax            8952    // 9000 B (Ethernet jumbo frame max size) - 40 B (IPv6 header) - 8 B (UDP header)
+
+#define kLocalStr                      "\x05" "local"
+#define kLocalLabel                    ( (const uint8_t *) kLocalStr )
+#define kLocalName                     ( (const uint8_t *) kLocalStr )
+#define kLocalNameLen          sizeof( kLocalStr )
+
+//===========================================================================================================================
+//     Test Address Blocks
+//===========================================================================================================================
+
+// IPv4 address block 203.0.113.0/24 (TEST-NET-3) is reserved for documentation. See <https://tools.ietf.org/html/rfc5737>.
+
+#define kDNSServerBaseAddrV4           UINT32_C( 0xCB007100 )  // 203.0.113.0/24
+
+// IPv6 address block 2001:db8::/32 is reserved for documentation. See <https://tools.ietf.org/html/rfc3849>.
+
+static const uint8_t           kDNSServerBaseAddrV6[] =
+{
+       0x20, 0x01, 0x0D, 0xB8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // 2001:db8:1::/120
+};
+
+static const uint8_t           kMDNSReplierBaseAddrV6[] =
+{
+       0x20, 0x01, 0x0D, 0xB8, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // 2001:db8:2::/96
+};
+
+check_compile_time( sizeof( kDNSServerBaseAddrV6 )   == 16 );
+check_compile_time( sizeof( kMDNSReplierBaseAddrV6 ) == 16 );
+
+// Bad IPv4 and IPv6 Address Blocks
+// Used by the DNS server when it needs to respond with intentionally "bad" A/AAAA record data, i.e., IP addresses neither
+// in 203.0.113.0/24 nor 2001:db8:1::/120.
+
+#define kDNSServerBadBaseAddrV4                UINT32_C( 0x00000000 )  // 0.0.0.0/24
+
+static const uint8_t           kDNSServerBadBaseAddrV6[] =
+{
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00  // ::ffff:0:0/120
+};
+
+check_compile_time( sizeof( kDNSServerBadBaseAddrV6 ) == 16 );
+
+//===========================================================================================================================
+//     Misc.
+//===========================================================================================================================
+
+#define kLowerAlphaNumericCharSet                      "abcdefghijklmnopqrstuvwxyz0123456789"
+#define kLowerAlphaNumericCharSetSize          sizeof_string( kLowerAlphaNumericCharSet )
+
+#if( !defined( kWhiteSpaceCharSet ) )
+       #define kWhiteSpaceCharSet              "\t\n\v\f\r "
+#endif
+
+// Note: strcpy_literal() appears in CoreUtils code, but isn't currently defined in framework headers.
+
+#if( !defined( strcpy_literal ) )
+       #define strcpy_literal( DST, SRC )              memcpy( DST, SRC, sizeof( SRC ) )
+#endif
+
+#define _RandomStringExact( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, OUT_STRING ) \
+       RandomString( CHAR_SET, CHAR_SET_SIZE, CHAR_COUNT, CHAR_COUNT, OUT_STRING )
+
+#define kNoSuchRecordStr                       "No Such Record"
+#define kNoSuchRecordAStr                      "No Such Record (A)"
+#define kNoSuchRecordAAAAStr           "No Such Record (AAAA)"
+
+#define kRootLabel             ( (const uint8_t *) "" )
+
+//===========================================================================================================================
+//     Gerneral Command Options
+//===========================================================================================================================
+
+// Command option macros
+
+#define Command( NAME, CALLBACK, SUB_OPTIONS, SHORT_HELP, IS_NOTCOMMON )                                                                                       \
+       CLI_COMMAND_EX( NAME, CALLBACK, SUB_OPTIONS, (IS_NOTCOMMON) ? kCLIOptionFlags_NotCommon : kCLIOptionFlags_None, \
+               (SHORT_HELP), NULL )
+
+#define kRequiredOptionSuffix          " [REQUIRED]"
+
+#define MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP )     \
+       CLI_OPTION_MULTI_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP,                                                                    \
+               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                                                                                          \
+               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
+
+#define MultiStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+               MultiStringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, VAL_COUNT_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
+
+#define IntegerOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED )     \
+       CLI_OPTION_INTEGER_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                                \
+               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                          \
+               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
+
+#define DoubleOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED )      \
+       CLI_OPTION_DOUBLE_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                                 \
+               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                          \
+               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
+
+#define BooleanOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP ) \
+       CLI_OPTION_BOOLEAN( (SHORT_CHAR), (LONG_NAME), (VAL_PTR), (SHORT_HELP), NULL )
+
+#define StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, LONG_HELP ) \
+       CLI_OPTION_STRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                                                         \
+               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                                                  \
+               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, LONG_HELP )
+
+#define StringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED ) \
+       StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED, NULL )
+
+#define CFStringOption( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP, SHORT_HELP, IS_REQUIRED )    \
+       CLI_OPTION_CFSTRING_EX( SHORT_CHAR, LONG_NAME, VAL_PTR, ARG_HELP,                                               \
+               (IS_REQUIRED) ? SHORT_HELP kRequiredOptionSuffix : SHORT_HELP,                                          \
+               (IS_REQUIRED) ? kCLIOptionFlags_Required : kCLIOptionFlags_None, NULL )
+
+// DNS-SD API flag options
+
+static int             gDNSSDFlags                                             = 0;
+static int             gDNSSDFlag_AllowExpiredAnswers  = false;
+static int             gDNSSDFlag_BrowseDomains                = false;
+static int             gDNSSDFlag_DenyCellular                 = false;
+static int             gDNSSDFlag_DenyConstrained              = false;
+static int             gDNSSDFlag_DenyExpensive                = false;
+static int             gDNSSDFlag_ForceMulticast               = false;
+static int             gDNSSDFlag_IncludeAWDL                  = false;
+static int             gDNSSDFlag_KnownUnique                  = false;
+static int             gDNSSDFlag_NoAutoRename                 = false;
+static int             gDNSSDFlag_PathEvaluationDone   = false;
+static int             gDNSSDFlag_RegistrationDomains  = false;
+static int             gDNSSDFlag_ReturnIntermediates  = false;
+static int             gDNSSDFlag_Shared                               = false;
+static int             gDNSSDFlag_SuppressUnusable             = false;
+static int             gDNSSDFlag_Timeout                              = false;
+static int             gDNSSDFlag_UnicastResponse              = false;
+static int             gDNSSDFlag_Unique                               = false;
+static int             gDNSSDFlag_WakeOnResolve                = false;
+
+#define DNSSDFlagsOption()                                                             \
+       IntegerOption( 'f', "flags", &gDNSSDFlags, "flags",     \
+               "DNSServiceFlags as an integer. This value is bitwise ORed with other single flag options.", false )
+
+#define DNSSDFlagOption( SHORT_CHAR, FLAG_NAME ) \
+       BooleanOption( SHORT_CHAR, # FLAG_NAME, &gDNSSDFlag_ ## FLAG_NAME, "Use kDNSServiceFlags" # FLAG_NAME "." )
+
+#define DNSSDFlagsOption_AllowExpiredAnswers()         DNSSDFlagOption( 'X', AllowExpiredAnswers )
+#define DNSSDFlagsOption_DenyCellular()                                DNSSDFlagOption( 'C', DenyCellular )
+#define DNSSDFlagsOption_DenyConstrained()                     DNSSDFlagOption( 'R', DenyConstrained)
+#define DNSSDFlagsOption_DenyExpensive()                       DNSSDFlagOption( 'E', DenyExpensive )
+#define DNSSDFlagsOption_ForceMulticast()                      DNSSDFlagOption( 'M', ForceMulticast )
+#define DNSSDFlagsOption_IncludeAWDL()                         DNSSDFlagOption( 'A', IncludeAWDL )
+#define DNSSDFlagsOption_KnownUnique()                         DNSSDFlagOption( 'K', KnownUnique )
+#define DNSSDFlagsOption_NoAutoRename()                                DNSSDFlagOption( 'N', NoAutoRename )
+#define DNSSDFlagsOption_PathEvalDone()                                DNSSDFlagOption( 'P', PathEvaluationDone )
+#define DNSSDFlagsOption_ReturnIntermediates()         DNSSDFlagOption( 'I', ReturnIntermediates )
+#define DNSSDFlagsOption_Shared()                                      DNSSDFlagOption( 'S', Shared )
+#define DNSSDFlagsOption_SuppressUnusable()                    DNSSDFlagOption( 'S', SuppressUnusable )
+#define DNSSDFlagsOption_Timeout()                                     DNSSDFlagOption( 'T', Timeout )
+#define DNSSDFlagsOption_UnicastResponse()                     DNSSDFlagOption( 'U', UnicastResponse )
+#define DNSSDFlagsOption_Unique()                                      DNSSDFlagOption( 'U', Unique )
+#define DNSSDFlagsOption_WakeOnResolve()                       DNSSDFlagOption( 'W', WakeOnResolve )
+
+// Interface option
+
+static const char *            gInterface = NULL;
+
+#define InterfaceOption()                                                                              \
+       StringOption( 'i', "interface", &gInterface, "interface",       \
+               "Network interface by name or index. Use index -1 for local-only.", false )
+
+// Connection options
+
+#define kConnectionArg_Normal                  ""
+#define kConnectionArgPrefix_PID               "pid:"
+#define kConnectionArgPrefix_UUID              "uuid:"
+
+static const char *            gConnectionOpt = kConnectionArg_Normal;
+
+#define ConnectionOptions()                                                                                                                                                                            \
+       { kCLIOptionType_String, 0, "connection", &gConnectionOpt, NULL, (intptr_t) kConnectionArg_Normal, "type",      \
+               kCLIOptionFlags_OptionalArgument, NULL, NULL, NULL, NULL,                                                                                               \
+               "Specifies the type of main connection to use. See " kConnectionSection_Name " below.", NULL }
+
+#define kConnectionSection_Name                "Connection Option"
+#define kConnectionSection_Text                                                                                                                                                                                        \
+       "The default behavior is to create a main connection with DNSServiceCreateConnection() and perform operations on\n"     \
+       "the main connection using the kDNSServiceFlagsShareConnection flag. This behavior can be explicitly invoked by\n"      \
+       "specifying the connection option without an argument, i.e.,\n"                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "    --connection\n"                                                                                                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "To instead use a delegate connection created with DNSServiceCreateDelegateConnection(), use\n"                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "    --connection=pid:<PID>\n"                                                                                                                                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "to specify the delegator by PID, or use\n"                                                                                                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "    --connection=uuid:<UUID>\n"                                                                                                                                                                        \
+       "\n"                                                                                                                                                                                                                            \
+       "to specify the delegator by UUID.\n"                                                                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "To not use a main connection at all, but instead perform operations on their own implicit connections, use\n"          \
+       "\n"                                                                                                                                                                                                                            \
+       "    --no-connection\n"
+
+#define ConnectionSection()            CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
+
+// Help text for record data options
+
+#define kRDataArgPrefix_Domain                 "domain:"
+#define kRDataArgPrefix_File                   "file:"
+#define kRDataArgPrefix_HexString              "hex:"
+#define kRDataArgPrefix_IPv4                   "ipv4:"
+#define kRDataArgPrefix_IPv6                   "ipv6:"
+#define kRDataArgPrefix_SRV                            "srv:"
+#define kRDataArgPrefix_String                 "string:"
+#define kRDataArgPrefix_TXT                            "txt:"
+
+#define kRecordDataSection_Name                "Record Data Arguments"
+#define kRecordDataSection_Text                                                                                                                                                                                        \
+       "A record data argument is specified in one of the following formats:\n"                                                                                        \
+       "\n"                                                                                                                                                                                                                            \
+       "Format                       Syntax                                   Example\n"                                                                       \
+       "Domain name                  domain:<domain name>                     domain:demo._test._tcp.local\n"                          \
+       "File containing record data  file:<file path>                         file:/path/to/binary-rdata-file\n"                       \
+       "Hexadecimal string           hex:<hex string>                         hex:c0000201 or hex:'C0 00 02 01'\n"                 \
+       "IPv4 address                 ipv4:<IPv4 address>                      ipv4:192.0.2.1\n"                                                        \
+       "IPv6 address                 ipv6:<IPv6 address>                      ipv6:2001:db8::1\n"                                                      \
+       "SRV record                   srv:<priority>,<weight>,<port>,<target>  srv:0,0,64206,example.local\n"                           \
+       "String                       string:<string>                          string:'\\x09color=red'\n"                                       \
+       "TXT record strings           txt:<comma-delimited strings>            txt:'vers=1.0,lang=en\\,es\\,fr,passreq'\n"      \
+       "\n"                                                                                                                                                                                                                            \
+       "Note: The string format converts each \\xHH escape sequence into the octet represented by the HH hex digit pair.\n"
+
+#define RecordDataSection()            CLI_SECTION( kRecordDataSection_Name, kRecordDataSection_Text )
+
+//===========================================================================================================================
+//     Output Formatting
+//===========================================================================================================================
+
+#define kOutputFormatStr_JSON          "json"
+#define kOutputFormatStr_XML           "xml"
+#define kOutputFormatStr_Binary                "binary"
+
+typedef enum
+{
+       kOutputFormatType_Invalid       = 0,
+       kOutputFormatType_JSON          = 1,
+       kOutputFormatType_XML           = 2,
+       kOutputFormatType_Binary        = 3
+       
+}      OutputFormatType;
+
+#define FormatOption( SHORT_CHAR, LONG_NAME, VAL_PTR, SHORT_HELP, IS_REQUIRED )                        \
+       StringOptionEx( SHORT_CHAR, LONG_NAME, VAL_PTR, "format", SHORT_HELP, IS_REQUIRED,      \
+               "\n"                                                                                                                                                    \
+               "Use '" kOutputFormatStr_JSON   "' for JavaScript Object Notation (JSON).\n"    \
+               "Use '" kOutputFormatStr_XML    "' for property list XML version 1.0.\n"                \
+               "Use '" kOutputFormatStr_Binary "' for property list binary version 1.0.\n"             \
+               "\n"                                                                                                                                                    \
+       )
+
+//===========================================================================================================================
+//     Browse Command Options
+//===========================================================================================================================
+
+static char **                 gBrowse_ServiceTypes            = NULL;
+static size_t                  gBrowse_ServiceTypesCount       = 0;
+static const char *            gBrowse_Domain                          = NULL;
+static int                             gBrowse_DoResolve                       = false;
+static int                             gBrowse_QueryTXT                        = false;
+static int                             gBrowse_TimeLimitSecs           = 0;
+
+static CLIOption               kBrowseOpts[] =
+{
+       InterfaceOption(),
+       MultiStringOption(      't', "type",    &gBrowse_ServiceTypes, &gBrowse_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\".", true ),
+       StringOption(           'd', "domain",  &gBrowse_Domain, "domain", "Domain in which to browse for the service type(s).", false ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       DNSSDFlagsOption_IncludeAWDL(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       ConnectionOptions(),
+       BooleanOption(  0 , "resolve",          &gBrowse_DoResolve,             "Resolve service instances." ),
+       BooleanOption(  0 , "queryTXT",         &gBrowse_QueryTXT,              "Query TXT records of service instances." ),
+       IntegerOption( 'l', "timeLimit",        &gBrowse_TimeLimitSecs, "seconds", "Specifies the max duration of the browse operation. Use '0' for no time limit.", false ),
+       
+       ConnectionSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     GetAddrInfo Command Options
+//===========================================================================================================================
+
+static const char *            gGetAddrInfo_Name                       = NULL;
+static int                             gGetAddrInfo_ProtocolIPv4       = false;
+static int                             gGetAddrInfo_ProtocolIPv6       = false;
+static int                             gGetAddrInfo_OneShot            = false;
+static int                             gGetAddrInfo_TimeLimitSecs      = 0;
+
+static CLIOption               kGetAddrInfoOpts[] =
+{
+       InterfaceOption(),
+       StringOption(  'n', "name", &gGetAddrInfo_Name,                 "domain name", "Domain name to resolve.", true ),
+       BooleanOption(  0 , "ipv4", &gGetAddrInfo_ProtocolIPv4, "Use kDNSServiceProtocol_IPv4." ),
+       BooleanOption(  0 , "ipv6", &gGetAddrInfo_ProtocolIPv6, "Use kDNSServiceProtocol_IPv6." ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       DNSSDFlagsOption_AllowExpiredAnswers(),
+       DNSSDFlagsOption_DenyCellular(),
+       DNSSDFlagsOption_DenyConstrained(),
+       DNSSDFlagsOption_DenyExpensive(),
+       DNSSDFlagsOption_PathEvalDone(),
+       DNSSDFlagsOption_ReturnIntermediates(),
+       DNSSDFlagsOption_SuppressUnusable(),
+       DNSSDFlagsOption_Timeout(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       ConnectionOptions(),
+       BooleanOption( 'o', "oneshot",          &gGetAddrInfo_OneShot,                  "Finish after first set of results." ),
+       IntegerOption( 'l', "timeLimit",        &gGetAddrInfo_TimeLimitSecs,    "seconds", "Maximum duration of the GetAddrInfo operation. Use '0' for no time limit.", false ),
+       
+       ConnectionSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     QueryRecord Command Options
+//===========================================================================================================================
+
+static const char *            gQueryRecord_Name                       = NULL;
+static const char *            gQueryRecord_Type                       = NULL;
+static int                             gQueryRecord_OneShot            = false;
+static int                             gQueryRecord_TimeLimitSecs      = 0;
+static int                             gQueryRecord_RawRData           = false;
+
+static CLIOption               kQueryRecordOpts[] =
+{
+       InterfaceOption(),
+       StringOption( 'n', "name", &gQueryRecord_Name, "domain name", "Full domain name of record to query.", true ),
+       StringOption( 't', "type", &gQueryRecord_Type, "record type", "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       DNSSDFlagsOption_AllowExpiredAnswers(),
+       DNSSDFlagsOption_DenyCellular(),
+       DNSSDFlagsOption_DenyConstrained(),
+       DNSSDFlagsOption_DenyExpensive(),
+       DNSSDFlagsOption_ForceMulticast(),
+       DNSSDFlagsOption_IncludeAWDL(),
+       DNSSDFlagsOption_PathEvalDone(),
+       DNSSDFlagsOption_ReturnIntermediates(),
+       DNSSDFlagsOption_SuppressUnusable(),
+       DNSSDFlagsOption_Timeout(),
+       DNSSDFlagsOption_UnicastResponse(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       ConnectionOptions(),
+       BooleanOption( 'o', "oneshot",          &gQueryRecord_OneShot,                  "Finish after first set of results." ),
+       IntegerOption( 'l', "timeLimit",        &gQueryRecord_TimeLimitSecs,    "seconds", "Maximum duration of the query record operation. Use '0' for no time limit.", false ),
+       BooleanOption(  0 , "raw",                      &gQueryRecord_RawRData,                 "Show record data as a hexdump." ),
+       
+       ConnectionSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     Register Command Options
+//===========================================================================================================================
+
+static const char *                    gRegister_Name                  = NULL;
+static const char *                    gRegister_Type                  = NULL;
+static const char *                    gRegister_Domain                = NULL;
+static int                                     gRegister_Port                  = 0;
+static const char *                    gRegister_TXT                   = NULL;
+static int                                     gRegister_LifetimeMs    = -1;
+static const char **           gAddRecord_Types                = NULL;
+static size_t                          gAddRecord_TypesCount   = 0;
+static const char **           gAddRecord_Data                 = NULL;
+static size_t                          gAddRecord_DataCount    = 0;
+static const char **           gAddRecord_TTLs                 = NULL;
+static size_t                          gAddRecord_TTLsCount    = 0;
+static const char *                    gUpdateRecord_Data              = NULL;
+static int                                     gUpdateRecord_DelayMs   = 0;
+static int                                     gUpdateRecord_TTL               = 0;
+
+static CLIOption               kRegisterOpts[] =
+{
+       InterfaceOption(),
+       StringOption(  'n', "name",             &gRegister_Name,        "service name", "Name of service.", false ),
+       StringOption(  't', "type",             &gRegister_Type,        "service type", "Service type, e.g., \"_ssh._tcp\".", true ),
+       StringOption(  'd', "domain",   &gRegister_Domain,      "domain",               "Domain in which to advertise the service.", false ),
+       IntegerOption( 'p', "port",             &gRegister_Port,        "port number",  "Service's port number.", true ),
+       StringOption(   0 , "txt",              &gRegister_TXT,         "record data",  "The TXT record data. See " kRecordDataSection_Name " below.", false ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       DNSSDFlagsOption_IncludeAWDL(),
+       DNSSDFlagsOption_KnownUnique(),
+       DNSSDFlagsOption_NoAutoRename(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       IntegerOption( 'l', "lifetime", &gRegister_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
+       
+       CLI_OPTION_GROUP( "Options for updating the registered service's primary TXT record with DNSServiceUpdateRecord()\n" ),
+       StringOption(  0 , "updateData",        &gUpdateRecord_Data,    "record data",  "Record data for the record update. See " kRecordDataSection_Name " below.", false ),
+       IntegerOption( 0 , "updateDelay",       &gUpdateRecord_DelayMs, "ms",                   "Number of milliseconds after registration to wait before record update.", false ),
+       IntegerOption( 0 , "updateTTL",         &gUpdateRecord_TTL,             "seconds",              "Time-to-live of the updated record.", false ),
+       
+       CLI_OPTION_GROUP( "Options for adding extra record(s) to the registered service with DNSServiceAddRecord()\n" ),
+       MultiStringOption(   0 , "addType",     &gAddRecord_Types,      &gAddRecord_TypesCount, "record type",  "Type of additional record by name (e.g., TXT, SRV, etc.) or number.", false ),
+       MultiStringOptionEx( 0 , "addData",     &gAddRecord_Data,       &gAddRecord_DataCount,  "record data",  "Additional record's data. See " kRecordDataSection_Name " below.", false, NULL ),
+       MultiStringOption(   0 , "addTTL",      &gAddRecord_TTLs,       &gAddRecord_TTLsCount,  "seconds",              "Time-to-live of additional record in seconds. Use '0' for default.", false ),
+       
+       RecordDataSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     RegisterRecord Command Options
+//===========================================================================================================================
+
+static const char *            gRegisterRecord_Name                    = NULL;
+static const char *            gRegisterRecord_Type                    = NULL;
+static const char *            gRegisterRecord_Data                    = NULL;
+static int                             gRegisterRecord_TTL                             = 0;
+static int                             gRegisterRecord_LifetimeMs              = -1;
+static const char *            gRegisterRecord_UpdateData              = NULL;
+static int                             gRegisterRecord_UpdateDelayMs   = 0;
+static int                             gRegisterRecord_UpdateTTL               = 0;
+
+static CLIOption               kRegisterRecordOpts[] =
+{
+       InterfaceOption(),
+       StringOption( 'n', "name",      &gRegisterRecord_Name,  "record name",  "Fully qualified domain name of record.", true ),
+       StringOption( 't', "type",      &gRegisterRecord_Type,  "record type",  "Record type by name (e.g., TXT, PTR, A) or number.", true ),
+       StringOption( 'd', "data",      &gRegisterRecord_Data,  "record data",  "The record data. See " kRecordDataSection_Name " below.", false ),
+       IntegerOption( 0 , "ttl",       &gRegisterRecord_TTL,   "seconds",              "Time-to-live in seconds. Use '0' for default.", false ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       DNSSDFlagsOption_IncludeAWDL(),
+       DNSSDFlagsOption_KnownUnique(),
+       DNSSDFlagsOption_Shared(),
+       DNSSDFlagsOption_Unique(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       IntegerOption( 'l', "lifetime", &gRegisterRecord_LifetimeMs, "ms", "Lifetime of the service registration in milliseconds.", false ),
+       
+       CLI_OPTION_GROUP( "Options for updating the registered record with DNSServiceUpdateRecord()\n" ),
+       StringOption(  0 , "updateData",        &gRegisterRecord_UpdateData,    "record data",  "Record data for the record update.", false ),
+       IntegerOption( 0 , "updateDelay",       &gRegisterRecord_UpdateDelayMs, "ms",                   "Number of milliseconds after registration to wait before record update.", false ),
+       IntegerOption( 0 , "updateTTL",         &gRegisterRecord_UpdateTTL,             "seconds",              "Time-to-live of the updated record.", false ),
+       
+       RecordDataSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     Resolve Command Options
+//===========================================================================================================================
+
+static char *          gResolve_Name                   = NULL;
+static char *          gResolve_Type                   = NULL;
+static char *          gResolve_Domain                 = NULL;
+static int                     gResolve_TimeLimitSecs  = 0;
+
+static CLIOption               kResolveOpts[] =
+{
+       InterfaceOption(),
+       StringOption( 'n', "name",              &gResolve_Name,         "service name", "Name of the service instance to resolve.", true ),
+       StringOption( 't', "type",              &gResolve_Type,         "service type", "Type of the service instance to resolve.", true ),
+       StringOption( 'd', "domain",    &gResolve_Domain,       "domain", "Domain of the service instance to resolve.", true ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       DNSSDFlagsOption_ForceMulticast(),
+       DNSSDFlagsOption_IncludeAWDL(),
+       DNSSDFlagsOption_ReturnIntermediates(),
+       DNSSDFlagsOption_WakeOnResolve(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       ConnectionOptions(),
+       IntegerOption( 'l', "timeLimit", &gResolve_TimeLimitSecs, "seconds", "Maximum duration of the resolve operation. Use '0' for no time limit.", false ),
+       
+       ConnectionSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     Reconfirm Command Options
+//===========================================================================================================================
+
+static const char *            gReconfirmRecord_Name   = NULL;
+static const char *            gReconfirmRecord_Type   = NULL;
+static const char *            gReconfirmRecord_Class  = NULL;
+static const char *            gReconfirmRecord_Data   = NULL;
+
+static CLIOption               kReconfirmOpts[] =
+{
+       InterfaceOption(),
+       StringOption( 'n', "name",      &gReconfirmRecord_Name,         "record name",  "Full name of the record to reconfirm.", true ),
+       StringOption( 't', "type",      &gReconfirmRecord_Type,         "record type",  "Type of the record to reconfirm.", true ),
+       StringOption( 'c', "class",     &gReconfirmRecord_Class,        "record class", "Class of the record to reconfirm. Default class is IN.", false ),
+       StringOption( 'd', "data",      &gReconfirmRecord_Data,         "record data",  "The record data. See " kRecordDataSection_Name " below.", false ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       
+       RecordDataSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     getaddrinfo-POSIX Command Options
+//===========================================================================================================================
+
+static const char *            gGAIPOSIX_HostName                      = NULL;
+static const char *            gGAIPOSIX_ServName                      = NULL;
+static const char *            gGAIPOSIX_Family                        = NULL;
+static int                             gGAIPOSIXFlag_AddrConfig        = false;
+static int                             gGAIPOSIXFlag_All                       = false;
+static int                             gGAIPOSIXFlag_CanonName         = false;
+static int                             gGAIPOSIXFlag_NumericHost       = false;
+static int                             gGAIPOSIXFlag_NumericServ       = false;
+static int                             gGAIPOSIXFlag_Passive           = false;
+static int                             gGAIPOSIXFlag_V4Mapped          = false;
+#if( defined( AI_V4MAPPED_CFG ) )
+static int                             gGAIPOSIXFlag_V4MappedCFG       = false;
+#endif
+#if( defined( AI_DEFAULT ) )
+static int                             gGAIPOSIXFlag_Default           = false;
+#endif
+#if( defined( AI_UNUSABLE ) )
+static int                             gGAIPOSIXFlag_Unusable          = false;
+#endif
+
+static CLIOption               kGetAddrInfoPOSIXOpts[] =
+{
+       StringOption(   'n', "hostname",                        &gGAIPOSIX_HostName,            "hostname", "Domain name to resolve or an IPv4 or IPv6 address.", true ),
+       StringOption(   's', "servname",                        &gGAIPOSIX_ServName,            "servname", "Port number in decimal or service name from services(5).", false ),
+       
+       CLI_OPTION_GROUP( "Hints" ),
+       StringOptionEx( 'f', "family",                          &gGAIPOSIX_Family,                      "address family", "Address family to use for hints ai_family field.", false,
+               "\n"
+               "Possible address family values are 'inet' for AF_INET, 'inet6' for AF_INET6, or 'unspec' for AF_UNSPEC. If no\n"
+               "address family is specified, then AF_UNSPEC is used.\n"
+               "\n" ),
+       BooleanOption(   0 , "flag-addrconfig",         &gGAIPOSIXFlag_AddrConfig,      "In hints ai_flags field, set AI_ADDRCONFIG." ),
+       BooleanOption(   0 , "flag-all",                        &gGAIPOSIXFlag_All,                     "In hints ai_flags field, set AI_ALL." ),
+       BooleanOption(   0 , "flag-canonname",          &gGAIPOSIXFlag_CanonName,       "In hints ai_flags field, set AI_CANONNAME." ),
+       BooleanOption(   0 , "flag-numerichost",        &gGAIPOSIXFlag_NumericHost,     "In hints ai_flags field, set AI_NUMERICHOST." ),
+       BooleanOption(   0 , "flag-numericserv",        &gGAIPOSIXFlag_NumericServ,     "In hints ai_flags field, set AI_NUMERICSERV." ),
+       BooleanOption(   0 , "flag-passive",            &gGAIPOSIXFlag_Passive,         "In hints ai_flags field, set AI_PASSIVE." ),
+       BooleanOption(   0 , "flag-v4mapped",           &gGAIPOSIXFlag_V4Mapped,        "In hints ai_flags field, set AI_V4MAPPED." ),
+#if( defined( AI_V4MAPPED_CFG ) )
+       BooleanOption(   0 , "flag-v4mappedcfg",        &gGAIPOSIXFlag_V4MappedCFG,     "In hints ai_flags field, set AI_V4MAPPED_CFG." ),
+#endif
+#if( defined( AI_DEFAULT ) )
+       BooleanOption(   0 , "flag-default",            &gGAIPOSIXFlag_Default,         "In hints ai_flags field, set AI_DEFAULT." ),
+#endif
+#if( defined( AI_UNUSABLE ) )
+       BooleanOption(   0 , "flag-unusable",           &gGAIPOSIXFlag_Unusable,        "In hints ai_flags field, set AI_UNUSABLE." ),
+#endif
+       
+       CLI_SECTION( "Notes", "See getaddrinfo(3) man page for more details.\n" ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     ReverseLookup Command Options
+//===========================================================================================================================
+
+static const char *            gReverseLookup_IPAddr                   = NULL;
+static int                             gReverseLookup_OneShot                  = false;
+static int                             gReverseLookup_TimeLimitSecs    = 0;
+
+static CLIOption               kReverseLookupOpts[] =
+{
+       InterfaceOption(),
+       StringOption( 'a', "address", &gReverseLookup_IPAddr, "IP address", "IPv4 or IPv6 address for which to perform a reverse IP lookup.", true ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       DNSSDFlagsOption_ForceMulticast(),
+       DNSSDFlagsOption_ReturnIntermediates(),
+       DNSSDFlagsOption_SuppressUnusable(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       ConnectionOptions(),
+       BooleanOption( 'o', "oneshot",          &gReverseLookup_OneShot,                "Finish after first set of results." ),
+       IntegerOption( 'l', "timeLimit",        &gReverseLookup_TimeLimitSecs,  "seconds", "Specifies the max duration of the query record operation. Use '0' for no time limit.", false ),
+       
+       ConnectionSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     PortMapping Command Options
+//===========================================================================================================================
+
+static int             gPortMapping_ProtocolTCP        = false;
+static int             gPortMapping_ProtocolUDP        = false;
+static int             gPortMapping_InternalPort       = 0;
+static int             gPortMapping_ExternalPort       = 0;
+static int             gPortMapping_TTL                        = 0;
+
+static CLIOption               kPortMappingOpts[] =
+{
+       InterfaceOption(),
+       BooleanOption( 0, "tcp",                        &gPortMapping_ProtocolTCP,      "Use kDNSServiceProtocol_TCP." ),
+       BooleanOption( 0, "udp",                        &gPortMapping_ProtocolUDP,      "Use kDNSServiceProtocol_UDP." ),
+       IntegerOption( 0, "internalPort",       &gPortMapping_InternalPort,     "port number", "Internal port.", false ),
+       IntegerOption( 0, "externalPort",       &gPortMapping_ExternalPort,     "port number", "Requested external port. Use '0' for any external port.", false ),
+       IntegerOption( 0, "ttl",                        &gPortMapping_TTL,                      "seconds", "Requested TTL (renewal period) in seconds. Use '0' for a default value.", false ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       ConnectionOptions(),
+       
+       ConnectionSection(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     BrowseAll Command Options
+//===========================================================================================================================
+
+static const char *            gBrowseAll_Domain                               = NULL;
+static const char **   gBrowseAll_ServiceTypes                 = NULL;
+static size_t                  gBrowseAll_ServiceTypesCount    = 0;
+static int                             gBrowseAll_BrowseTimeSecs               = 5;
+static int                             gBrowseAll_ConnectTimeout               = 0;
+
+static CLIOption               kBrowseAllOpts[] =
+{
+       InterfaceOption(),
+       StringOption(      'd', "domain", &gBrowseAll_Domain, "domain", "Domain in which to browse for the service.", false ),
+       MultiStringOption( 't', "type",   &gBrowseAll_ServiceTypes, &gBrowseAll_ServiceTypesCount, "service type", "Service type(s), e.g., \"_ssh._tcp\". All services are browsed for if none is specified.", false ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption_IncludeAWDL(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       IntegerOption( 'b', "browseTime",     &gBrowseAll_BrowseTimeSecs, "seconds", "Amount of time to spend browsing in seconds. (default: 5)", false ),
+       IntegerOption( 'c', "connectTimeout", &gBrowseAll_ConnectTimeout, "seconds", "Timeout for connection attempts. If <= 0, no connections are attempted. (default: 0)", false ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     GetNameInfo Command Options
+//===========================================================================================================================
+
+static void    GetNameInfoCmd( void );
+
+static char *          gGetNameInfo_IPAddress                  = NULL;
+static int                     gGetNameInfoFlag_DGram                  = false;
+static int                     gGetNameInfoFlag_NameReqd               = false;
+static int                     gGetNameInfoFlag_NoFQDN                 = false;
+static int                     gGetNameInfoFlag_NumericHost    = false;
+static int                     gGetNameInfoFlag_NumericScope   = false;
+static int                     gGetNameInfoFlag_NumericServ    = false;
+
+static CLIOption               kGetNameInfoOpts[] =
+{
+       StringOption( 'a', "address",           &gGetNameInfo_IPAddress,        "IP address", "IPv4 or IPv6 address to use in sockaddr structure.", true ),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       BooleanOption( 0 , "flag-dgram",        &gGetNameInfoFlag_DGram,        "Use NI_DGRAM flag." ),
+       BooleanOption( 0 , "flag-namereqd",     &gGetNameInfoFlag_NameReqd,     "Use NI_NAMEREQD flag." ),
+       BooleanOption( 0 , "flag-nofqdn",       &gGetNameInfoFlag_NoFQDN,       "Use NI_NOFQDN flag." ),
+       BooleanOption( 0 , "flag-numerichost",  &gGetNameInfoFlag_NumericHost,  "Use NI_NUMERICHOST flag." ),
+       BooleanOption( 0 , "flag-numericscope", &gGetNameInfoFlag_NumericScope, "Use NI_NUMERICSCOPE flag." ),
+       BooleanOption( 0 , "flag-numericserv",  &gGetNameInfoFlag_NumericServ,  "Use NI_NUMERICSERV flag." ),
+       
+       CLI_SECTION( "Notes", "See getnameinfo(3) man page for more details.\n" ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     GetAddrInfoStress Command Options
+//===========================================================================================================================
+
+static int             gGAIStress_TestDurationSecs     = 0;
+static int             gGAIStress_ConnectionCount      = 0;
+static int             gGAIStress_DurationMinMs        = 0;
+static int             gGAIStress_DurationMaxMs        = 0;
+static int             gGAIStress_RequestCountMax      = 0;
+
+static CLIOption               kGetAddrInfoStressOpts[] =
+{
+       InterfaceOption(),
+       
+       CLI_OPTION_GROUP( "Flags" ),
+       DNSSDFlagsOption_ReturnIntermediates(),
+       DNSSDFlagsOption_SuppressUnusable(),
+       
+       CLI_OPTION_GROUP( "Operation" ),
+       IntegerOption( 0, "testDuration",                       &gGAIStress_TestDurationSecs,   "seconds",      "Stress test duration in seconds. Use '0' for forever.", false ),
+       IntegerOption( 0, "connectionCount",            &gGAIStress_ConnectionCount,    "integer",      "Number of simultaneous DNS-SD connections.", true ),
+       IntegerOption( 0, "requestDurationMin",         &gGAIStress_DurationMinMs,              "ms",           "Minimum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
+       IntegerOption( 0, "requestDurationMax",         &gGAIStress_DurationMaxMs,              "ms",           "Maximum duration of DNSServiceGetAddrInfo() request in milliseconds.", true ),
+       IntegerOption( 0, "consecutiveRequestMax",      &gGAIStress_RequestCountMax,    "integer",      "Maximum number of requests on a connection before restarting it.", true ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     DNSQuery Command Options
+//===========================================================================================================================
+
+static char *          gDNSQuery_Name                  = NULL;
+static char *          gDNSQuery_Type                  = "A";
+static char *          gDNSQuery_Server                = NULL;
+static int                     gDNSQuery_TimeLimitSecs = 5;
+static int                     gDNSQuery_UseTCP                = false;
+static int                     gDNSQuery_Flags                 = kDNSHeaderFlag_RecursionDesired;
+static int                     gDNSQuery_RawRData              = false;
+static int                     gDNSQuery_Verbose               = false;
+
+#if( TARGET_OS_DARWIN )
+       #define kDNSQueryServerOptionIsRequired         false
+#else
+       #define kDNSQueryServerOptionIsRequired         true
+#endif
+
+static CLIOption               kDNSQueryOpts[] =
+{
+       StringOption(  'n', "name",                     &gDNSQuery_Name,                        "name", "Question name (QNAME) to put in DNS query message.", true ),
+       StringOption(  't', "type",                     &gDNSQuery_Type,                        "type", "Question type (QTYPE) to put in DNS query message. Default value is 'A'.", false ),
+       StringOption(  's', "server",           &gDNSQuery_Server,                      "IP address", "DNS server's IPv4 or IPv6 address.", kDNSQueryServerOptionIsRequired ),
+       IntegerOption( 'l', "timeLimit",        &gDNSQuery_TimeLimitSecs,       "seconds", "Specifies query time limit. Use '-1' for no limit and '0' to exit immediately after sending.", false ),
+       BooleanOption(  0 , "tcp",                      &gDNSQuery_UseTCP,                      "Send the DNS query via TCP instead of UDP." ),
+       IntegerOption( 'f', "flags",            &gDNSQuery_Flags,                       "flags", "16-bit value for DNS header flags/codes field. Default value is 0x0100 (Recursion Desired).", false ),
+       BooleanOption(  0 , "raw",                      &gDNSQuery_RawRData,            "Present record data as a hexdump." ),
+       BooleanOption( 'v', "verbose",          &gDNSQuery_Verbose,                     "Prints the DNS message to be sent to the server." ),
+       CLI_OPTION_END()
+};
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+//===========================================================================================================================
+//     DNSCrypt Command Options
+//===========================================================================================================================
+
+static char *          gDNSCrypt_ProviderName  = NULL;
+static char *          gDNSCrypt_ProviderKey   = NULL;
+static char *          gDNSCrypt_Name                  = NULL;
+static char *          gDNSCrypt_Type                  = NULL;
+static char *          gDNSCrypt_Server                = NULL;
+static int                     gDNSCrypt_TimeLimitSecs = 5;
+static int                     gDNSCrypt_RawRData              = false;
+static int                     gDNSCrypt_Verbose               = false;
+
+static CLIOption               kDNSCryptOpts[] =
+{
+       StringOption(  'p', "providerName",     &gDNSCrypt_ProviderName,        "name", "The DNSCrypt provider name.", true ),
+       StringOption(  'k', "providerKey",      &gDNSCrypt_ProviderKey,         "hex string", "The DNSCrypt provider's public signing key.", true ),
+       StringOption(  'n', "name",                     &gDNSCrypt_Name,                        "name", "Question name (QNAME) to put in DNS query message.", true ),
+       StringOption(  't', "type",                     &gDNSCrypt_Type,                        "type", "Question type (QTYPE) to put in DNS query message.", true ),
+       StringOption(  's', "server",           &gDNSCrypt_Server,                      "IP address", "DNS server's IPv4 or IPv6 address.", true ),
+       IntegerOption( 'l', "timeLimit",        &gDNSCrypt_TimeLimitSecs,       "seconds", "Specifies query time limit. Use '-1' for no time limit and '0' to exit immediately after sending.", false ),
+       BooleanOption(  0 , "raw",                      &gDNSCrypt_RawRData,            "Present record data as a hexdump." ),
+       BooleanOption( 'v', "verbose",          &gDNSCrypt_Verbose,                     "Prints the DNS message to be sent to the server." ),
+       CLI_OPTION_END()
+};
+#endif
+
+//===========================================================================================================================
+//     MDNSQuery Command Options
+//===========================================================================================================================
+
+static char *          gMDNSQuery_Name                 = NULL;
+static char *          gMDNSQuery_Type                 = NULL;
+static int                     gMDNSQuery_SourcePort   = 0;
+static int                     gMDNSQuery_IsQU                 = false;
+static int                     gMDNSQuery_RawRData             = false;
+static int                     gMDNSQuery_UseIPv4              = false;
+static int                     gMDNSQuery_UseIPv6              = false;
+static int                     gMDNSQuery_AllResponses = false;
+static int                     gMDNSQuery_ReceiveSecs  = 1;
+
+static CLIOption               kMDNSQueryOpts[] =
+{
+       StringOption(  'i', "interface",        &gInterface,                            "name or index", "Network interface by name or index.", true ),
+       StringOption(  'n', "name",                     &gMDNSQuery_Name,                       "name", "Question name (QNAME) to put in mDNS message.", true ),
+       StringOption(  't', "type",                     &gMDNSQuery_Type,                       "type", "Question type (QTYPE) to put in mDNS message.", true ),
+       IntegerOption( 'p', "sourcePort",       &gMDNSQuery_SourcePort,         "port number", "UDP source port to use when sending mDNS messages. Default is 5353 for QM questions.", false ),
+       BooleanOption( 'u', "QU",                       &gMDNSQuery_IsQU,                       "Set the unicast-response bit, i.e., send a QU question." ),
+       BooleanOption(  0 , "raw",                      &gMDNSQuery_RawRData,           "Present record data as a hexdump." ),
+       BooleanOption(  0 , "ipv4",                     &gMDNSQuery_UseIPv4,            "Use IPv4." ),
+       BooleanOption(  0 , "ipv6",                     &gMDNSQuery_UseIPv6,            "Use IPv6." ),
+       BooleanOption( 'a', "allResponses",     &gMDNSQuery_AllResponses,       "Print all received mDNS messages, not just those containing answers." ),
+       IntegerOption( 'r', "receiveTime",      &gMDNSQuery_ReceiveSecs,        "seconds", "Amount of time to spend receiving messages after the query is sent. The default is one second. Use -1 for unlimited time.", false ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     MDNSCollider Command Options
+//===========================================================================================================================
+
+#define kMDNSColliderProgramSection_Intro                                                                                                                                                              \
+       "Programs dictate when the collider sends out unsolicited response messages for its record and how the collider\n"      \
+       "ought to react to probe queries that match its record's name, if at all.\n"                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "For example, suppose that the goal is to cause a specific unique record in the verified state to be renamed.\n"        \
+       "The collider should be invoked such that its record's name is equal to that of the record being targeted. Also,\n"     \
+       "the record's type and data should be such that no record with that name, type, and data combination currently\n"       \
+       "exists. If the mDNS responder that owns the record follows sections 8.1 and 9 of RFC 6762, then the goal can be\n"     \
+       "accomplished with the following program:\n"                                                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "    probes 3r; send; wait 5000\n"                                                                                                                                                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "The first command, 'probes 3r', tells the collider to respond to the next three probe queries that match its\n"        \
+       "record's name. The second command, makes the collider send an unsolicited response message that contains its\n"        \
+       "record in the answer section. The third command makes the collider wait for five seconds before exiting, which\n"      \
+       "is more than enough time for the collider to respond to probe queries.\n"                                                                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "The send command will cause the targeted record to go into the probing state per section 9 since the collider's\n"     \
+       "record conflicts with target record. Per the probes command, the subsequent probe query sent during the probing\n"     \
+       "state will be answered by the collider, which will cause the record to be renamed per section 8.1.\n"
+
+#define kMDNSColliderProgramSection_Probes                                                                                                                                                             \
+       "The probes command defines how the collider ought to react to probe queries that match its record's name.\n"           \
+       "\n"                                                                                                                                                                                                                            \
+       "Usage: probes [<action-string>]\n"                                                                                                                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "The syntax for an action-string is\n"                                                                                                                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "    <action-string> ::= <action> | <action-string> \"-\" <action>\n"                                                                                           \
+       "    <action>        ::= [<repeat-count>] <action-code>\n"                                                                                                                      \
+       "    <repeat-count>  ::= \"1\" | \"2\" | ... | \"10\"\n"                                                                                                                        \
+       "    <action-code>   ::= \"n\" | \"r\" | \"u\" | \"m\" | \"p\"\n"                                                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "An expanded action-string is defined as\n"                                                                                                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "    <expanded-action-string> ::= <action-code> | <expanded-action-string> \"-\" <action-code>\n"                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "The action-string argument is converted into an expanded-action-string by expanding each action with a\n"                      \
+       "repeat-count into an expanded-action-string consisting of exactly <repeat-count> <action-code>s. For example,\n"       \
+       "2n-r expands to n-n-r. Action-strings that expand to expanded-action-strings with more than 10 action-codes\n"         \
+       "are not allowed.\n"                                                                                                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "When the probes command is executed, it does two things. Firstly, it resets to zero the collider's count of\n"         \
+       "probe queries that match its record's name. Secondly, it defines how the collider ought to react to such probe\n"      \
+       "queries based on the action-string argument. Specifically, the nth action-code in the expanded version of the\n"       \
+       "action-string argument defines how the collider ought to react to the nth received probe query:\n"                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "    Code  Action\n"                                                                                                                                                                                            \
+       "    ----  ------\n"                                                                                                                                                                                            \
+       "    n     Do nothing.\n"                                                                                                                                                                                       \
+       "    r     Respond to the probe query.\n"                                                                                                                                                       \
+       "    u     Respond to the probe query via unicast.\n"                                                                                                                           \
+       "    m     Respond to the probe query via multicast.\n"                                                                                                                         \
+       "    p     Multicast own probe query. (Useful for causing simultaneous probe scenarios.)\n"                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "Note: If no action is defined for a received probe query, then the collider does nothing, i.e., it doesn't send\n"     \
+       "a response nor does it multicast its own probe query.\n"
+
+#define kMDNSColliderProgramSection_Send                                                                                                                                                               \
+       "The send command multicasts an unsolicited mDNS response containing the collider's record in the answer\n"                     \
+       "section, which can be used to force unique records with the same record name into the probing state.\n"                        \
+       "\n"                                                                                                                                                                                                                            \
+       "Usage: send\n"
+
+#define kMDNSColliderProgramSection_Wait                                                                                                                                                               \
+       "The wait command pauses program execution for the interval of time specified by its argument.\n"                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "Usage: wait <milliseconds>\n"
+
+#define kMDNSColliderProgramSection_Loop                                                                                                                                                               \
+       "The loop command starts a counting loop. The done statement marks the end of the loop body. The loop command's\n"      \
+       "argument specifies the number of loop iterations. Note: Loop nesting is supported up to a depth of 16.\n"                      \
+       "\n"                                                                                                                                                                                                                            \
+       "Usage: loop <non-zero count>; ... ; done\n"                                                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "For example, the following program sends three unsolicited responses at an approximate rate of one per second:\n"      \
+       "\n"                                                                                                                                                                                                                            \
+       "    loop 3; wait 1000; send; done"
+
+#define ConnectionSection()            CLI_SECTION( kConnectionSection_Name, kConnectionSection_Text )
+
+static const char *            gMDNSCollider_Name                      = NULL;
+static const char *            gMDNSCollider_Type                      = NULL;
+static const char *            gMDNSCollider_RecordData        = NULL;
+static int                             gMDNSCollider_UseIPv4           = false;
+static int                             gMDNSCollider_UseIPv6           = false;
+static const char *            gMDNSCollider_Program           = NULL;
+
+static CLIOption               kMDNSColliderOpts[] =
+{
+       StringOption(  'i', "interface", &gInterface,               "name or index", "Network interface by name or index.", true ),
+       StringOption(  'n', "name",      &gMDNSCollider_Name,       "name", "Collider's record name.", true ),
+       StringOption(  't', "type",      &gMDNSCollider_Type,       "type", "Collider's record type.", true ),
+       StringOption(  'd', "data",      &gMDNSCollider_RecordData, "record data", "Collider's record data. See " kRecordDataSection_Name " below.", true ),
+       StringOption(  'p', "program",   &gMDNSCollider_Program,    "program", "Program to execute. See Program section below.", true ),
+       BooleanOption(  0 , "ipv4",      &gMDNSCollider_UseIPv4,    "Use IPv4." ),
+       BooleanOption(  0 , "ipv6",      &gMDNSCollider_UseIPv6,    "Use IPv6." ),
+       
+       RecordDataSection(),
+       CLI_SECTION( "Program",                                 kMDNSColliderProgramSection_Intro ),
+       CLI_SECTION( "Program Command: probes", kMDNSColliderProgramSection_Probes ),
+       CLI_SECTION( "Program Command: send",   kMDNSColliderProgramSection_Send ),
+       CLI_SECTION( "Program Command: wait",   kMDNSColliderProgramSection_Wait ),
+       CLI_SECTION( "Program Command: loop",   kMDNSColliderProgramSection_Loop ),
+       CLI_OPTION_END()
+};
+
+static void    MDNSColliderCmd( void );
+
+//===========================================================================================================================
+//     PIDToUUID Command Options
+//===========================================================================================================================
+
+static int             gPIDToUUID_PID = 0;
+
+static CLIOption               kPIDToUUIDOpts[] =
+{
+       IntegerOption( 'p', "pid", &gPIDToUUID_PID, "PID", "Process ID.", true ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     DNSServer Command Options
+//===========================================================================================================================
+
+#define kDNSServerInfoText_Intro                                                                                                                                                                               \
+       "The DNS server answers certain queries in the d.test. domain. Responses are dynamically generated based on the\n"      \
+       "presence of special labels in the query's QNAME. There are currently eight types of special labels that can be\n"      \
+       "used to generate specific responses: Alias labels, Alias-TTL labels, Count labels, Tag labels, TTL labels, the\n"      \
+       "IPv4 label, the IPv6 label, and SRV labels.\n"                                                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
+
+#define kDNSServerInfoText_NameExistence                                                                                                                                                               \
+       "A name is considered to exist if it's an Address name or an SRV name.\n"                                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "An Address name is defined as a name that ends with d.test., and the other labels, if any, and in no particular\n"     \
+       "order, unless otherwise noted, consist of\n"                                                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. at most one Alias or Alias-TTL label as the first label;\n"                                                                                                     \
+       "    2. at most one Count label;\n"                                                                                                                                                                     \
+       "    3. zero or more Tag labels;\n"                                                                                                                                                                     \
+       "    4. at most one TTL label; and\n"                                                                                                                                                           \
+       "    5. at most one IPv4 or IPv6 label.\n"                                                                                                                                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "An SRV name is defined as a name with the following form:\n"                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       " _<service>._<proto>[.<parent domain>][.<SRV label 1>[.<target 1>][.<SRV label 2>[.<target 2>][...]]].d.test.\n"       \
+       "\n"                                                                                                                                                                                                                            \
+       "See \"SRV Names\" for details.\n"
+
+#define kDNSServerInfoText_ResourceRecords                                                                                                                                                             \
+       "Currently, the server only supports CNAME, A, AAAA, and SRV records.\n"                                                                                        \
+       "\n"                                                                                                                                                                                                                            \
+       "Address names that begin with an Alias or Alias-TTL label are aliases of canonical names, i.e., they're the\n"         \
+       "names of CNAME records. See \"Alias Labels\" and \"Alias-TTL Labels\" for details.\n"                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "A canonical Address name can exclusively be the name of one or more A records, can exclusively be the name or\n"       \
+       "one or more AAAA records, or can be the name of both A and AAAA records. Address names that contain an IPv4\n"         \
+       "label have at least one A record, but no AAAA records. Address names that contain an IPv6 label, have at least\n"      \
+       "one AAAA record, but no A records. All other Address names have at least one A record and at least one AAAA\n"         \
+       "record. See \"Count Labels\" for how the number of address records for a given Address name is determined.\n"          \
+       "\n"                                                                                                                                                                                                                            \
+       "A records contain IPv4 addresses in the 203.0.113.0/24 block, while AAAA records contain IPv6 addresses in the\n"      \
+       "2001:db8:1::/120 block. Both of these address blocks are reserved for documentation. See\n"                                            \
+       "<https://tools.ietf.org/html/rfc5737> and <https://tools.ietf.org/html/rfc3849>.\n"                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "SRV names are names of SRV records.\n"                                                                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "Unless otherwise specified, all resource records will use a default TTL. The default TTL can be set with the\n"        \
+       "--defaultTTL option. See \"Alias-TTL Labels\" and \"TTL Labels\" for details on how to query for CNAME, A, and\n"      \
+       "AAAA records with specific TTL values.\n"
+
+#define kDNSServerInfoText_AliasLabel                                                                                                                                                                  \
+       "Alias labels are of the form \"alias\" or \"alias-N\", where N is an integer in [2, 2^31 - 1].\n"                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an Address name and its first label is Alias label \"alias-N\", then the response will contain\n"          \
+       "exactly N CNAME records:\n"                                                                                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. For each i in [3, N], the response will contain a CNAME record whose name is identical to QNAME, except\n"      \
+       "       that the first label is \"alias-i\" instead, and whose RDATA is the name of the other CNAME record whose\n"     \
+       "       name has \"alias-(i - 1)\" as its first label.\n"                                                                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n"       \
+       "       is \"alias-2\" instead, and whose RDATA is the name identical to QNAME, except that the first label is\n"       \
+       "       \"alias\" instead.\n"                                                                                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "    3. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n"       \
+       "       is \"alias\" instead, and whose RDATA is the name identical to QNAME minus its first label.\n"                          \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an Address name and its first label is Alias label \"alias\", then the response will contain a\n"          \
+       "single CNAME record. The CNAME record's name will be equal to QNAME and its RDATA will be the name identical to\n"     \
+       "QNAME minus its first label.\n"                                                                                                                                                                        \
+       "\n"                                                                                                                                                                                                                            \
+       "Example. A response to a query with a QNAME of alias-3.count-5.d.test will contain the following CNAME\n"                      \
+       "records:\n"                                                                                                                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "    alias-4.count-5.d.test.                        60    IN CNAME alias-3.count-5.d.test.\n"                                           \
+       "    alias-3.count-5.d.test.                        60    IN CNAME alias-2.count-5.d.test.\n"                                           \
+       "    alias-2.count-5.d.test.                        60    IN CNAME alias.count-5.d.test.\n"                                                     \
+       "    alias.count-5.d.test.                          60    IN CNAME count-5.d.test.\n"
+
+#define kDNSServerInfoText_AliasTTLLabel                                                                                                                                                               \
+       "Alias-TTL labels are of the form \"alias-ttl-T_1[-T_2[...-T_N]]\", where each T_i is an integer in\n"                          \
+       "[0, 2^31 - 1] and N is a positive integer bounded by the size of the maximum legal label length (63 octets).\n"        \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an Address name and its first label is Alias-TTL label \"alias-ttl-T_1...-T_N\", then the response\n"      \
+       "will contain exactly N CNAME records:\n"                                                                                                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. For each i in [1, N - 1], the response will contain a CNAME record whose name is identical to QNAME,\n"         \
+       "       except that the first label is \"alias-ttl-T_i...-T_N\" instead, whose TTL value is T_i, and whose RDATA\n"     \
+       "       is the name of the other CNAME record whose name has \"alias-ttl-T_(i+1)...-T_N\" as its first label.\n"        \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. The response will contain a CNAME record whose name is identical to QNAME, except that the first label\n"       \
+       "       is \"alias-ttl-T_N\", whose TTL is T_N, and whose RDATA is identical to QNAME stripped of its first\n"          \
+       "       label.\n"                                                                                                                                                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "Example. A response to a query with a QNAME of alias-ttl-20-40-80.count-5.d.test will contain the following\n"         \
+       "CNAME records:\n"                                                                                                                                                                                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "    alias-ttl-20-40-80.count-5.d.test.             20    IN CNAME alias-ttl-40-80.count-5.d.test.\n"                           \
+       "    alias-ttl-40-80.count-5.d.test.                40    IN CNAME alias-ttl-80.count-5.d.test.\n"                                      \
+       "    alias-ttl-80.count-5.d.test.                   80    IN CNAME count-5.d.test.\n"
+
+#define kDNSServerInfoText_CountLabel                                                                                                                                                                  \
+       "Count labels are of the form \"count-N_1\" or \"count-N_1-N_2\", where N_1 is an integer in [1, 255] and N_2 is\n"     \
+       "an integer in [N_1, 255].\n"                                                                                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an Address name, contains Count label \"count-N\", and has the type of address records specified by\n"     \
+       "QTYPE, then the response will contain exactly N address records:\n"                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. For i in [1, N], the response will contain an address record of type QTYPE whose name is equal to QNAME\n"      \
+       "       and whose RDATA is an address equal to a constant base address + i.\n"                                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. The address records will be ordered by the address contained in RDATA in ascending order.\n"                            \
+       "\n"                                                                                                                                                                                                                            \
+       "Example. A response to an A record query with a QNAME of alias.count-3.d.test will contain the following A\n"          \
+       "records:\n"                                                                                                                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "    count-3.d.test.                                60    IN A     203.0.113.1\n"                                                                       \
+       "    count-3.d.test.                                60    IN A     203.0.113.2\n"                                                                       \
+       "    count-3.d.test.                                60    IN A     203.0.113.3\n"                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an Address name, contains Count label \"count-N_1-N_2\", and has the type of address records\n"            \
+       "specified by QTYPE, then the response will contain exactly N_1 address records:\n"                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. Each of the address records will be of type QTYPE, have name equal to QNAME, and have as its RDATA a\n"         \
+       "       unique address equal to a constant base address + i, where i is a randomly chosen integer in [1, N_2].\n"       \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. The order of the address records will be random.\n"                                                                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "Example. A response to a AAAA record query with a QNAME of count-3-100.ttl-20.d.test could contain the\n"                      \
+       "following AAAA records:\n"                                                                                                                                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "    count-3-100.ttl-20.d.test.                     20    IN AAAA  2001:db8:1::c\n"                                                                     \
+       "    count-3-100.ttl-20.d.test.                     20    IN AAAA  2001:db8:1::3a\n"                                                            \
+       "    count-3-100.ttl-20.d.test.                     20    IN AAAA  2001:db8:1::4f\n"                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an Address name, but doesn't have the type of address records specified by QTYPE, then the response\n"     \
+       "will contain no address records, regardless of whether it contains a Count label.\n"                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "Address names that don't have a Count label are treated as though they contain a count label equal to\n"                       \
+       "count-1\".\n"
+
+#define kDNSServerInfoText_TagLabel                                                                                                                                                                            \
+       "Tag labels are labels prefixed with \"tag-\" and contain zero or more arbitrary octets after the prefix.\n"            \
+       "\n"                                                                                                                                                                                                                            \
+       "This type of label exists to allow testers to \"uniquify\" domain names. Tag labels can also serve as padding\n"       \
+       "to increase the sizes of domain names.\n"
+
+#define kDNSServerInfoText_TTLLabel                                                                                                                                                                            \
+       "TTL labels are of the form \"ttl-T\", where T is an integer in [0, 2^31 - 1].\n"                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an Address name and contains TTL label \"ttl-T\", then all non-CNAME records contained in the\n"           \
+       "response will have a TTL value equal to T.\n"
+
+#define kDNSServerInfoText_IPv4Label \
+       "The IPv4 label is \"ipv4\". See \"Resource Records\" for the affect of this label.\n"
+
+#define kDNSServerInfoText_IPv6Label \
+       "The IPv6 label is \"ipv6\". See \"Resource Records\" for the affect of this label.\n"
+
+#define kDNSServerInfoText_SRVNames                                                                                                                                                                            \
+       "SRV labels are of the form \"srv-R-W-P\", where R, W, and P are integers in [0, 2^16 - 1].\n"                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "After the first two labels, i.e., the service and protocol labels, the sequence of labels, which may be empty,\n"      \
+       "leading up to the the first SRV label, if one exists, or the d.test. labels will be used as a parent domain for\n"     \
+       "the target hostname of each of the SRV name's SRV records.\n"                                                                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "If QNAME is an SRV name and QTYPE is SRV, then for each SRV label, the response will contain an SRV record with\n"     \
+       "priority R, weight W, port P, and target hostname <target>[.<parent domain>]., where <target> is the sequence\n"       \
+       "of labels, which may be empty, that follows the SRV label leading up to either the next SRV label or the\n"            \
+       "d.test. labels, whichever comes first.\n"                                                                                                                                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "Example. A response to an SRV record query with a QNAME of\n"                                                                                                          \
+       "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test. will contain the following SRV records:\n"                      \
+       "\n"                                                                                                                                                                                                                            \
+       "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test.     60    IN SRV   0 0 80 www.example.com.\n"           \
+       "_http._tcp.example.com.srv-0-0-80.www.srv-1-0-8080.www.d.test.     60    IN SRV   1 0 8080 www.example.com.\n"
+
+#define kDNSServerInfoText_BadUDPMode \
+       "The purpose of Bad UDP mode is to test mDNSResponder's TCP fallback mechanism by which mDNSResponder reissues a\n"     \
+       "UDP query as a TCP query if the UDP response contains the expected QNAME, QTYPE, and QCLASS, but a message ID\n"       \
+       "that's not equal to the query's message ID.\n"                                                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "This mode is identical to the normal mode except that all responses sent via UDP have a message ID equal to the\n"     \
+       "query's message ID plus one. Also, in this mode, to aid in debugging, A records in responses sent via UDP have\n"      \
+       "IPv4 addresses in the 0.0.0.0/24 block instead of the 203.0.113.0/24 block, i.e., 0.0.0.0 is used as the IPv4\n"       \
+       "base address, and AAAA records in responses sent via UDP have IPv6 addresses in the ::ffff:0:0/120 block\n"            \
+       "instead of the 2001:db8:1::/120 block, i.e., ::ffff:0:0 is used as the IPv6 base address.\n"
+
+static int                             gDNSServer_LoopbackOnly         = false;
+static int                             gDNSServer_Foreground           = false;
+static int                             gDNSServer_ResponseDelayMs      = 0;
+static int                             gDNSServer_DefaultTTL           = 60;
+static int                             gDNSServer_Port                         = kDNSPort;
+static const char *            gDNSServer_DomainOverride       = NULL;
+#if( TARGET_OS_DARWIN )
+static const char *            gDNSServer_FollowPID            = NULL;
+#endif
+static int                             gDNSServer_BadUDPMode           = false;
+
+static CLIOption               kDNSServerOpts[] =
+{
+       BooleanOption( 'l', "loopback",      &gDNSServer_LoopbackOnly,    "Bind to to the loopback interface." ),
+       BooleanOption( 'f', "foreground",    &gDNSServer_Foreground,      "Direct log output to stdout instead of system logging." ),
+       IntegerOption( 'd', "responseDelay", &gDNSServer_ResponseDelayMs, "ms", "The amount of additional delay in milliseconds to apply to responses. (default: 0)", false ),
+       IntegerOption(  0 , "defaultTTL",    &gDNSServer_DefaultTTL,      "seconds", "Resource record TTL value to use when unspecified. (default: 60)", false ),
+       IntegerOption( 'p', "port",          &gDNSServer_Port,            "port number", "UDP/TCP port number to use. Use 0 for any port. (default: 53)", false ),
+       StringOption(   0 , "domain",        &gDNSServer_DomainOverride,  "domain", "Used to override 'd.test.' as the server's domain.", false ),
+#if( TARGET_OS_DARWIN )
+       StringOption(   0 , "follow",        &gDNSServer_FollowPID,       "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
+#endif
+       BooleanOption(  0 , "badUDPMode",    &gDNSServer_BadUDPMode,      "Run in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
+       
+       CLI_SECTION( "Intro",                           kDNSServerInfoText_Intro ),
+       CLI_SECTION( "Name Existence",          kDNSServerInfoText_NameExistence ),
+       CLI_SECTION( "Resource Records",        kDNSServerInfoText_ResourceRecords ),
+       CLI_SECTION( "Alias Labels",            kDNSServerInfoText_AliasLabel ),
+       CLI_SECTION( "Alias-TTL Labels",        kDNSServerInfoText_AliasTTLLabel ),
+       CLI_SECTION( "Count Labels",            kDNSServerInfoText_CountLabel ),
+       CLI_SECTION( "Tag Labels",                      kDNSServerInfoText_TagLabel ),
+       CLI_SECTION( "TTL Labels",                      kDNSServerInfoText_TTLLabel ),
+       CLI_SECTION( "IPv4 Label",                      kDNSServerInfoText_IPv4Label ),
+       CLI_SECTION( "IPv6 Label",                      kDNSServerInfoText_IPv6Label ),
+       CLI_SECTION( "SRV Names",                       kDNSServerInfoText_SRVNames ),
+       CLI_SECTION( "Bad UDP Mode",            kDNSServerInfoText_BadUDPMode ),
+       CLI_OPTION_END()
+};
+
+static void    DNSServerCmd( void );
+
+//===========================================================================================================================
+//     MDNSReplier Command Options
+//===========================================================================================================================
+
+#define kMDNSReplierPortBase           50000
+
+#define kMDNSReplierInfoText_Intro                                                                                                                                                                             \
+       "The mDNS replier answers mDNS queries for its authoritative records. These records are of class IN and of types\n"     \
+       "PTR, SRV, TXT, A, and AAAA as described below.\n"                                                                                                                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "Note: Sub-strings representing integers in domain name labels are in decimal notation and without leading zeros.\n"
+
+#define kMDNSReplierInfoText_Parameters                                                                                                                                                                        \
+       "There are five parameters that control the replier's set of authoritative records.\n"                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. <hostname> is the base name used for service instance names and the names of A and AAAA records. This\n"        \
+       "       parameter is specified with the --hostname option.\n"                                                                                                           \
+       "    2. <tag> is an arbitrary string used to uniquify service types. This parameter is specified with the --tag\n"      \
+       "       option.\n"                                                                                                                                                                                                      \
+       "    3. N_max in an integer in [1, 65535] and limits service types to those that have no more than N_max\n"                     \
+       "       instances. It also limits the number of hostnames to N_max, i.e., <hostname>.local.,\n"                                         \
+       "       <hostname>-1.local., ..., <hostname>-N_max.local. This parameter is specified with the\n"                                       \
+       "       --maxInstanceCount option.\n"                                                                                                                                                           \
+       "    4. N_a is an integer in [1, 255] and the number of A records per hostname. This parameter is specified\n"          \
+       "       with the --countA option.\n"                                                                                                                                                            \
+       "    5. N_aaaa is an integer in [1, 255] and the number of AAAA records per hostname. This parameter is\n"                      \
+       "       specified with the --countAAAA option.\n"
+
+#define kMDNSReplierInfoText_PTR                                                                                                                                                                               \
+       "The replier's authoritative PTR records have names of the form _t-<tag>-<L>-<N>._tcp.local., where L is an\n"          \
+       "integer in [1, 65535], and N is an integer in [1, N_max].\n"                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "For a given L and N, the replier has exactly N authoritative PTR records:\n"                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. The first PTR record is defined as\n"                                                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:  _t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                                         \
+       "        TYPE:  PTR\n"                                                                                                                                                                                          \
+       "        CLASS: IN\n"                                                                                                                                                                                           \
+       "        TTL:   4500\n"                                                                                                                                                                                         \
+       "        RDATA: <hostname>._t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                      \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. For each i in [2, N], there is one PTR record defined as\n"                                                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:  _t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                                         \
+       "        TYPE:  PTR\n"                                                                                                                                                                                          \
+       "        CLASS: IN\n"                                                                                                                                                                                           \
+       "        TTL:   4500\n"                                                                                                                                                                                         \
+       "        RDATA: \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"
+
+#define kMDNSReplierInfoText_SRV                                                                                                                                                                               \
+       "The replier's authoritative SRV records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n"        \
+       "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n"            \
+       "\"<hostname> (<i>)\", where i is in [2, N].\n"                                                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "For a given L and N, the replier has exactly N authoritative SRV records:\n"                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. The first SRV record is defined as\n"                                                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:  <hostname>._t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                                      \
+       "        TYPE:  SRV\n"                                                                                                                                                                                          \
+       "        CLASS: IN\n"                                                                                                                                                                                           \
+       "        TTL:   120\n"                                                                                                                                                                                          \
+       "        RDATA:\n"                                                                                                                                                                                                      \
+       "            Priority: 0\n"                                                                                                                                                                                     \
+       "            Weight:   0\n"                                                                                                                                                                                     \
+       "            Port:     (50000 + L) mod 2^16\n"                                                                                                                                          \
+       "            Target:   <hostname>.local.\n"                                                                                                                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. For each i in [2, N], there is one SRV record defined as:\n"                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:  \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"                                                                                            \
+       "        TYPE:  SRV\n"                                                                                                                                                                                          \
+       "        CLASS: IN\n"                                                                                                                                                                                           \
+       "        TTL:   120\n"                                                                                                                                                                                          \
+       "        RDATA:\n"                                                                                                                                                                                                      \
+       "            Priority: 0\n"                                                                                                                                                                                     \
+       "            Weight:   0\n"                                                                                                                                                                                     \
+       "            Port:     (50000 + L) mod 2^16\n"                                                                                                                                          \
+       "            Target:   <hostname>-<i>.local.\n"
+
+#define kMDNSReplierInfoText_TXT                                                                                                                                                                               \
+       "The replier's authoritative TXT records have names of the form <instance name>._t-<tag>-<L>-<N>._tcp.local.,\n"        \
+       "where L is an integer in [1, 65535], N is an integer in [1, N_max], and <instance name> is <hostname> or\n"            \
+       "\"<hostname> (<i>)\", where i is in [2, N].\n"                                                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "For a given L and N, the replier has exactly N authoritative TXT records:\n"                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. The first TXT record is defined as\n"                                                                                                                                           \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:     <hostname>._t-<tag>-<L>-<N>._tcp.local.\n"                                                                                                           \
+       "        TYPE:     TXT\n"                                                                                                                                                                                       \
+       "        CLASS:    IN\n"                                                                                                                                                                                        \
+       "        TTL:      4500\n"                                                                                                                                                                                      \
+       "        RDLENGTH: L\n"                                                                                                                                                                                         \
+       "        RDATA:    <one or more strings with an aggregate length of L octets>\n"                                                                        \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. For each i in [2, N], there is one TXT record:\n"                                                                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:     \"<hostname> (<i>)._t-<tag>-<L>-<N>._tcp.local.\"\n"                                                                                         \
+       "        TYPE:     TXT\n"                                                                                                                                                                                       \
+       "        CLASS:    IN\n"                                                                                                                                                                                        \
+       "        TTL:      4500\n"                                                                                                                                                                                      \
+       "        RDLENGTH: L\n"                                                                                                                                                                                         \
+       "        RDATA:    <one or more strings with an aggregate length of L octets>\n"                                                                        \
+       "\n"                                                                                                                                                                                                                            \
+       "The RDATA of each TXT record is exactly L octets and consists of a repeating series of the 15-byte string\n"           \
+       "\"hash=0x<32-bit FNV-1 hash of the record name as an 8-character hexadecimal string>\". The last instance of\n"        \
+       "the string may be truncated to satisfy the TXT record data's size requirement.\n"
+
+#define kMDNSReplierInfoText_A                                                                                                                                                                                 \
+       "The replier has exactly N_max x N_a authoritative A records:\n"                                                                                                        \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. For each j in [1, N_a], an A record is defined as\n"                                                                                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:     <hostname>.local.\n"                                                                                                                                                         \
+       "        TYPE:     A\n"                                                                                                                                                                                         \
+       "        CLASS:    IN\n"                                                                                                                                                                                        \
+       "        TTL:      120\n"                                                                                                                                                                                       \
+       "        RDLENGTH: 4\n"                                                                                                                                                                                         \
+       "        RDATA:    0.0.1.<j>\n"                                                                                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. For each i in [2, N_max], for each j in [1, N_a], an A record is defined as\n"                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:     <hostname>-<i>.local.\n"                                                                                                                                                     \
+       "        TYPE:     A\n"                                                                                                                                                                                         \
+       "        CLASS:    IN\n"                                                                                                                                                                                        \
+       "        TTL:      120\n"                                                                                                                                                                                       \
+       "        RDLENGTH: 4\n"                                                                                                                                                                                         \
+       "        RDATA:    0.<ceil(i / 256)>.<i mod 256>.<j>\n"
+
+#define kMDNSReplierInfoText_AAAA                                                                                                                                                                              \
+       "The replier has exactly N_max x N_aaaa authoritative AAAA records:\n"                                                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "    1. For each j in [1, N_aaaa], a AAAA record is defined as\n"                                                                                                       \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:     <hostname>.local.\n"                                                                                                                                                         \
+       "        TYPE:     AAAA\n"                                                                                                                                                                                      \
+       "        CLASS:    IN\n"                                                                                                                                                                                        \
+       "        TTL:      120\n"                                                                                                                                                                                       \
+       "        RDLENGTH: 16\n"                                                                                                                                                                                        \
+       "        RDATA:    2001:db8:2::1:<j>\n"                                                                                                                                                         \
+       "\n"                                                                                                                                                                                                                            \
+       "    2. For each i in [2, N_max], for each j in [1, N_aaaa], a AAAA record is defined as\n"                                                     \
+       "\n"                                                                                                                                                                                                                            \
+       "        NAME:     <hostname>-<i>.local.\n"                                                                                                                                                     \
+       "        TYPE:     AAAA\n"                                                                                                                                                                                      \
+       "        CLASS:    IN\n"                                                                                                                                                                                        \
+       "        TTL:      120\n"                                                                                                                                                                                       \
+       "        RDLENGTH: 16\n"                                                                                                                                                                                        \
+       "        RDATA:    2001:db8:2::<i>:<j>\n"
+
+#define kMDNSReplierInfoText_Responses                                                                                                                                                                 \
+       "When generating answers for a query message, any two records pertaining to the same hostname will be grouped\n"        \
+       "together in the same response message, and any two records pertaining to different hostnames will be in\n"                     \
+       "separate response messages.\n"
+
+static const char *            gMDNSReplier_Hostname                   = NULL;
+static const char *            gMDNSReplier_ServiceTypeTag             = NULL;
+static int                             gMDNSReplier_MaxInstanceCount   = 1000;
+static int                             gMDNSReplier_NoAdditionals              = false;
+static int                             gMDNSReplier_RecordCountA               = 1;
+static int                             gMDNSReplier_RecordCountAAAA    = 1;
+static double                  gMDNSReplier_UnicastDropRate    = 0.0;
+static double                  gMDNSReplier_MulticastDropRate  = 0.0;
+static int                             gMDNSReplier_MaxDropCount               = 0;
+static int                             gMDNSReplier_UseIPv4                    = false;
+static int                             gMDNSReplier_UseIPv6                    = false;
+static int                             gMDNSReplier_Foreground                 = false;
+static const char *            gMDNSReplier_FollowPID              = NULL;
+
+static CLIOption               kMDNSReplierOpts[] =
+{
+       StringOption(  'i', "interface",        &gInterface,                     "name or index", "Network interface by name or index.", true ),
+       StringOption(  'n', "hostname",         &gMDNSReplier_Hostname,          "string", "Base name to use for hostnames and service instance names.", true ),
+       StringOption(  't', "tag",              &gMDNSReplier_ServiceTypeTag,    "string", "Tag to use for service types, e.g., _t-<tag>-<TXT size>-<count>._tcp.", true ),
+       IntegerOption( 'c', "maxInstanceCount", &gMDNSReplier_MaxInstanceCount,  "count", "Maximum number of service instances. (default: 1000)", false ),
+       BooleanOption(  0 , "noAdditionals",    &gMDNSReplier_NoAdditionals,     "When answering queries, don't include any additional records." ),
+       IntegerOption(  0 , "countA",           &gMDNSReplier_RecordCountA,      "count", "Number of A records per hostname. (default: 1)", false ),
+       IntegerOption(  0 , "countAAAA",        &gMDNSReplier_RecordCountAAAA,   "count", "Number of AAAA records per hostname. (default: 1)", false ),
+       DoubleOption(   0 , "udrop",            &gMDNSReplier_UnicastDropRate,   "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
+       DoubleOption(   0 , "mdrop",            &gMDNSReplier_MulticastDropRate, "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
+       IntegerOption(  0 , "maxDropCount",     &gMDNSReplier_MaxDropCount,      "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
+       BooleanOption(  0 , "ipv4",             &gMDNSReplier_UseIPv4,           "Use IPv4." ),
+       BooleanOption(  0 , "ipv6",             &gMDNSReplier_UseIPv6,           "Use IPv6." ),
+       BooleanOption( 'f', "foreground",       &gMDNSReplier_Foreground,        "Direct log output to stdout instead of system logging." ),
+#if( TARGET_OS_DARWIN )
+       StringOption(   0 , "follow",           &gMDNSReplier_FollowPID,         "pid", "Exit when the process, usually the parent process, specified by PID exits.", false ),
+#endif
+       
+       CLI_SECTION( "Intro",                                                   kMDNSReplierInfoText_Intro ),
+       CLI_SECTION( "Authoritative Record Parameters", kMDNSReplierInfoText_Parameters ),
+       CLI_SECTION( "Authoritative PTR Records",               kMDNSReplierInfoText_PTR ),
+       CLI_SECTION( "Authoritative SRV Records",               kMDNSReplierInfoText_SRV ),
+       CLI_SECTION( "Authoritative TXT Records",               kMDNSReplierInfoText_TXT ),
+       CLI_SECTION( "Authoritative A Records",                 kMDNSReplierInfoText_A ),
+       CLI_SECTION( "Authoritative AAAA Records",              kMDNSReplierInfoText_AAAA ),
+       CLI_SECTION( "Responses",                                               kMDNSReplierInfoText_Responses ),
+       CLI_OPTION_END()
+};
+
+static void    MDNSReplierCmd( void );
+
+//===========================================================================================================================
+//     Test Command Options
+//===========================================================================================================================
+
+#define kTestExitStatusSection_Name            "Exit Status"
+#define kTestExitStatusSection_Text                                                                                                                                                                            \
+       "This test command can exit with one of three status codes:\n"                                                                                                          \
+       "\n"                                                                                                                                                                                                                            \
+       "0 - The test ran to completion and passed.\n"                                                                                                                                          \
+       "1 - A fatal error prevented the test from completing.\n"                                                                                                                       \
+       "2 - The test ran to completion, but it or a subtest failed. See test output for details.\n"                                            \
+       "\n"                                                                                                                                                                                                                            \
+       "Note: The pass/fail status applies to the correctness or results. It does not necessarily imply anything about\n"      \
+       "performance.\n"
+
+#define TestExitStatusSection()                CLI_SECTION( kTestExitStatusSection_Name, kTestExitStatusSection_Text )
+
+#define kGAIPerfTestSuiteName_Basic                    "basic"
+#define kGAIPerfTestSuiteName_Advanced         "advanced"
+
+static const char *            gGAIPerf_TestSuite                              = NULL;
+static int                             gGAIPerf_CallDelayMs                    = 10;
+static int                             gGAIPerf_ServerDelayMs                  = 10;
+static int                             gGAIPerf_SkipPathEvalulation    = false;
+static int                             gGAIPerf_BadUDPMode                             = false;
+static int                             gGAIPerf_IterationCount                 = 100;
+static int                             gGAIPerf_IterationTimeLimitMs   = 100;
+static const char *            gGAIPerf_OutputFilePath                 = NULL;
+static const char *            gGAIPerf_OutputFormat                   = kOutputFormatStr_JSON;
+static int                             gGAIPerf_OutputAppendNewline    = false;
+
+static void    GAIPerfCmd( void );
+
+#define kGAIPerfSectionText_TestSuiteBasic                                                                                                                                                                     \
+       "This test suite consists of the following three test cases:\n"                                                                                                                 \
+       "\n"                                                                                                                                                                                                                                    \
+       "Test Case #1: Resolve a domain name with\n"                                                                                                                                                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "    2 CNAME records, 4 A records, and 4 AAAA records\n"                                                                                                                                \
+       "\n"                                                                                                                                                                                                                                    \
+       "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n"             \
+       "server queries.\n"                                                                                                                                                                                                             \
+       "\n"                                                                                                                                                                                                                                    \
+       "Test Case #2: Resolve a domain name with\n"                                                                                                                                                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "    2 CNAME records, 4 A records, and 4 AAAA records\n"                                                                                                                                \
+       "\n"                                                                                                                                                                                                                                    \
+       "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n"             \
+       "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n"              \
+       "which should ideally require no additional server queries, i.e., the results should come from the cache.\n"                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n"               \
+       "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n"             \
+       "domain name in the preliminary iteration isn't counted in the performance stats.\n"                                                                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "Test Case #3: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
+
+#define kGAIPerfSectionText_TestSuiteAdvanced                                                                                                                                                          \
+       "This test suite consists of 33 test cases. Test cases 1 through 32 can be described in the following way\n"                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "Test Case #N (where N is in [1, 32] and odd): Resolve a domain name with\n"                                                                                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "    N_c CNAME records, N_a A records, and N_a AAAA records\n"                                                                                                                  \
+       "\n"                                                                                                                                                                                                                                    \
+       "to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which requires\n"             \
+       "server queries.\n"                                                                                                                                                                                                             \
+       "\n"                                                                                                                                                                                                                                    \
+       "Test Case #N (where N is in [1, 32] and even): Resolve a domain name with\n"                                                                                   \
+       "\n"                                                                                                                                                                                                                                    \
+       "    N_c CNAME records, N_a A records, and N_a AAAA records\n"                                                                                                                  \
+       "\n"                                                                                                                                                                                                                                    \
+       "to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which\n"             \
+       "requires server queries. Each subsequent iteration resolves the same domain name as the preliminary iteration,\n"              \
+       "which should ideally require no additional server queries, i.e., the results should come from the cache.\n"                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "Unlike the preceding test case, this test case is concerned with DNSServiceGetAddrInfo() performance when the\n"               \
+       "records of the domain name being resolved are already in the cache. Therefore, the time required to resolve the\n"             \
+       "domain name in the preliminary iteration isn't counted in the performance stats.\n"                                                                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "N_c and N_a take on the following values, depending on the value of N:\n"                                                                                              \
+       "\n"                                                                                                                                                                                                                                    \
+       "    N_c is 0 if N is in [1, 8].\n"                                                                                                                                                                             \
+       "    N_c is 1 if N is in [9, 16].\n"                                                                                                                                                                    \
+       "    N_c is 2 if N is in [17, 24].\n"                                                                                                                                                                   \
+       "    N_c is 4 if N is in [25, 32].\n"                                                                                                                                                                   \
+       "\n"                                                                                                                                                                                                                                    \
+       "    N_a is 1 if N mod 8 is 1 or 2.\n"                                                                                                                                                                  \
+       "    N_a is 2 if N mod 8 is 3 or 4.\n"                                                                                                                                                                  \
+       "    N_a is 4 if N mod 8 is 5 or 6.\n"                                                                                                                                                                  \
+       "    N_a is 8 if N mod 8 is 7 or 0.\n"                                                                                                                                                                  \
+       "\n"                                                                                                                                                                                                                                    \
+       "Finally,\n"                                                                                                                                                                                                                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "Test Case #33: Each iteration resolves localhost to its IPv4 and IPv6 addresses.\n"
+
+static CLIOption               kGAIPerfOpts[] =
+{
+       StringOptionEx( 's', "suite",         &gGAIPerf_TestSuite,            "name", "Name of the predefined test suite to run.", true,
+               "\n"
+               "There are currently two predefined test suites, '" kGAIPerfTestSuiteName_Basic "' and '" kGAIPerfTestSuiteName_Advanced "', which are described below.\n"
+               "\n"
+       ),
+       StringOption(   'o', "output",        &gGAIPerf_OutputFilePath,       "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+       FormatOption(   'f', "format",        &gGAIPerf_OutputFormat,         "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+       BooleanOption(  'n', "appendNewline", &gGAIPerf_OutputAppendNewline,  "If the output format is JSON, output a trailing newline character." ),
+       IntegerOption(  'i', "iterations",    &gGAIPerf_IterationCount,       "count", "The number of iterations per test case. (default: 100)", false ),
+       IntegerOption(  'l', "timeLimit",     &gGAIPerf_IterationTimeLimitMs, "ms", "Time limit for each DNSServiceGetAddrInfo() operation in milliseconds. (default: 100)", false ),
+       IntegerOption(   0 , "callDelay",     &gGAIPerf_CallDelayMs,          "ms", "Time to wait before calling DNSServiceGetAddrInfo() in milliseconds. (default: 10)", false ),
+       BooleanOption(   0 , "skipPathEval",  &gGAIPerf_SkipPathEvalulation,  "Use kDNSServiceFlagsPathEvaluationDone when calling DNSServiceGetAddrInfo()." ),
+       
+       CLI_OPTION_GROUP( "DNS Server Options" ),
+       IntegerOption(   0 , "responseDelay", &gGAIPerf_ServerDelayMs,        "ms", "Additional delay in milliseconds to have the server apply to responses. (default: 10)", false ),
+       BooleanOption(   0 , "badUDPMode",    &gGAIPerf_BadUDPMode,           "Run server in Bad UDP mode to trigger mDNSResponder's TCP fallback mechanism." ),
+       
+       CLI_SECTION( "Test Suite \"Basic\"",    kGAIPerfSectionText_TestSuiteBasic ),
+       CLI_SECTION( "Test Suite \"Advanced\"", kGAIPerfSectionText_TestSuiteAdvanced ),
+       TestExitStatusSection(),
+       CLI_OPTION_END()
+};
+
+static void    MDNSDiscoveryTestCmd( void );
+
+static int                             gMDNSDiscoveryTest_InstanceCount                = 100;
+static int                             gMDNSDiscoveryTest_TXTSize                              = 100;
+static int                             gMDNSDiscoveryTest_BrowseTimeSecs               = 2;
+static int                             gMDNSDiscoveryTest_FlushCache                   = false;
+static char *                  gMDNSDiscoveryTest_Interface                    = NULL;
+static int                             gMDNSDiscoveryTest_NoAdditionals                = false;
+static int                             gMDNSDiscoveryTest_RecordCountA                 = 1;
+static int                             gMDNSDiscoveryTest_RecordCountAAAA              = 1;
+static double                  gMDNSDiscoveryTest_UnicastDropRate              = 0.0;
+static double                  gMDNSDiscoveryTest_MulticastDropRate    = 0.0;
+static int                             gMDNSDiscoveryTest_MaxDropCount                 = 0;
+static int                             gMDNSDiscoveryTest_UseIPv4                              = false;
+static int                             gMDNSDiscoveryTest_UseIPv6                              = false;
+static const char *            gMDNSDiscoveryTest_OutputFormat                 = kOutputFormatStr_JSON;
+static int                             gMDNSDiscoveryTest_OutputAppendNewline  = false;
+static const char *            gMDNSDiscoveryTest_OutputFilePath               = NULL;
+
+static CLIOption               kMDNSDiscoveryTestOpts[] =
+{
+       IntegerOption( 'c', "instanceCount",  &gMDNSDiscoveryTest_InstanceCount,       "count", "Number of service instances to discover. (default: 100)", false ),
+       IntegerOption( 's', "txtSize",        &gMDNSDiscoveryTest_TXTSize,             "bytes", "Desired size of each service instance's TXT record data. (default: 100)", false ),
+       IntegerOption( 'b', "browseTime",     &gMDNSDiscoveryTest_BrowseTimeSecs,      "seconds", "Amount of time to spend browsing in seconds. (default: 2)", false ),
+       BooleanOption(  0 , "flushCache",     &gMDNSDiscoveryTest_FlushCache,          "Flush mDNSResponder's record cache before browsing. Requires root privileges." ),
+       
+       CLI_OPTION_GROUP( "mDNS Replier Parameters" ),
+       StringOption(  'i', "interface",      &gMDNSDiscoveryTest_Interface,           "name or index", "Network interface. If unspecified, any available mDNS-capable interface will be used.", false ),
+       BooleanOption(  0 , "noAdditionals",  &gMDNSDiscoveryTest_NoAdditionals,       "When answering queries, don't include any additional records." ),
+       IntegerOption(  0 , "countA",         &gMDNSDiscoveryTest_RecordCountA,        "count", "Number of A records per hostname. (default: 1)", false ),
+       IntegerOption(  0 , "countAAAA",      &gMDNSDiscoveryTest_RecordCountAAAA,     "count", "Number of AAAA records per hostname. (default: 1)", false ),
+       DoubleOption(   0 , "udrop",          &gMDNSDiscoveryTest_UnicastDropRate,     "probability", "Probability of dropping a unicast response. (default: 0.0)", false ),
+       DoubleOption(   0 , "mdrop",          &gMDNSDiscoveryTest_MulticastDropRate,   "probability", "Probability of dropping a multicast query or response. (default: 0.0)", false ),
+       IntegerOption(  0 , "maxDropCount",   &gMDNSDiscoveryTest_MaxDropCount,        "count", "If > 0, drop probabilities are limted to first <count> responses from each instance. (default: 0)", false ),
+       BooleanOption(  0 , "ipv4",           &gMDNSDiscoveryTest_UseIPv4,             "Use IPv4." ),
+       BooleanOption(  0 , "ipv6",           &gMDNSDiscoveryTest_UseIPv6,             "Use IPv6." ),
+       
+       CLI_OPTION_GROUP( "Results" ),
+       FormatOption(   'f', "format",        &gMDNSDiscoveryTest_OutputFormat,        "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+       StringOption(   'o', "output",        &gMDNSDiscoveryTest_OutputFilePath,      "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+       
+       TestExitStatusSection(),
+       CLI_OPTION_END()
+};
+
+static void    DotLocalTestCmd( void );
+
+static const char *            gDotLocalTest_Interface                 = NULL;
+static const char *            gDotLocalTest_OutputFormat              = kOutputFormatStr_JSON;
+static const char *            gDotLocalTest_OutputFilePath    = NULL;
+
+#define kDotLocalTestSubtestDesc_GAIMDNSOnly   "GAI for a dotlocal name that has only MDNS A and AAAA records."
+#define kDotLocalTestSubtestDesc_GAIDNSOnly            "GAI for a dotlocal name that has only DNS A and AAAA records."
+#define kDotLocalTestSubtestDesc_GAIBoth               "GAI for a dotlocal name that has both mDNS and DNS A and AAAA records."
+#define kDotLocalTestSubtestDesc_GAINeither            "GAI for a dotlocal name that has no A or AAAA records."
+#define kDotLocalTestSubtestDesc_GAINoSuchRecord \
+       "GAI for a dotlocal name that has no A or AAAA records, but is a subdomain name of a search domain."
+#define kDotLocalTestSubtestDesc_QuerySRV              "SRV query for a dotlocal name that has only a DNS SRV record."
+
+#define kDotLocalTestSectionText_Description                                                                                                                                                           \
+       "The goal of the dotlocal test is to verify that mDNSResponder properly handles queries for domain names in the\n"              \
+       "local domain when a local SOA record exists. As part of the test setup, a test DNS server and an mdnsreplier are\n"    \
+       "spawned, and a dummy local SOA record is registered with DNSServiceRegisterRecord(). The server is invoked such\n"             \
+       "that its domain is a second-level subdomain of the local domain, i.e., <some label>.local, while the mdnsreplier is\n" \
+       "invoked such that its base hostname is equal to the server's domain, e.g., if the server's domain is test.local.,\n"   \
+       "then the mdnsreplier's base hostname is test.local.\n"                                                                                                                                 \
+       "\n"                                                                                                                                                                                                                                    \
+       "The dotlocal test consists of six subtests that perform either a DNSServiceGetAddrInfo (GAI) operation for a\n"                \
+       "hostname in the local domain or a DNSServiceQueryRecord operation to query for an SRV record in the local domain:\n"   \
+       "\n"                                                                                                                                                                                                                                    \
+       "1. " kDotLocalTestSubtestDesc_GAIMDNSOnly              "\n"                                                                                                                                    \
+       "2. " kDotLocalTestSubtestDesc_GAIDNSOnly               "\n"                                                                                                                                    \
+       "3. " kDotLocalTestSubtestDesc_GAIBoth                  "\n"                                                                                                                                    \
+       "4. " kDotLocalTestSubtestDesc_GAINeither               "\n"                                                                                                                                    \
+       "5. " kDotLocalTestSubtestDesc_GAINoSuchRecord  "\n"                                                                                                                                    \
+       "6. " kDotLocalTestSubtestDesc_QuerySRV                 "\n"                                                                                                                                    \
+       "\n"                                                                                                                                                                                                                                    \
+       "Each subtest runs for five seconds.\n"
+
+static CLIOption               kDotLocalTestOpts[] =
+{
+       StringOption(  'i', "interface",     &gDotLocalTest_Interface,           "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
+       
+       CLI_OPTION_GROUP( "Results" ),
+       FormatOption(  'f', "format",        &gDotLocalTest_OutputFormat,        "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+       StringOption(  'o', "output",        &gDotLocalTest_OutputFilePath,      "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+       
+       CLI_SECTION( "Description", kDotLocalTestSectionText_Description ),
+       TestExitStatusSection(),
+       CLI_OPTION_END()
+};
+
+static void    ProbeConflictTestCmd( void );
+
+static const char *            gProbeConflictTest_Interface            = NULL;
+static int                             gProbeConflictTest_UseComputerName      = false;
+static const char *            gProbeConflictTest_OutputFormat         = kOutputFormatStr_JSON;
+static const char *            gProbeConflictTest_OutputFilePath       = NULL;
+
+static CLIOption               kProbeConflictTestOpts[] =
+{
+       StringOption(  'i', "interface",       &gProbeConflictTest_Interface,           "name or index", "mdnsreplier's network interface. If not set, any mDNS-capable interface will be used.", false ),
+       BooleanOption( 'c', "useComputerName", &gProbeConflictTest_UseComputerName,     "Use the device's \"computer name\" for the test service's name." ),
+       
+       CLI_OPTION_GROUP( "Results" ),
+       FormatOption(  'f', "format",          &gProbeConflictTest_OutputFormat,        "Specifies the test report output format. (default: " kOutputFormatStr_JSON ")", false ),
+       StringOption(  'o', "output",          &gProbeConflictTest_OutputFilePath,      "path", "Path of the file to write test report to instead of standard output (stdout).", false ),
+       
+       TestExitStatusSection(),
+       CLI_OPTION_END()
+};
+
+static void    RegistrationTestCmd( void );
+
+static int                             gRegistrationTest_BATSEnvironment       = false;
+static const char *            gRegistrationTest_OutputFormat          = kOutputFormatStr_JSON;
+static const char *            gRegistrationTest_OutputFilePath        = NULL;
+
+static CLIOption               kRegistrationTestOpts[] =
+{
+       CLI_OPTION_BOOLEAN( 0, "bats", &gRegistrationTest_BATSEnvironment, "Informs the test that it's running in a BATS environment.",
+               "\n"
+               "This option allows the test to take special measures while running in a BATS environment. Currently, this option\n"
+               "only has an effect on watchOS. Because it has been observed that the Wi-Fi interface sometimes goes down during\n"
+               "watchOS BATS testing, for watchOS, when a service is registered using kDNSServiceInterfaceIndexAny,\n"
+               "\n"
+               "    1. missing browse and query \"add\" results for Wi-Fi interfaces aren't enough for a subtest to fail; and\n"
+               "    2. unexpected browse and query results for Wi-Fi interfaces are ignored.\n"
+       ),
+       CLI_OPTION_GROUP( "Results" ),
+       FormatOption( 'f', "format", &gRegistrationTest_OutputFormat,   "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+       StringOption( 'o', "output", &gRegistrationTest_OutputFilePath, "path", "Path of the file to write test results to instead of standard output (stdout).", false ),
+       
+       TestExitStatusSection(),
+       CLI_OPTION_END()
+};
+
+static void ExpensiveConstrainedTestCmd( void );
+
+static const char *     gExpensiveConstrainedTest_Interface                 = NULL;
+static const char *     gExpensiveConstrainedTest_Name                      = NULL;
+static Boolean          gExpensiveConstrainedTest_DenyExpensive             = false;
+static Boolean          gExpensiveConstrainedTest_DenyConstrained           = false;
+static Boolean          gExpensiveConstrainedTest_StartFromExpensive        = false;
+static int              gExpensiveConstrainedTest_ProtocolIPv4              = false;
+static int              gExpensiveConstrainedTest_ProtocolIPv6              = false;
+static const char *     gExpensiveConstrainedTest_OutputFormat              = kOutputFormatStr_JSON;
+static const char *     gExpensiveConstrainedTest_OutputFilePath            = NULL;
+
+static CLIOption        kExpensiveConstrainedTestOpts[] =
+{
+    CLI_OPTION_GROUP( "Results" ),
+    FormatOption( 'f', "format", &gExpensiveConstrainedTest_OutputFormat,              "Specifies the test results output format. (default: " kOutputFormatStr_JSON ")", false ),
+    StringOption( 'o', "output", &gExpensiveConstrainedTest_OutputFilePath, "path",    "Path of the file to write test results to instead of standard output (stdout).", false ),
+
+    TestExitStatusSection(),
+    CLI_OPTION_END()
+};
+
+static CLIOption               kTestOpts[] =
+{
+       Command( "gaiperf",        GAIPerfCmd,           kGAIPerfOpts,            "Runs DNSServiceGetAddrInfo() performance tests.", false ),
+       Command( "mdnsdiscovery",  MDNSDiscoveryTestCmd, kMDNSDiscoveryTestOpts,  "Tests mDNS service discovery for correctness.", false ),
+       Command( "dotlocal",       DotLocalTestCmd,      kDotLocalTestOpts,       "Tests DNS and mDNS queries for domain names in the local domain.", false ),
+       Command( "probeconflicts", ProbeConflictTestCmd, kProbeConflictTestOpts,  "Tests various probing conflict scenarios.", false ),
+       Command( "registration",   RegistrationTestCmd,  kRegistrationTestOpts,   "Tests service registrations.", false ),
+    Command( "expensive_constrained_updates", ExpensiveConstrainedTestCmd, kExpensiveConstrainedTestOpts, "Tests if the mDNSResponder can handle expensive and constrained property change correctly", false),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     SSDP Command Options
+//===========================================================================================================================
+
+static int                             gSSDPDiscover_MX                        = 1;
+static const char *            gSSDPDiscover_ST                        = "ssdp:all";
+static int                             gSSDPDiscover_ReceiveSecs       = 1;
+static int                             gSSDPDiscover_UseIPv4           = false;
+static int                             gSSDPDiscover_UseIPv6           = false;
+static int                             gSSDPDiscover_Verbose           = false;
+
+static CLIOption               kSSDPDiscoverOpts[] =
+{
+       StringOption(  'i', "interface",        &gInterface,                            "name or index", "Network interface by name or index.", true ),
+       IntegerOption( 'm', "mx",                       &gSSDPDiscover_MX,                      "seconds", "MX value in search request, i.e., max response delay in seconds. (Default: 1 second)", false ),
+       StringOption(  's', "st",                       &gSSDPDiscover_ST,                      "string", "ST value in search request, i.e., the search target. (Default: \"ssdp:all\")", false ),
+       IntegerOption( 'r', "receiveTime",      &gSSDPDiscover_ReceiveSecs,     "seconds", "Amount of time to spend receiving responses. -1 means unlimited. (Default: 1 second)", false ),
+       BooleanOption(  0 , "ipv4",                     &gSSDPDiscover_UseIPv4,         "Use IPv4, i.e., multicast to 239.255.255.250:1900." ),
+       BooleanOption(  0 , "ipv6",                     &gSSDPDiscover_UseIPv6,         "Use IPv6, i.e., multicast to [ff02::c]:1900" ),
+       BooleanOption( 'v', "verbose",          &gSSDPDiscover_Verbose,         "Prints the search request(s) that were sent." ),
+       CLI_OPTION_END()
+};
+
+static void    SSDPDiscoverCmd( void );
+
+static CLIOption               kSSDPOpts[] =
+{
+       Command( "discover", SSDPDiscoverCmd, kSSDPDiscoverOpts, "Crafts and multicasts an SSDP search message.", false ),
+       CLI_OPTION_END()
+};
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+//     res_query Command Options
+//===========================================================================================================================
+
+static void    ResQueryCmd( void );
+
+static const char *            gResQuery_Name                  = NULL;
+static const char *            gResQuery_Type                  = NULL;
+static const char *            gResQuery_Class                 = NULL;
+static int                             gResQuery_UseLibInfo    = false;
+
+static CLIOption               kResQueryOpts[] =
+{
+       StringOption( 'n', "name",              &gResQuery_Name,                "domain name",  "Full domain name of record to query.", true ),
+       StringOption( 't', "type",              &gResQuery_Type,                "record type",  "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
+       StringOption( 'c', "class",             &gResQuery_Class,               "record class", "Record class by name or number. Default class is IN.", false ),
+       BooleanOption( 0 , "libinfo",   &gResQuery_UseLibInfo,  "Use res_query from libinfo instead of libresolv." ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     dns_query Command Options
+//===========================================================================================================================
+
+static void ResolvDNSQueryCmd( void );
+
+static const char *            gResolvDNSQuery_Name    = NULL;
+static const char *            gResolvDNSQuery_Type    = NULL;
+static const char *            gResolvDNSQuery_Class   = NULL;
+static const char *            gResolvDNSQuery_Path    = NULL;
+
+static CLIOption               kResolvDNSQueryOpts[] =
+{
+       StringOption( 'n', "name",      &gResolvDNSQuery_Name,  "domain name",  "Full domain name of record to query.", true ),
+       StringOption( 't', "type",      &gResolvDNSQuery_Type,  "record type",  "Record type by name (e.g., TXT, SRV, etc.) or number.", true ),
+       StringOption( 'c', "class",     &gResolvDNSQuery_Class, "record class", "Record class by name or number. Default class is IN.", false ),
+       StringOption( 'p', "path",      &gResolvDNSQuery_Path,  "file path",    "The path argument to pass to dns_open() before calling dns_query(). Default value is NULL.", false ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     CFHost Command Options
+//===========================================================================================================================
+
+static void    CFHostCmd( void );
+
+static const char *            gCFHost_Name            = NULL;
+static int                             gCFHost_WaitSecs        = 0;
+
+static CLIOption               kCFHostOpts[] =
+{
+       StringOption(  'n', "name", &gCFHost_Name,     "hostname", "Hostname to resolve.", true ),
+       IntegerOption( 'w', "wait", &gCFHost_WaitSecs, "seconds",  "Time in seconds to wait before a normal exit. (default: 0)", false ),
+       CLI_OPTION_END()
+};
+
+static CLIOption               kLegacyOpts[] =
+{
+       Command( "res_query", ResQueryCmd,       kResQueryOpts,       "Uses res_query() from either libresolv or libinfo to query for a record.", true ),
+       Command( "dns_query", ResolvDNSQueryCmd, kResolvDNSQueryOpts, "Uses dns_query() from libresolv to query for a record.", true ),
+       Command( "cfhost",    CFHostCmd,         kCFHostOpts,         "Uses CFHost to resolve a hostname.", true ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     DNSConfigAdd Command Options
+//===========================================================================================================================
+
+static void    DNSConfigAddCmd( void );
+
+static CFStringRef             gDNSConfigAdd_ID                        = NULL;
+static char **                 gDNSConfigAdd_IPAddrArray       = NULL;
+static size_t                  gDNSConfigAdd_IPAddrCount       = 0;
+static char **                 gDNSConfigAdd_DomainArray       = NULL;
+static size_t                  gDNSConfigAdd_DomainCount       = 0;
+static const char *            gDNSConfigAdd_Interface         = NULL;
+
+static CLIOption               kDNSConfigAddOpts[] =
+{
+       CFStringOption(     0 , "id",        &gDNSConfigAdd_ID,                                      "ID", "Arbitrary ID to use for resolver entry.", true ),
+       MultiStringOption( 'a', "address",   &gDNSConfigAdd_IPAddrArray, &gDNSConfigAdd_IPAddrCount, "IP address", "DNS server IP address(es). Can be specified more than once.", true ),
+       MultiStringOption( 'd', "domain",    &gDNSConfigAdd_DomainArray, &gDNSConfigAdd_DomainCount, "domain", "Specific domain(s) for the resolver entry. Can be specified more than once.", false ),
+       StringOption(      'i', "interface", &gDNSConfigAdd_Interface,                               "interface name", "Specific interface for the resolver entry.", false ),
+       
+       CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     DNSConfigRemove Command Options
+//===========================================================================================================================
+
+static void    DNSConfigRemoveCmd( void );
+
+static CFStringRef             gDNSConfigRemove_ID = NULL;
+
+static CLIOption               kDNSConfigRemoveOpts[] =
+{
+       CFStringOption( 0, "id", &gDNSConfigRemove_ID, "ID", "ID of resolver entry to remove.", true ),
+       
+       CLI_SECTION( "Notes", "Run 'scutil -d -v --dns' to see the current DNS configuration. See scutil(8) man page for more details.\n" ),
+       CLI_OPTION_END()
+};
+
+static CLIOption               kDNSConfigOpts[] =
+{
+       Command( "add",    DNSConfigAddCmd,    kDNSConfigAddOpts,    "Add a supplemental resolver entry to the system's DNS configuration.", true ),
+       Command( "remove", DNSConfigRemoveCmd, kDNSConfigRemoveOpts, "Remove a supplemental resolver entry from the system's DNS configuration.", true ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     XPCSend
+//===========================================================================================================================
+
+static void    XPCSendCmd( void );
+
+static const char *            gXPCSend_ServiceName    = NULL;
+static const char *            gXPCSend_MessageStr             = NULL;
+
+static const char              kXPCSendMessageSection_Name[] = "Message Argument";
+static const char              kXPCSendMessageSection_Text[] =
+       "XPC messages are described as a string using the following syntax.\n"
+       "\n"
+       "With the exception of the top-most XPC message dictionary, dictionaries begin with a '{' and end with a '}'.\n"
+       "Key-value pairs are of the form <key>=<value>, where <key> is a string and <value> is a value of any of the\n"
+       "currently supported XPC types.\n"
+       "\n"
+       "Arrays begin with a '[' and end with a ']'.\n"
+       "\n"
+       "The following non-container XPC types are supported:\n"
+       "\n"
+       "Type                              Syntax                      Example\n"
+       "bool                              bool:<string>               bool:true (or yes/y/on/1), bool:false (or no/n/off/0)\n"
+       "data                              data:<hex string>           data:C0000201\n"
+       "int64  (signed 64-bit integer)    int:<pos. or neg. integer>  int:-1\n"
+       "string                            string:<string>             string:hello\\ world\n"
+       "uint64 (unsigned 64-bit integer)  uint:<pos. integer>         uint:1024 or uint:0x400\n"
+       "UUID                              uuid:<UUID>                 uuid:dab10183-84b5-4859-9de6-4bee287cfea3\n"
+       "\n"
+       "Example 1: 'cmd=string:add make=string:Apple model=string:Macintosh aliases=[string:Mac string:Macintosh\\ 128K]'\n"
+       "Example 2: 'cmd=string:search features={portable=bool:yes solar=bool:no} priceMin=uint:100 priceMax=uint:200'\n";
+
+static CLIOption               kXPCSendOpts[] =
+{
+       StringOption( 's', "service", &gXPCSend_ServiceName, "service name", "XPC service name.", true ),
+       StringOption( 'm', "message", &gXPCSend_MessageStr,  "message",      "XPC message as a string.", true ),
+       
+       CLI_SECTION( kXPCSendMessageSection_Name, kXPCSendMessageSection_Text ),
+       CLI_OPTION_END()
+};
+#endif // TARGET_OS_DARWIN
+
+#if ( MDNSRESPONDER_PROJECT )
+//===========================================================================================================================
+//     InterfaceMonitor
+//===========================================================================================================================
+
+static void InterfaceMonitorCmd( void );
+
+static CLIOption               kInterfaceMonitorOpts[] =
+{
+       StringOption( 'i', "interface", &gInterface, "name or index", "Network interface by name or index.", true ),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     DNSProxy
+//===========================================================================================================================
+
+static void DNSProxyCmd( void );
+
+static char **                 gDNSProxy_InputInterfaces               = NULL;
+static size_t                  gDNSProxy_InputInterfaceCount   = 0;
+static const char *            gDNSProxy_OutputInterface               = NULL;
+
+static CLIOption               kDNSProxyOpts[] =
+{
+       MultiStringOption( 'i', "inputInterface",  &gDNSProxy_InputInterfaces, &gDNSProxy_InputInterfaceCount, "name or index", "Interface to accept queries on. Can be specified more than once.", true ),
+       StringOption(      'o', "outputInterface", &gDNSProxy_OutputInterface, "name or index", "Interface to forward queries over. Use '0' for primary interface. (default: 0)", false ),
+       CLI_OPTION_END()
+};
+#endif // MDNSRESPONDER_PROJECT
+
+//===========================================================================================================================
+//     Command Table
+//===========================================================================================================================
+
+static OSStatus        VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset );
+
+static void    BrowseCmd( void );
+static void    GetAddrInfoCmd( void );
+static void    QueryRecordCmd( void );
+static void    RegisterCmd( void );
+static void    RegisterRecordCmd( void );
+static void    ResolveCmd( void );
+static void    ReconfirmCmd( void );
+static void    GetAddrInfoPOSIXCmd( void );
+static void    ReverseLookupCmd( void );
+static void    PortMappingCmd( void );
+static void    BrowseAllCmd( void );
+static void    GetAddrInfoStressCmd( void );
+static void    DNSQueryCmd( void );
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+static void    DNSCryptCmd( void );
+#endif
+static void    MDNSQueryCmd( void );
+static void    PIDToUUIDCmd( void );
+static void    DaemonVersionCmd( void );
+
+static CLIOption               kGlobalOpts[] =
+{
+       CLI_OPTION_CALLBACK_EX( 'V', "version", VersionOptionCallback, NULL, NULL,
+               kCLIOptionFlags_NoArgument | kCLIOptionFlags_GlobalOnly, "Displays the version of this tool.", NULL ),
+       CLI_OPTION_HELP(),
+       
+       // Common commands.
+       
+       Command( "browse",                              BrowseCmd,                              kBrowseOpts,                    "Uses DNSServiceBrowse() to browse for one or more service types.", false ),
+       Command( "getAddrInfo",                 GetAddrInfoCmd,                 kGetAddrInfoOpts,               "Uses DNSServiceGetAddrInfo() to resolve a hostname to IP addresses.", false ),
+       Command( "queryRecord",                 QueryRecordCmd,                 kQueryRecordOpts,               "Uses DNSServiceQueryRecord() to query for an arbitrary DNS record.", false ),
+       Command( "register",                    RegisterCmd,                    kRegisterOpts,                  "Uses DNSServiceRegister() to register a service.", false ),
+       Command( "registerRecord",              RegisterRecordCmd,              kRegisterRecordOpts,    "Uses DNSServiceRegisterRecord() to register a record.", false ),
+       Command( "resolve",                             ResolveCmd,                             kResolveOpts,                   "Uses DNSServiceResolve() to resolve a service.", false ),
+       Command( "reconfirm",                   ReconfirmCmd,                   kReconfirmOpts,                 "Uses DNSServiceReconfirmRecord() to reconfirm a record.", false ),
+       Command( "getaddrinfo-posix",   GetAddrInfoPOSIXCmd,    kGetAddrInfoPOSIXOpts,  "Uses getaddrinfo() to resolve a hostname to IP addresses.", false ),
+       Command( "reverseLookup",               ReverseLookupCmd,               kReverseLookupOpts,             "Uses DNSServiceQueryRecord() to perform a reverse IP address lookup.", false ),
+       Command( "portMapping",                 PortMappingCmd,                 kPortMappingOpts,               "Uses DNSServiceNATPortMappingCreate() to create a port mapping.", false ),
+       Command( "browseAll",                   BrowseAllCmd,                   kBrowseAllOpts,                 "Browse and resolve all (or specific) services and, optionally, attempt connections.", false ),
+       
+       // Uncommon commands.
+       
+       Command( "getnameinfo",                 GetNameInfoCmd,                 kGetNameInfoOpts,               "Calls getnameinfo() and prints results.", true ),
+       Command( "getAddrInfoStress",   GetAddrInfoStressCmd,   kGetAddrInfoStressOpts, "Runs DNSServiceGetAddrInfo() stress testing.", true ),
+       Command( "DNSQuery",                    DNSQueryCmd,                    kDNSQueryOpts,                  "Crafts and sends a DNS query.", true ),
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+       Command( "DNSCrypt",                    DNSCryptCmd,                    kDNSCryptOpts,                  "Crafts and sends a DNSCrypt query.", true ),
+#endif
+       Command( "mdnsquery",                   MDNSQueryCmd,                   kMDNSQueryOpts,                 "Crafts and sends an mDNS query over the specified interface.", true ),
+       Command( "mdnscollider",                MDNSColliderCmd,                kMDNSColliderOpts,              "Creates record name collision scenarios.", true ),
+       Command( "pid2uuid",                    PIDToUUIDCmd,                   kPIDToUUIDOpts,                 "Prints the UUID of a process.", true ),
+       Command( "server",                              DNSServerCmd,                   kDNSServerOpts,                 "DNS server for testing.", true ),
+       Command( "mdnsreplier",                 MDNSReplierCmd,                 kMDNSReplierOpts,               "Responds to mDNS queries for a set of authoritative resource records.", true ),
+       Command( "test",                                NULL,                                   kTestOpts,                              "Commands for testing DNS-SD.", true ),
+       Command( "ssdp",                                NULL,                                   kSSDPOpts,                              "Simple Service Discovery Protocol (SSDP).", true ),
+#if( TARGET_OS_DARWIN )
+       Command( "legacy",                              NULL,                                   kLegacyOpts,                    "Legacy DNS API.", true ),
+       Command( "dnsconfig",                   NULL,                                   kDNSConfigOpts,                 "Add/remove a supplemental resolver entry to/from the system's DNS configuration.", true ),
+       Command( "xpcsend",                             XPCSendCmd,                             kXPCSendOpts,                   "Sends a message to an XPC service.", true ),
+#endif
+#if ( MDNSRESPONDER_PROJECT )
+       Command( "interfaceMonitor",    InterfaceMonitorCmd,    kInterfaceMonitorOpts,  "mDNSResponder's interface monitor.", true ),
+       Command( "dnsproxy",                    DNSProxyCmd,                    kDNSProxyOpts,                  "Enables mDNSResponder's DNS proxy.", true ),
+#endif
+       Command( "daemonVersion",               DaemonVersionCmd,               NULL,                                   "Prints the version of the DNS-SD daemon.", true ),
+       
+       CLI_COMMAND_HELP(),
+       CLI_OPTION_END()
+};
+
+//===========================================================================================================================
+//     Helper Prototypes
+//===========================================================================================================================
+
+#define kExitReason_OneShotDone                                "one-shot done"
+#define kExitReason_ReceivedResponse           "received response"
+#define kExitReason_SIGINT                                     "interrupt signal"
+#define kExitReason_Timeout                                    "timeout"
+#define kExitReason_TimeLimit                          "time limit"
+
+static void    Exit( void *inContext ) ATTRIBUTE_NORETURN;
+
+static DNSServiceFlags GetDNSSDFlagsFromOpts( void );
+
+typedef enum
+{
+       kConnectionType_None                    = 0,
+       kConnectionType_Normal                  = 1,
+       kConnectionType_DelegatePID             = 2,
+       kConnectionType_DelegateUUID    = 3
+       
+}      ConnectionType;
+
+typedef struct
+{
+       ConnectionType          type;
+       union
+       {
+               int32_t                 pid;
+               uint8_t                 uuid[ 16 ];
+               
+       }       delegate;
+       
+}      ConnectionDesc;
+
+static OSStatus
+       CreateConnectionFromArgString(
+               const char *                    inString,
+               dispatch_queue_t                inQueue,
+               DNSServiceRef *                 outSDRef,
+               ConnectionDesc *                outDesc );
+static OSStatus                        InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex );
+static OSStatus                        RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen );
+static OSStatus                        RecordTypeFromArgString( const char *inString, uint16_t *outValue );
+static OSStatus                        RecordClassFromArgString( const char *inString, uint16_t *outValue );
+
+#define kInterfaceNameBufLen           ( Max( IF_NAMESIZE, 16 ) + 1 )
+
+static char *                  InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] );
+static const char *            RecordTypeToString( unsigned int inValue );
+
+static OSStatus
+       DNSRecordDataToString(
+               const void *    inRDataPtr,
+               size_t                  inRDataLen,
+               unsigned int    inRDataType,
+               const void *    inMsgPtr,
+               size_t                  inMsgLen,
+               char **                 outString );
+
+static OSStatus
+       DNSMessageToText(
+               const uint8_t * inMsgPtr,
+               size_t                  inMsgLen,
+               Boolean                 inIsMDNS,
+               Boolean                 inPrintRaw,
+               char **                 outText );
+
+static OSStatus
+       WriteDNSQueryMessage(
+               uint8_t                 inMsg[ kDNSQueryMessageMaxLen ],
+               uint16_t                inMsgID,
+               uint16_t                inFlags,
+               const char *    inQName,
+               uint16_t                inQType,
+               uint16_t                inQClass,
+               size_t *                outMsgLen );
+
+// Dispatch helpers
+
+typedef void ( *DispatchHandler )( void *inContext );
+
+static OSStatus
+       DispatchSignalSourceCreate(
+               int                                     inSignal,
+               DispatchHandler         inEventHandler,
+               void *                          inContext,
+               dispatch_source_t *     outSource );
+static OSStatus
+       DispatchSocketSourceCreate(
+               SocketRef                               inSock,
+               dispatch_source_type_t  inType,
+               dispatch_queue_t                inQueue,
+               DispatchHandler                 inEventHandler,
+               DispatchHandler                 inCancelHandler,
+               void *                                  inContext,
+               dispatch_source_t *             outSource );
+
+#define DispatchReadSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
+       DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_READ, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
+
+#define DispatchWriteSourceCreate( SOCK, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE ) \
+       DispatchSocketSourceCreate( SOCK, DISPATCH_SOURCE_TYPE_WRITE, QUEUE, EVENT_HANDLER, CANCEL_HANDLER, CONTEXT, OUT_SOURCE )
+
+static OSStatus
+       DispatchTimerCreate(
+               dispatch_time_t         inStart,
+               uint64_t                        inIntervalNs,
+               uint64_t                        inLeewayNs,
+               dispatch_queue_t        inQueue,
+               DispatchHandler         inEventHandler,
+               DispatchHandler         inCancelHandler,
+               void *                          inContext,
+               dispatch_source_t *     outTimer );
+
+#define DispatchTimerOneShotCreate( IN_START, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, IN_CONTEXT, OUT_TIMER )   \
+       DispatchTimerCreate( IN_START, DISPATCH_TIME_FOREVER, IN_LEEWAY, IN_QUEUE, IN_EVENT_HANDLER, NULL, IN_CONTEXT, OUT_TIMER )
+
+static OSStatus
+       DispatchProcessMonitorCreate(
+               pid_t                           inPID,
+               unsigned long           inFlags,
+               dispatch_queue_t        inQueue,
+               DispatchHandler         inEventHandler,
+               DispatchHandler         inCancelHandler,
+               void *                          inContext,
+               dispatch_source_t *     outMonitor );
+
+static const char *    ServiceTypeDescription( const char *inName );
+
+typedef struct
+{
+       SocketRef               sock;                   // Socket.
+       void *                  userContext;    // User context.
+       int32_t                 refCount;               // Reference count.
+       
+}      SocketContext;
+
+static OSStatus                        SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext );
+static SocketContext * SocketContextRetain( SocketContext *inContext );
+static void                            SocketContextRelease( SocketContext *inContext );
+static void                            SocketContextCancelHandler( void *inContext );
+
+#define ForgetSocketContext( X )       ForgetCustom( X, SocketContextRelease )
+
+static OSStatus                StringToInt32( const char *inString, int32_t *outValue );
+static OSStatus                StringToUInt32( const char *inString, uint32_t *outValue );
+#if( TARGET_OS_DARWIN )
+static int64_t         _StringToInt64( const char *inString, OSStatus *outError );
+static uint64_t                _StringToUInt64( const char *inString, OSStatus *outError );
+static pid_t           _StringToPID( const char *inString, OSStatus *outError );
+static OSStatus
+       _ParseEscapedString(
+               const char *    inSrc,
+               const char *    inEnd,
+               const char *    inDelimiters,
+               char *                  inBufPtr,
+               size_t                  inBufLen,
+               size_t *                outCopiedLen,
+               size_t *                outActualLen,
+               const char **   outPtr );
+#endif
+static OSStatus                StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
+static OSStatus                StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen );
+static OSStatus                StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen );
+#if( TARGET_OS_DARWIN )
+static OSStatus                GetDefaultDNSServer( sockaddr_ip *outAddr );
+#endif
+static OSStatus
+       _ServerSocketOpenEx2( 
+               int                             inFamily, 
+               int                             inType, 
+               int                             inProtocol, 
+               const void *    inAddr, 
+               int                             inPort, 
+               int *                   outPort, 
+               int                             inRcvBufSize, 
+               Boolean                 inNoPortReuse,
+               SocketRef *             outSock );
+
+static const struct sockaddr * GetMDNSMulticastAddrV4( void );
+static const struct sockaddr * GetMDNSMulticastAddrV6( void );
+
+static OSStatus
+       CreateMulticastSocket(
+               const struct sockaddr * inAddr,
+               int                                             inPort,
+               const char *                    inIfName,
+               uint32_t                                inIfIndex,
+               Boolean                                 inJoin,
+               int *                                   outPort,
+               SocketRef *                             outSock );
+
+static OSStatus        DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr );
+static OSStatus        CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax );
+static OSStatus        CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax );
+static OSStatus        CheckRootUser( void );
+static OSStatus        SpawnCommand( pid_t *outPID, const char *inFormat, ... );
+static OSStatus        OutputFormatFromArgString( const char *inArgString, OutputFormatType *outFormat );
+static OSStatus        OutputPropertyList( CFPropertyListRef inPList, OutputFormatType inType, const char *inOutputFilePath );
+static OSStatus        CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen );
+static OSStatus        CreateTXTRecordDataFromString( const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen );
+static OSStatus
+       CreateNSECRecordData(
+               const uint8_t * inNextDomainName,
+               uint8_t **              outPtr,
+               size_t *                outLen,
+               unsigned int    inTypeCount,
+               ... );
+static OSStatus
+       AppendSOARecord(
+               DataBuffer *    inDB,
+               const uint8_t * inNamePtr,
+               size_t                  inNameLen,
+               uint16_t                inType,
+               uint16_t                inClass,
+               uint32_t                inTTL,
+               const uint8_t * inMName,
+               const uint8_t * inRName,
+               uint32_t                inSerial,
+               uint32_t                inRefresh,
+               uint32_t                inRetry,
+               uint32_t                inExpire,
+               uint32_t                inMinimumTTL,
+               size_t *                outLen );
+static OSStatus
+       CreateSOARecordData(
+               const uint8_t * inMName,
+               const uint8_t * inRName,
+               uint32_t                inSerial,
+               uint32_t                inRefresh,
+               uint32_t                inRetry,
+               uint32_t                inExpire,
+               uint32_t                inMinimumTTL,
+               uint8_t **              outPtr,
+               size_t *                outLen );
+static OSStatus
+       _DataBuffer_AppendDNSQuestion(
+               DataBuffer *    inDB,
+               const uint8_t * inNamePtr,
+               size_t                  inNameLen,
+               uint16_t                inType,
+               uint16_t                inClass );
+static OSStatus
+       _DataBuffer_AppendDNSRecord(
+               DataBuffer *    inDB,
+               const uint8_t * inNamePtr,
+               size_t                  inNameLen,
+               uint16_t                inType,
+               uint16_t                inClass,
+               uint32_t                inTTL,
+               const uint8_t * inRDataPtr,
+               size_t                  inRDataLen );
+static char *  _NanoTime64ToTimestamp( NanoTime64 inTime, char *inBuf, size_t inMaxLen );
+
+typedef struct MDNSInterfaceItem               MDNSInterfaceItem;
+struct MDNSInterfaceItem
+{
+       MDNSInterfaceItem *             next;
+       char *                                  ifName;
+       uint32_t                                ifIndex;
+       Boolean                                 hasIPv4;
+       Boolean                                 hasIPv6;
+       Boolean                                 isAWDL;
+       Boolean                                 isWiFi;
+};
+
+typedef enum
+{
+       kMDNSInterfaceSubset_All                = 0,    // All mDNS-capable interfaces.
+       kMDNSInterfaceSubset_AWDL               = 1,    // All mDNS-capable AWDL interfaces.
+       kMDNSInterfaceSubset_NonAWDL    = 2             // All mDNS-capable non-AWDL iterfaces.
+       
+}      MDNSInterfaceSubset;
+
+static OSStatus        _MDNSInterfaceListCreate( MDNSInterfaceSubset inSubset, size_t inItemSize, MDNSInterfaceItem **outList );
+static void            _MDNSInterfaceListFree( MDNSInterfaceItem *inList );
+#define _MDNSInterfaceListForget( X )          ForgetCustom( X, _MDNSInterfaceListFree )
+static OSStatus _MDNSInterfaceGetAny( MDNSInterfaceSubset inSubset, char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex );
+
+static OSStatus        _SetComputerName( CFStringRef inComputerName, CFStringEncoding inEncoding );
+static OSStatus        _SetComputerNameWithUTF8CString( const char *inComputerName );
+static OSStatus        _SetLocalHostName( CFStringRef inLocalHostName );
+static OSStatus        _SetLocalHostNameWithUTF8CString( const char *inLocalHostName );
+
+static OSStatus        _SocketWriteAll( SocketRef inSock, const void *inData, size_t inSize, int32_t inTimeoutSecs );
+static OSStatus
+       _StringToIPv4Address(
+               const char *                    inStr,
+               StringToIPAddressFlags  inFlags,
+               uint32_t *                              outIP,
+               int *                                   outPort,
+               uint32_t *                              outSubnet,
+               uint32_t *                              outRouter,
+               const char **                   outStr );
+static void    _StringArray_Free( char **inArray, size_t inCount );
+static OSStatus
+       _StringToIPv6Address(
+               const char *                    inStr,
+               StringToIPAddressFlags  inFlags,
+               uint8_t                                 outIPv6[ 16 ],
+               uint32_t *                              outScope,
+               int *                                   outPort,
+               int *                                   outPrefix,
+               const char **                   outStr );
+static Boolean
+       _ParseQuotedEscapedString(
+               const char *    inSrc,
+               const char *    inEnd,
+               const char *    inDelimiters,
+               char *                  inBuf,
+               size_t                  inMaxLen,
+               size_t *                outCopiedLen,
+               size_t *                outTotalLen,
+               const char **   outSrc );
+static void *  _memdup( const void *inPtr, size_t inLen );
+static int             _memicmp( const void *inP1, const void *inP2, size_t inLen );
+static uint32_t        _FNV1( const void *inData, size_t inSize );
+
+#define Unused( X )            (void)(X)
+
+//===========================================================================================================================
+//     MDNSCollider
+//===========================================================================================================================
+
+typedef struct MDNSColliderPrivate *           MDNSColliderRef;
+
+typedef uint32_t               MDNSColliderProtocols;
+#define kMDNSColliderProtocol_None             0
+#define kMDNSColliderProtocol_IPv4             ( 1 << 0 )
+#define kMDNSColliderProtocol_IPv6             ( 1 << 1 )
+
+typedef void ( *MDNSColliderStopHandler_f )( void *inContext, OSStatus inError );
+
+static OSStatus        MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider );
+static OSStatus        MDNSColliderStart( MDNSColliderRef inCollider );
+static void            MDNSColliderStop( MDNSColliderRef inCollider );
+static void            MDNSColliderSetProtocols( MDNSColliderRef inCollider, MDNSColliderProtocols inProtocols );
+static void            MDNSColliderSetInterfaceIndex( MDNSColliderRef inCollider, uint32_t inInterfaceIndex );
+static OSStatus        MDNSColliderSetProgram( MDNSColliderRef inCollider, const char *inProgramStr );
+static void
+       MDNSColliderSetStopHandler(
+               MDNSColliderRef                         inCollider,
+               MDNSColliderStopHandler_f       inStopHandler,
+               void *                                          inStopContext );
+static OSStatus
+       MDNSColliderSetRecord(
+               MDNSColliderRef inCollider,
+               const uint8_t * inName,
+               uint16_t                inType,
+               const void *    inRDataPtr,
+               size_t                  inRDataLen );
+static CFTypeID        MDNSColliderGetTypeID( void );
+
+//===========================================================================================================================
+//     ServiceBrowser
+//===========================================================================================================================
+
+typedef struct ServiceBrowserPrivate *         ServiceBrowserRef;
+typedef struct ServiceBrowserResults           ServiceBrowserResults;
+typedef struct SBRDomain                                       SBRDomain;
+typedef struct SBRServiceType                          SBRServiceType;
+typedef struct SBRServiceInstance                      SBRServiceInstance;
+typedef struct SBRIPAddress                                    SBRIPAddress;
+
+typedef void ( *ServiceBrowserCallback_f )( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
+
+struct ServiceBrowserResults
+{
+       SBRDomain *             domainList;     // List of domains in which services were found.
+};
+
+struct SBRDomain
+{
+       SBRDomain *                             next;           // Next domain in list.
+       char *                                  name;           // Name of domain represented by this object.
+       SBRServiceType *                typeList;       // List of service types in this domain.
+};
+
+struct SBRServiceType
+{
+       SBRServiceType *                        next;                   // Next service type in list.
+       char *                                          name;                   // Name of service type represented by this object.
+       SBRServiceInstance *            instanceList;   // List of service instances of this service type.
+};
+
+struct SBRServiceInstance
+{
+       SBRServiceInstance *            next;                   // Next service instance in list.
+       char *                                          name;                   // Name of service instance represented by this object.
+       char *                                          hostname;               // Target from service instance's SRV record.
+       uint32_t                                        ifIndex;                // Index of interface over which this service instance was discovered.
+       uint16_t                                        port;                   // Port from service instance's SRV record.
+       uint8_t *                                       txtPtr;                 // Service instance's TXT record data.
+       size_t                                          txtLen;                 // Service instance's TXT record data length.
+       SBRIPAddress *                          ipaddrList;             // List of IP addresses that the hostname resolved to.
+       uint64_t                                        discoverTimeUs; // Time it took to discover this service instance in microseconds.
+       uint64_t                                        resolveTimeUs;  // Time it took to resolve this service instance in microseconds.
+};
+
+struct SBRIPAddress
+{
+       SBRIPAddress *          next;                   // Next IP address in list.
+       sockaddr_ip                     sip;                    // IPv4 or IPv6 address.
+       uint64_t                        resolveTimeUs;  // Time it took to resolve this IP address in microseconds.
+};
+
+static CFTypeID        ServiceBrowserGetTypeID( void );
+static OSStatus
+       ServiceBrowserCreate(
+               dispatch_queue_t        inQueue,
+               uint32_t                        inInterfaceIndex,
+               const char *            inDomain,
+               unsigned int            inBrowseTimeSecs,
+               Boolean                         inIncludeAWDL,
+               ServiceBrowserRef *     outBrowser );
+static void            ServiceBrowserStart( ServiceBrowserRef inBrowser );
+static OSStatus        ServiceBrowserAddServiceType( ServiceBrowserRef inBrowser, const char *inServiceType );
+static void
+       ServiceBrowserSetCallback(
+               ServiceBrowserRef                       inBrowser,
+               ServiceBrowserCallback_f        inCallback,
+               void *                                          inContext );
+static void            ServiceBrowserResultsRetain( ServiceBrowserResults *inResults );
+static void            ServiceBrowserResultsRelease( ServiceBrowserResults *inResults );
+
+#define ForgetServiceBrowserResults( X )               ForgetCustom( X, ServiceBrowserResultsRelease )
+
+//===========================================================================================================================
+//     main
+//===========================================================================================================================
+
+#define _PRINTF_EXTENSION_HANDLER_DECLARE( NAME )      \
+       static int                                                                              \
+               _PrintFExtension ## NAME ## Handler(            \
+                       PrintFContext * inContext,                              \
+                       PrintFFormat *  inFormat,                               \
+                       PrintFVAList *  inArgs,                                 \
+                       void *                  inUserContext )
+
+_PRINTF_EXTENSION_HANDLER_DECLARE( Timestamp );
+_PRINTF_EXTENSION_HANDLER_DECLARE( DNSMessage );
+_PRINTF_EXTENSION_HANDLER_DECLARE( CallbackFlags );
+_PRINTF_EXTENSION_HANDLER_DECLARE( DNSRecordData );
+
+int    main( int argc, const char **argv )
+{
+       OSStatus                err;
+       
+       // Route DebugServices logging output to stderr.
+       
+       dlog_control( "DebugServices:output=file;stderr" );
+       
+       PrintFRegisterExtension( "du:time",    _PrintFExtensionTimestampHandler,     NULL );
+       PrintFRegisterExtension( "du:dnsmsg",  _PrintFExtensionDNSMessageHandler,    NULL );
+       PrintFRegisterExtension( "du:cbflags", _PrintFExtensionCallbackFlagsHandler, NULL );
+       PrintFRegisterExtension( "du:rdata",   _PrintFExtensionDNSRecordDataHandler, NULL );
+       CLIInit( argc, argv );
+       err = CLIParse( kGlobalOpts, kCLIFlags_None );
+       if( err ) exit( 1 );
+       
+       return( gExitCode );
+}
+
+//===========================================================================================================================
+//     VersionOptionCallback
+//===========================================================================================================================
+
+static OSStatus        VersionOptionCallback( CLIOption *inOption, const char *inArg, int inUnset )
+{
+       const char *            srcVers;
+#if( MDNSRESPONDER_PROJECT )
+       char                            srcStr[ 16 ];
+#endif
+       
+       Unused( inOption );
+       Unused( inArg );
+       Unused( inUnset );
+       
+#if( MDNSRESPONDER_PROJECT )
+       srcVers = SourceVersionToCString( _DNS_SD_H, srcStr );
+#else
+       srcVers = DNSSDUTIL_SOURCE_VERSION;
+#endif
+       FPrintF( stdout, "%s version %v (%s)\n", gProgramName, kDNSSDUtilNumVersion, srcVers );
+       
+       return( kEndingErr );
+}
+
+//===========================================================================================================================
+//     BrowseCmd
+//===========================================================================================================================
+
+typedef struct BrowseResolveOp         BrowseResolveOp;
+
+struct BrowseResolveOp
+{
+       BrowseResolveOp *               next;                   // Next resolve operation in list.
+       DNSServiceRef                   sdRef;                  // sdRef of the DNSServiceResolve or DNSServiceQueryRecord operation.
+       char *                                  fullName;               // Full name of the service to resolve.
+       uint32_t                                interfaceIndex; // Interface index of the DNSServiceResolve or DNSServiceQueryRecord operation.
+};
+
+typedef struct
+{
+       DNSServiceRef                   mainRef;                        // Main sdRef for shared connection.
+       DNSServiceRef *                 opRefs;                         // Array of sdRefs for individual Browse operarions.
+       size_t                                  opRefsCount;            // Count of array of sdRefs for non-shared connections.
+       const char *                    domain;                         // Domain for DNSServiceBrowse operation(s).
+       DNSServiceFlags                 flags;                          // Flags for DNSServiceBrowse operation(s).
+       char **                                 serviceTypes;           // Array of service types to browse for.
+       size_t                                  serviceTypesCount;      // Count of array of service types to browse for.
+       int                                             timeLimitSecs;          // Time limit of DNSServiceBrowse operation in seconds.
+       BrowseResolveOp *               resolveList;            // List of resolve and/or TXT record query operations.
+       uint32_t                                ifIndex;                        // Interface index of DNSServiceBrowse operation(s).
+       Boolean                                 printedHeader;          // True if results header has been printed.
+       Boolean                                 doResolve;                      // True if service instances are to be resolved.
+       Boolean                                 doResolveTXTOnly;       // True if TXT records of service instances are to be queried.
+       
+}      BrowseContext;
+
+static void            BrowsePrintPrologue( const BrowseContext *inContext );
+static void            BrowseContextFree( BrowseContext *inContext );
+static OSStatus        BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp );
+static void            BrowseResolveOpFree( BrowseResolveOp *inOp );
+static void DNSSD_API
+       BrowseCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inRegType,
+               const char *            inDomain,
+               void *                          inContext );
+static void DNSSD_API
+       BrowseResolveCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               uint16_t                                inTXTLen,
+               const unsigned char *   inTXTPtr,
+               void *                                  inContext );
+static void DNSSD_API
+       BrowseQueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+
+static void    BrowseCmd( void )
+{
+       OSStatus                                err;
+       size_t                                  i;
+       BrowseContext *                 context                 = NULL;
+       dispatch_source_t               signalSource    = NULL;
+       int                                             useMainConnection;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Create context.
+       
+       context = (BrowseContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->opRefs = (DNSServiceRef *) calloc( gBrowse_ServiceTypesCount, sizeof( DNSServiceRef ) );
+       require_action( context->opRefs, exit, err = kNoMemoryErr );
+       context->opRefsCount = gBrowse_ServiceTypesCount;
+       
+       // Check command parameters.
+       
+       if( gBrowse_TimeLimitSecs < 0 )
+       {
+               FPrintF( stderr, "Invalid time limit: %d seconds.\n", gBrowse_TimeLimitSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create main connection.
+       
+       if( gConnectionOpt )
+       {
+               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+               require_noerr_quiet( err, exit );
+               useMainConnection = true;
+       }
+       else
+       {
+               useMainConnection = false;
+       }
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+       
+       // Get interface.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Set remaining parameters.
+       
+       context->serviceTypes           = gBrowse_ServiceTypes;
+       context->serviceTypesCount      = gBrowse_ServiceTypesCount;
+       context->domain                         = gBrowse_Domain;
+       context->doResolve                      = gBrowse_DoResolve     ? true : false;
+       context->timeLimitSecs          = gBrowse_TimeLimitSecs;
+       context->doResolveTXTOnly       = gBrowse_QueryTXT      ? true : false;
+       
+       // Print prologue.
+       
+       BrowsePrintPrologue( context );
+       
+       // Start operation(s).
+       
+       for( i = 0; i < context->serviceTypesCount; ++i )
+       {
+               DNSServiceRef           sdRef;
+               
+               sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+               err = DNSServiceBrowse( &sdRef, context->flags, context->ifIndex, context->serviceTypes[ i ], context->domain,
+                       BrowseCallback, context );
+               require_noerr( err, exit );
+               
+               context->opRefs[ i ] = sdRef;
+               if( !useMainConnection )
+               {
+                       err = DNSServiceSetDispatchQueue( context->opRefs[ i ], dispatch_get_main_queue() );
+                       require_noerr( err, exit );
+               }
+       }
+       
+       // Set time limit.
+       
+       if( context->timeLimitSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+                       kExitReason_TimeLimit, Exit );
+       }
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) BrowseContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     BrowsePrintPrologue
+//===========================================================================================================================
+
+static void    BrowsePrintPrologue( const BrowseContext *inContext )
+{
+       const int                                               timeLimitSecs   = inContext->timeLimitSecs;
+       const char * const *                    ptr                             = (const char **) inContext->serviceTypes;
+       const char * const * const              end                             = (const char **) inContext->serviceTypes + inContext->serviceTypesCount;
+       char                                                    ifName[ kInterfaceNameBufLen ];
+       
+       InterfaceIndexToName( inContext->ifIndex, ifName );
+       
+       FPrintF( stdout, "Flags:         %#{flags}\n",  inContext->flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:     %d (%s)\n",    (int32_t) inContext->ifIndex, ifName );
+       FPrintF( stdout, "Service types: %s",                   *ptr++ );
+       while( ptr < end ) FPrintF( stdout, ", %s",             *ptr++ );
+       FPrintF( stdout, "\n" );
+       FPrintF( stdout, "Domain:        %s\n", inContext->domain ? inContext->domain : "<NULL> (default domains)" );
+       FPrintF( stdout, "Time limit:    " );
+       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+       else                                    FPrintF( stdout, "∞\n" );
+       FPrintF( stdout, "Start time:    %{du:time}\n", NULL );
+       FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+//     BrowseContextFree
+//===========================================================================================================================
+
+static void    BrowseContextFree( BrowseContext *inContext )
+{
+       size_t          i;
+       
+       for( i = 0; i < inContext->opRefsCount; ++i )
+       {
+               DNSServiceForget( &inContext->opRefs[ i ] );
+       }
+       if( inContext->serviceTypes )
+       {
+               _StringArray_Free( inContext->serviceTypes, inContext->serviceTypesCount );
+               inContext->serviceTypes                 = NULL;
+               inContext->serviceTypesCount    = 0;
+       }
+       DNSServiceForget( &inContext->mainRef );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     BrowseResolveOpCreate
+//===========================================================================================================================
+
+static OSStatus        BrowseResolveOpCreate( const char *inFullName, uint32_t inInterfaceIndex, BrowseResolveOp **outOp )
+{
+       OSStatus                                err;
+       BrowseResolveOp *               resolveOp;
+       
+       resolveOp = (BrowseResolveOp *) calloc( 1, sizeof( *resolveOp ) );
+       require_action( resolveOp, exit, err = kNoMemoryErr );
+       
+       resolveOp->fullName = strdup( inFullName );
+       require_action( resolveOp->fullName, exit, err = kNoMemoryErr );
+       
+       resolveOp->interfaceIndex = inInterfaceIndex;
+       
+       *outOp = resolveOp;
+       resolveOp = NULL;
+       err = kNoErr;
+       
+exit:
+       if( resolveOp ) BrowseResolveOpFree( resolveOp );
+       return( err );
+}
+
+//===========================================================================================================================
+//     BrowseResolveOpFree
+//===========================================================================================================================
+
+static void    BrowseResolveOpFree( BrowseResolveOp *inOp )
+{
+       DNSServiceForget( &inOp->sdRef );
+       ForgetMem( &inOp->fullName );
+       free( inOp );
+}
+
+//===========================================================================================================================
+//     BrowseCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       BrowseCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inRegType,
+               const char *            inDomain,
+               void *                          inContext )
+{
+       BrowseContext * const           context = (BrowseContext *) inContext;
+       OSStatus                                        err;
+       BrowseResolveOp *                       newOp = NULL;
+       BrowseResolveOp **                      p;
+       char                                            fullName[ kDNSServiceMaxDomainName ];
+       struct timeval                          now;
+       
+       Unused( inSDRef );
+       
+       gettimeofday( &now, NULL );
+       
+       err = inError;
+       require_noerr( err, exit );
+       
+       if( !context->printedHeader )
+       {
+               FPrintF( stdout, "%-26s  %-16s IF %-20s %-20s Instance Name\n", "Timestamp", "Flags", "Domain", "Service Type" );
+               context->printedHeader = true;
+       }
+       FPrintF( stdout, "%{du:time}  %{du:cbflags} %2d %-20s %-20s %s\n",
+               &now, inFlags, (int32_t) inInterfaceIndex, inDomain, inRegType, inName );
+       
+       if( !context->doResolve && !context->doResolveTXTOnly ) goto exit;
+       
+       err = DNSServiceConstructFullName( fullName, inName, inRegType, inDomain );
+       require_noerr( err, exit );
+       
+       if( inFlags & kDNSServiceFlagsAdd )
+       {
+               DNSServiceRef           sdRef;
+               DNSServiceFlags         flags;
+               
+               err = BrowseResolveOpCreate( fullName, inInterfaceIndex, &newOp );
+               require_noerr( err, exit );
+               
+               if( context->mainRef )
+               {
+                       sdRef = context->mainRef;
+                       flags = kDNSServiceFlagsShareConnection;
+               }
+               else
+               {
+                       flags = 0;
+               }
+               if( context->doResolve )
+               {
+                       err = DNSServiceResolve( &sdRef, flags, inInterfaceIndex, inName, inRegType, inDomain, BrowseResolveCallback,
+                               NULL );
+                       require_noerr( err, exit );
+               }
+               else
+               {
+                       err = DNSServiceQueryRecord( &sdRef, flags, inInterfaceIndex, fullName, kDNSServiceType_TXT, kDNSServiceClass_IN,
+                               BrowseQueryRecordCallback, NULL );
+                       require_noerr( err, exit );
+               }
+               
+               newOp->sdRef = sdRef;
+               if( !context->mainRef )
+               {
+                       err = DNSServiceSetDispatchQueue( newOp->sdRef, dispatch_get_main_queue() );
+                       require_noerr( err, exit );
+               }
+               for( p = &context->resolveList; *p; p = &( *p )->next ) {}
+               *p = newOp;
+               newOp = NULL;
+       }
+       else
+       {
+               BrowseResolveOp *               resolveOp;
+               
+               for( p = &context->resolveList; ( resolveOp = *p ) != NULL; p = &resolveOp->next )
+               {
+                       if( ( resolveOp->interfaceIndex == inInterfaceIndex ) && ( strcasecmp( resolveOp->fullName, fullName ) == 0 ) )
+                       {
+                               break;
+                       }
+               }
+               if( resolveOp )
+               {
+                       *p = resolveOp->next;
+                       BrowseResolveOpFree( resolveOp );
+               }
+       }
+       
+exit:
+       if( newOp ) BrowseResolveOpFree( newOp );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     BrowseQueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       BrowseQueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                        err;
+       struct timeval          now;
+       
+       Unused( inSDRef );
+       Unused( inClass );
+       Unused( inTTL );
+       Unused( inContext );
+       
+       gettimeofday( &now, NULL );
+       
+       err = inError;
+       require_noerr( err, exit );
+       require_action( inType == kDNSServiceType_TXT, exit, err = kTypeErr );
+       
+       FPrintF( stdout, "%{du:time}  %s %s TXT on interface %d\n    TXT: %#{txt}\n",
+               &now, DNSServiceFlagsToAddRmvStr( inFlags ), inFullName, (int32_t) inInterfaceIndex, inRDataPtr,
+               (size_t) inRDataLen );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     BrowseResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       BrowseResolveCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               uint16_t                                inTXTLen,
+               const unsigned char *   inTXTPtr,
+               void *                                  inContext )
+{
+       struct timeval          now;
+       char                            errorStr[ 64 ];
+       
+       Unused( inSDRef );
+       Unused( inFlags );
+       Unused( inContext );
+       
+       gettimeofday( &now, NULL );
+       
+       if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
+       
+       FPrintF( stdout, "%{du:time}  %s can be reached at %s:%u (interface %d)%?s\n",
+               &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
+       if( inTXTLen == 1 )
+       {
+               FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
+       }
+       else
+       {
+               FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
+       }
+}
+
+//===========================================================================================================================
+//     GetAddrInfoCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSServiceRef                   mainRef;                // Main sdRef for shared connection.
+       DNSServiceRef                   opRef;                  // sdRef for the DNSServiceGetAddrInfo operation.
+       const char *                    name;                   // Hostname to resolve.
+       DNSServiceFlags                 flags;                  // Flags argument for DNSServiceGetAddrInfo().
+       DNSServiceProtocol              protocols;              // Protocols argument for DNSServiceGetAddrInfo().
+       uint32_t                                ifIndex;                // Interface index argument for DNSServiceGetAddrInfo().
+       int                                             timeLimitSecs;  // Time limit for the DNSServiceGetAddrInfo() operation in seconds.
+       Boolean                                 printedHeader;  // True if the results header has been printed.
+       Boolean                                 oneShotMode;    // True if command is done after the first set of results (one-shot mode).
+       Boolean                                 needIPv4;               // True if in one-shot mode and an IPv4 result is needed.
+       Boolean                                 needIPv6;               // True if in one-shot mode and an IPv6 result is needed.
+       
+}      GetAddrInfoContext;
+
+static void    GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext );
+static void    GetAddrInfoContextFree( GetAddrInfoContext *inContext );
+static void DNSSD_API
+       GetAddrInfoCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+
+static void    GetAddrInfoCmd( void )
+{
+       OSStatus                                        err;
+       DNSServiceRef                           sdRef;
+       GetAddrInfoContext *            context                 = NULL;
+       dispatch_source_t                       signalSource    = NULL;
+       int                                                     useMainConnection;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Check command parameters.
+       
+       if( gGetAddrInfo_TimeLimitSecs < 0 )
+       {
+               FPrintF( stderr, "Invalid time limit: %d s.\n", gGetAddrInfo_TimeLimitSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create context.
+       
+       context = (GetAddrInfoContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       // Create main connection.
+       
+       if( gConnectionOpt )
+       {
+               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+               require_noerr_quiet( err, exit );
+               useMainConnection = true;
+       }
+       else
+       {
+               useMainConnection = false;
+       }
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+       
+       // Get interface.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Set remaining parameters.
+       
+       context->name                   = gGetAddrInfo_Name;
+       context->timeLimitSecs  = gGetAddrInfo_TimeLimitSecs;
+       if( gGetAddrInfo_ProtocolIPv4 ) context->protocols |= kDNSServiceProtocol_IPv4;
+       if( gGetAddrInfo_ProtocolIPv6 ) context->protocols |= kDNSServiceProtocol_IPv6;
+       if( gGetAddrInfo_OneShot )
+       {
+               context->oneShotMode    = true;
+               context->needIPv4               = ( gGetAddrInfo_ProtocolIPv4 || !gGetAddrInfo_ProtocolIPv6 ) ? true : false;
+               context->needIPv6               = ( gGetAddrInfo_ProtocolIPv6 || !gGetAddrInfo_ProtocolIPv4 ) ? true : false;
+       }
+       
+       // Print prologue.
+       
+       GetAddrInfoPrintPrologue( context );
+       
+       // Start operation.
+       
+       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+       err = DNSServiceGetAddrInfo( &sdRef, context->flags, context->ifIndex, context->protocols, context->name,
+               GetAddrInfoCallback, context );
+       require_noerr( err, exit );
+       
+       context->opRef = sdRef;
+       if( !useMainConnection )
+       {
+               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+               require_noerr( err, exit );
+       }
+       
+       // Set time limit.
+       
+       if( context->timeLimitSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+                       kExitReason_TimeLimit, Exit );
+       }
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) GetAddrInfoContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     GetAddrInfoPrintPrologue
+//===========================================================================================================================
+
+static void    GetAddrInfoPrintPrologue( const GetAddrInfoContext *inContext )
+{
+       const int               timeLimitSecs = inContext->timeLimitSecs;
+       char                    ifName[ kInterfaceNameBufLen ];
+       
+       InterfaceIndexToName( inContext->ifIndex, ifName );
+       
+       FPrintF( stdout, "Flags:      %#{flags}\n",             inContext->flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:  %d (%s)\n",               (int32_t) inContext->ifIndex, ifName );
+       FPrintF( stdout, "Protocols:  %#{flags}\n",             inContext->protocols, kDNSServiceProtocolDescriptors );
+       FPrintF( stdout, "Name:       %s\n",                    inContext->name );
+       FPrintF( stdout, "Mode:       %s\n",                    inContext->oneShotMode ? "one-shot" : "continuous" );
+       FPrintF( stdout, "Time limit: " );
+       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+       else                                    FPrintF( stdout, "∞\n" );
+       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
+       FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+//     GetAddrInfoContextFree
+//===========================================================================================================================
+
+static void    GetAddrInfoContextFree( GetAddrInfoContext *inContext )
+{
+       DNSServiceForget( &inContext->opRef );
+       DNSServiceForget( &inContext->mainRef );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     GetAddrInfoCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       GetAddrInfoCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       GetAddrInfoContext * const              context = (GetAddrInfoContext *) inContext;
+       struct timeval                                  now;
+       OSStatus                                                err;
+       const char *                                    addrStr;
+       char                                                    addrStrBuf[ kSockAddrStringMaxSize ];
+       
+       Unused( inSDRef );
+       
+       gettimeofday( &now, NULL );
+       
+       switch( inError )
+       {
+               case kDNSServiceErr_NoError:
+               case kDNSServiceErr_NoSuchRecord:
+                       err = kNoErr;
+                       break;
+               
+               case kDNSServiceErr_Timeout:
+                       Exit( kExitReason_Timeout );
+               
+               default:
+                       err = inError;
+                       goto exit;
+       }
+       
+       if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+       {
+               dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+               err = kTypeErr;
+               goto exit;
+       }
+       
+       if( !inError )
+       {
+               err = SockAddrToString( inSockAddr, kSockAddrStringFlagsNone, addrStrBuf );
+               require_noerr( err, exit );
+               addrStr = addrStrBuf;
+       }
+       else
+       {
+               addrStr = ( inSockAddr->sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr;
+       }
+       
+       if( !context->printedHeader )
+       {
+               FPrintF( stdout, "%-26s  %-16s IF %-30s %-34s %6s\n", "Timestamp", "Flags", "Hostname", "Address", "TTL" );
+               context->printedHeader = true;
+       }
+       FPrintF( stdout, "%{du:time}  %{du:cbflags} %2d %-30s %-34s %6u\n",
+               &now, inFlags, (int32_t) inInterfaceIndex, inHostname, addrStr, inTTL );
+       
+       if( context->oneShotMode )
+       {
+               if( inFlags & kDNSServiceFlagsAdd )
+               {
+                       if( inSockAddr->sa_family == AF_INET )  context->needIPv4 = false;
+                       else                                                                    context->needIPv6 = false;
+               }
+               if( !( inFlags & kDNSServiceFlagsMoreComing ) && !context->needIPv4 && !context->needIPv6 )
+               {
+                       Exit( kExitReason_OneShotDone );
+               }
+       }
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     QueryRecordCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSServiceRef           mainRef;                // Main sdRef for shared connection.
+       DNSServiceRef           opRef;                  // sdRef for the DNSServiceQueryRecord operation.
+       const char *            recordName;             // Resource record name argument for DNSServiceQueryRecord().
+       DNSServiceFlags         flags;                  // Flags argument for DNSServiceQueryRecord().
+       uint32_t                        ifIndex;                // Interface index argument for DNSServiceQueryRecord().
+       int                                     timeLimitSecs;  // Time limit for the DNSServiceQueryRecord() operation in seconds.
+       uint16_t                        recordType;             // Resource record type argument for DNSServiceQueryRecord().
+       Boolean                         printedHeader;  // True if the results header was printed.
+       Boolean                         oneShotMode;    // True if command is done after the first set of results (one-shot mode).
+       Boolean                         gotRecord;              // True if in one-shot mode and received at least one record of the desired type.
+       Boolean                         printRawRData;  // True if RDATA results are not to be formatted when printed.
+       
+}      QueryRecordContext;
+
+static void    QueryRecordPrintPrologue( const QueryRecordContext *inContext );
+static void    QueryRecordContextFree( QueryRecordContext *inContext );
+static void DNSSD_API
+       QueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+
+static void    QueryRecordCmd( void )
+{
+       OSStatus                                        err;
+       DNSServiceRef                           sdRef;
+       QueryRecordContext *            context                 = NULL;
+       dispatch_source_t                       signalSource    = NULL;
+       int                                                     useMainConnection;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Create context.
+       
+       context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       // Check command parameters.
+       
+       if( gQueryRecord_TimeLimitSecs < 0 )
+       {
+               FPrintF( stderr, "Invalid time limit: %d seconds.\n", gQueryRecord_TimeLimitSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create main connection.
+       
+       if( gConnectionOpt )
+       {
+               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+               require_noerr_quiet( err, exit );
+               useMainConnection = true;
+       }
+       else
+       {
+               useMainConnection = false;
+       }
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+       
+       // Get interface.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Get record type.
+       
+       err = RecordTypeFromArgString( gQueryRecord_Type, &context->recordType );
+       require_noerr( err, exit );
+       
+       // Set remaining parameters.
+       
+       context->recordName             = gQueryRecord_Name;
+       context->timeLimitSecs  = gQueryRecord_TimeLimitSecs;
+       context->oneShotMode    = gQueryRecord_OneShot  ? true : false;
+       context->printRawRData  = gQueryRecord_RawRData ? true : false;
+       
+       // Print prologue.
+       
+       QueryRecordPrintPrologue( context );
+       
+       // Start operation.
+       
+       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+       err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
+               kDNSServiceClass_IN, QueryRecordCallback, context );
+       require_noerr( err, exit );
+       
+       context->opRef = sdRef;
+       if( !useMainConnection )
+       {
+               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+               require_noerr( err, exit );
+       }
+       
+       // Set time limit.
+       
+       if( context->timeLimitSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_TimeLimit,
+                       Exit );
+       }
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) QueryRecordContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     QueryRecordContextFree
+//===========================================================================================================================
+
+static void    QueryRecordContextFree( QueryRecordContext *inContext )
+{
+       DNSServiceForget( &inContext->opRef );
+       DNSServiceForget( &inContext->mainRef );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     QueryRecordPrintPrologue
+//===========================================================================================================================
+
+static void    QueryRecordPrintPrologue( const QueryRecordContext *inContext )
+{
+       const int               timeLimitSecs = inContext->timeLimitSecs;
+       char                    ifName[ kInterfaceNameBufLen ];
+       
+       InterfaceIndexToName( inContext->ifIndex, ifName );
+       
+       FPrintF( stdout, "Flags:       %#{flags}\n",    inContext->flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:   %d (%s)\n",              (int32_t) inContext->ifIndex, ifName );
+       FPrintF( stdout, "Name:        %s\n",                   inContext->recordName );
+       FPrintF( stdout, "Type:        %s (%u)\n",              RecordTypeToString( inContext->recordType ), inContext->recordType );
+       FPrintF( stdout, "Mode:        %s\n",                   inContext->oneShotMode ? "one-shot" : "continuous" );
+       FPrintF( stdout, "Time limit:  " );
+       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+       else                                    FPrintF( stdout, "∞\n" );
+       FPrintF( stdout, "Start time:  %{du:time}\n",   NULL );
+       FPrintF( stdout, "---\n" );
+       
+}
+
+//===========================================================================================================================
+//     QueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       QueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       QueryRecordContext * const              context         = (QueryRecordContext *) inContext;
+       struct timeval                                  now;
+       OSStatus                                                err;
+       char *                                                  rdataStr        = NULL;
+       
+       Unused( inSDRef );
+       
+       gettimeofday( &now, NULL );
+       
+       switch( inError )
+       {
+               case kDNSServiceErr_NoError:
+               case kDNSServiceErr_NoSuchRecord:
+                       err = kNoErr;
+                       break;
+               
+               case kDNSServiceErr_Timeout:
+                       Exit( kExitReason_Timeout );
+               
+               default:
+                       err = inError;
+                       goto exit;
+       }
+       
+       if( inError != kDNSServiceErr_NoSuchRecord )
+       {
+               if( !context->printRawRData ) DNSRecordDataToString( inRDataPtr, inRDataLen, inType, NULL, 0, &rdataStr );
+               if( !rdataStr )
+               {
+                       ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, INT_MAX );
+                       require_action( rdataStr, exit, err = kNoMemoryErr );
+               }
+       }
+       
+       if( !context->printedHeader )
+       {
+               FPrintF( stdout, "%-26s  %-16s IF %-32s %-5s %-5s %6s RData\n",
+                       "Timestamp", "Flags", "Name", "Type", "Class", "TTL" );
+               context->printedHeader = true;
+       }
+       FPrintF( stdout, "%{du:time}  %{du:cbflags} %2d %-32s %-5s %?-5s%?5u %6u %s\n",
+               &now, inFlags, (int32_t) inInterfaceIndex, inFullName, RecordTypeToString( inType ),
+               ( inClass == kDNSServiceClass_IN ), "IN", ( inClass != kDNSServiceClass_IN ), inClass, inTTL,
+               rdataStr ? rdataStr : kNoSuchRecordStr );
+       
+       if( context->oneShotMode )
+       {
+               if( ( inFlags & kDNSServiceFlagsAdd ) &&
+                       ( ( context->recordType == kDNSServiceType_ANY ) || ( context->recordType == inType ) ) )
+               {
+                       context->gotRecord = true;
+               }
+               if( !( inFlags & kDNSServiceFlagsMoreComing ) && context->gotRecord ) Exit( kExitReason_OneShotDone );
+       }
+       
+exit:
+       FreeNullSafe( rdataStr );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     RegisterCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSRecordRef            recordRef;      // Reference returned by DNSServiceAddRecord().
+       uint8_t *                       dataPtr;        // Record data.
+       size_t                          dataLen;        // Record data length.
+       uint32_t                        ttl;            // Record TTL value.
+       uint16_t                        type;           // Record type.
+       
+}      ExtraRecord;
+
+typedef struct
+{
+       DNSServiceRef           opRef;                          // sdRef for DNSServiceRegister operation.
+       const char *            name;                           // Service name argument for DNSServiceRegister().
+       const char *            type;                           // Service type argument for DNSServiceRegister().
+       const char *            domain;                         // Domain in which advertise the service.
+       uint8_t *                       txtPtr;                         // Service TXT record data. (malloc'd)
+       size_t                          txtLen;                         // Service TXT record data len.
+       ExtraRecord *           extraRecords;           // Array of extra records to add to registered service.
+       size_t                          extraRecordsCount;      // Number of extra records.
+       uint8_t *                       updateTXTPtr;           // Pointer to record data for TXT record update. (malloc'd)
+       size_t                          updateTXTLen;           // Length of record data for TXT record update.
+       uint32_t                        updateTTL;                      // TTL of updated TXT record.
+       int                                     updateDelayMs;          // Post-registration TXT record update delay in milliseconds.
+       DNSServiceFlags         flags;                          // Flags argument for DNSServiceRegister().
+       uint32_t                        ifIndex;                        // Interface index argument for DNSServiceRegister().
+       int                                     lifetimeMs;                     // Lifetime of the record registration in milliseconds.
+       uint16_t                        port;                           // Service instance's port number.
+       Boolean                         printedHeader;          // True if results header was printed.
+       Boolean                         didRegister;            // True if service was registered.
+       
+}      RegisterContext;
+
+static void    RegisterPrintPrologue( const RegisterContext *inContext );
+static void    RegisterContextFree( RegisterContext *inContext );
+static void DNSSD_API
+       RegisterCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inType,
+               const char *            inDomain,
+               void *                          inContext );
+static void    RegisterUpdate( void *inContext );
+
+static void    RegisterCmd( void )
+{
+       OSStatus                                err;
+       RegisterContext *               context                 = NULL;
+       dispatch_source_t               signalSource    = NULL;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Create context.
+       
+       context = (RegisterContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       // Check command parameters.
+       
+       if( ( gRegister_Port < 0 ) || ( gRegister_Port > UINT16_MAX ) )
+       {
+               FPrintF( stderr, "Port number %d is out-of-range.\n", gRegister_Port );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       if( ( gAddRecord_DataCount != gAddRecord_TypesCount ) || ( gAddRecord_TTLsCount != gAddRecord_TypesCount ) )
+       {
+               FPrintF( stderr, "There are missing additional record parameters.\n" );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       
+       // Get interface index.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Get TXT record data.
+       
+       if( gRegister_TXT )
+       {
+               err = RecordDataFromArgString( gRegister_TXT, &context->txtPtr, &context->txtLen );
+               require_noerr_quiet( err, exit );
+       }
+       
+       // Set remaining parameters.
+       
+       context->name           = gRegister_Name;
+       context->type           = gRegister_Type;
+       context->domain         = gRegister_Domain;
+       context->port           = (uint16_t) gRegister_Port;
+       context->lifetimeMs     = gRegister_LifetimeMs;
+       
+       if( gAddRecord_TypesCount > 0 )
+       {
+               size_t          i;
+               
+               context->extraRecords = (ExtraRecord *) calloc( gAddRecord_TypesCount, sizeof( ExtraRecord ) );
+               require_action( context, exit, err = kNoMemoryErr );
+               context->extraRecordsCount = gAddRecord_TypesCount;
+               
+               for( i = 0; i < gAddRecord_TypesCount; ++i )
+               {
+                       ExtraRecord * const             extraRecord = &context->extraRecords[ i ];
+                       
+                       err = RecordTypeFromArgString( gAddRecord_Types[ i ], &extraRecord->type );
+                       require_noerr( err, exit );
+                       
+                       err = StringToUInt32( gAddRecord_TTLs[ i ], &extraRecord->ttl );
+                       if( err )
+                       {
+                               FPrintF( stderr, "Invalid TTL value: %s\n", gAddRecord_TTLs[ i ] );
+                               err = kParamErr;
+                               goto exit;
+                       }
+                       
+                       err = RecordDataFromArgString( gAddRecord_Data[ i ], &extraRecord->dataPtr, &extraRecord->dataLen );
+                       require_noerr_quiet( err, exit );
+               }
+       }
+       
+       if( gUpdateRecord_Data )
+       {
+               err = RecordDataFromArgString( gUpdateRecord_Data, &context->updateTXTPtr, &context->updateTXTLen );
+               require_noerr_quiet( err, exit );
+               
+               context->updateTTL              = (uint32_t) gUpdateRecord_TTL;
+               context->updateDelayMs  = gUpdateRecord_DelayMs;
+       }
+       
+       // Print prologue.
+       
+       RegisterPrintPrologue( context );
+       
+       // Start operation.
+       
+       err = DNSServiceRegister( &context->opRef, context->flags, context->ifIndex, context->name, context->type,
+               context->domain, NULL, htons( context->port ), (uint16_t) context->txtLen, context->txtPtr,
+               RegisterCallback, context );
+       ForgetMem( &context->txtPtr );
+       require_noerr( err, exit );
+       
+       err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+       require_noerr( err, exit );
+       
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) RegisterContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     RegisterPrintPrologue
+//===========================================================================================================================
+
+static void    RegisterPrintPrologue( const RegisterContext *inContext )
+{
+       size_t          i;
+       int                     infinite;
+       char            ifName[ kInterfaceNameBufLen ];
+       
+       InterfaceIndexToName( inContext->ifIndex, ifName );
+       
+       FPrintF( stdout, "Flags:      %#{flags}\n",     inContext->flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:  %d (%s)\n",       (int32_t) inContext->ifIndex, ifName );
+       FPrintF( stdout, "Name:       %s\n",            inContext->name ? inContext->name : "<NULL>" );
+       FPrintF( stdout, "Type:       %s\n",            inContext->type );
+       FPrintF( stdout, "Domain:     %s\n",            inContext->domain ? inContext->domain : "<NULL> (default domains)" );
+       FPrintF( stdout, "Port:       %u\n",            inContext->port );
+       FPrintF( stdout, "TXT data:   %#{txt}\n",       inContext->txtPtr, inContext->txtLen );
+       infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
+       FPrintF( stdout, "Lifetime:   %?s%?d ms\n",     infinite, "∞", !infinite, inContext->lifetimeMs );
+       if( inContext->updateTXTPtr )
+       {
+               FPrintF( stdout, "\nUpdate record:\n" );
+               FPrintF( stdout, "    Delay:    %d ms\n",       ( inContext->updateDelayMs > 0 ) ? inContext->updateDelayMs : 0 );
+               FPrintF( stdout, "    TTL:      %u%?s\n",
+                       inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
+               FPrintF( stdout, "    TXT data: %#{txt}\n",     inContext->updateTXTPtr, inContext->updateTXTLen );
+       }
+       if( inContext->extraRecordsCount > 0 ) FPrintF( stdout, "\n" );
+       for( i = 0; i < inContext->extraRecordsCount; ++i )
+       {
+               const ExtraRecord *             record = &inContext->extraRecords[ i ];
+               
+               FPrintF( stdout, "Extra record %zu:\n",         i + 1 );
+               FPrintF( stdout, "    Type:  %s (%u)\n",        RecordTypeToString( record->type ), record->type );
+               FPrintF( stdout, "    TTL:   %u%?s\n",          record->ttl, record->ttl == 0, " (system will use a default value.)" );
+               FPrintF( stdout, "    RData: %#H\n\n",          record->dataPtr, (int) record->dataLen, INT_MAX );
+       }
+       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
+       FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+//     RegisterContextFree
+//===========================================================================================================================
+
+static void    RegisterContextFree( RegisterContext *inContext )
+{
+       ExtraRecord *                                   record;
+       const ExtraRecord * const               end = inContext->extraRecords + inContext->extraRecordsCount;
+       
+       DNSServiceForget( &inContext->opRef );
+       ForgetMem( &inContext->txtPtr );
+       for( record = inContext->extraRecords; record < end; ++record )
+       {
+               check( !record->recordRef );
+               ForgetMem( &record->dataPtr );
+       }
+       ForgetMem( &inContext->extraRecords );
+       ForgetMem( &inContext->updateTXTPtr );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     RegisterCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       RegisterCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inType,
+               const char *            inDomain,
+               void *                          inContext )
+{
+       RegisterContext * const         context = (RegisterContext *) inContext;
+       OSStatus                                        err;
+       struct timeval                          now;
+       
+       Unused( inSDRef );
+       
+       gettimeofday( &now, NULL );
+       
+       if( !context->printedHeader )
+       {
+               FPrintF( stdout, "%-26s  %-16s Service\n", "Timestamp", "Flags" );
+               context->printedHeader = true;
+       }
+       FPrintF( stdout, "%{du:time}  %{du:cbflags} %s.%s%s %?#m\n", &now, inFlags, inName, inType, inDomain, inError, inError );
+       
+       require_noerr_action_quiet( inError, exit, err = inError );
+       
+       if( !context->didRegister && ( inFlags & kDNSServiceFlagsAdd ) )
+       {
+               context->didRegister = true;
+               if( context->updateTXTPtr )
+               {
+                       if( context->updateDelayMs > 0 )
+                       {
+                               dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
+                                       context, RegisterUpdate );
+                       }
+                       else
+                       {
+                               RegisterUpdate( context );
+                       }
+               }
+               if( context->extraRecordsCount > 0 )
+               {
+                       ExtraRecord *                                   record;
+                       const ExtraRecord * const               end = context->extraRecords + context->extraRecordsCount;
+                       
+                       for( record = context->extraRecords; record < end; ++record )
+                       {
+                               err = DNSServiceAddRecord( context->opRef, &record->recordRef, 0, record->type,
+                                       (uint16_t) record->dataLen, record->dataPtr, record->ttl );
+                               require_noerr( err, exit );
+                       }
+               }
+               if( context->lifetimeMs == 0 )
+               {
+                       Exit( kExitReason_TimeLimit );
+               }
+               else if( context->lifetimeMs > 0 )
+               {
+                       dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
+                               kExitReason_TimeLimit, Exit );
+               }
+       }
+       err = kNoErr;
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     RegisterUpdate
+//===========================================================================================================================
+
+static void    RegisterUpdate( void *inContext )
+{
+       OSStatus                                        err;
+       RegisterContext * const         context = (RegisterContext *) inContext;
+       
+       err = DNSServiceUpdateRecord( context->opRef, NULL, 0, (uint16_t) context->updateTXTLen, context->updateTXTPtr,
+               context->updateTTL );
+       require_noerr( err, exit );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     RegisterRecordCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSServiceRef           conRef;                 // sdRef to be initialized by DNSServiceCreateConnection().
+       DNSRecordRef            recordRef;              // Registered record reference.
+       const char *            recordName;             // Name of resource record.
+       uint8_t *                       dataPtr;                // Pointer to resource record data.
+       size_t                          dataLen;                // Length of resource record data.
+       uint32_t                        ttl;                    // TTL value of resource record in seconds.
+       uint32_t                        ifIndex;                // Interface index argument for DNSServiceRegisterRecord().
+       DNSServiceFlags         flags;                  // Flags argument for DNSServiceRegisterRecord().
+       int                                     lifetimeMs;             // Lifetime of the record registration in milliseconds.
+       uint16_t                        recordType;             // Resource record type.
+       uint8_t *                       updateDataPtr;  // Pointer to data for record update. (malloc'd)
+       size_t                          updateDataLen;  // Length of data for record update.
+       uint32_t                        updateTTL;              // TTL for updated record.
+       int                                     updateDelayMs;  // Post-registration record update delay in milliseconds.
+       Boolean                         didRegister;    // True if the record was registered.
+       
+}      RegisterRecordContext;
+
+static void    RegisterRecordPrintPrologue( const RegisterRecordContext *inContext );
+static void    RegisterRecordContextFree( RegisterRecordContext *inContext );
+static void DNSSD_API
+       RegisterRecordCallback(
+               DNSServiceRef           inSDRef,
+               DNSRecordRef            inRecordRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               void *                          inContext );
+static void    RegisterRecordUpdate( void *inContext );
+
+static void    RegisterRecordCmd( void )
+{
+       OSStatus                                        err;
+       RegisterRecordContext *         context                 = NULL;
+       dispatch_source_t                       signalSource    = NULL;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Create context.
+       
+       context = (RegisterRecordContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       // Create connection.
+       
+       err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->conRef, NULL );
+       require_noerr_quiet( err, exit );
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       
+       // Get interface.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Get record type.
+       
+       err = RecordTypeFromArgString( gRegisterRecord_Type, &context->recordType );
+       require_noerr( err, exit );
+       
+       // Get record data.
+       
+       if( gRegisterRecord_Data )
+       {
+               err = RecordDataFromArgString( gRegisterRecord_Data, &context->dataPtr, &context->dataLen );
+               require_noerr_quiet( err, exit );
+       }
+       
+       // Set remaining parameters.
+       
+       context->recordName     = gRegisterRecord_Name;
+       context->ttl            = (uint32_t) gRegisterRecord_TTL;
+       context->lifetimeMs     = gRegisterRecord_LifetimeMs;
+       
+       // Get update data.
+       
+       if( gRegisterRecord_UpdateData )
+       {
+               err = RecordDataFromArgString( gRegisterRecord_UpdateData, &context->updateDataPtr, &context->updateDataLen );
+               require_noerr_quiet( err, exit );
+               
+               context->updateTTL              = (uint32_t) gRegisterRecord_UpdateTTL;
+               context->updateDelayMs  = gRegisterRecord_UpdateDelayMs;
+       }
+       
+       // Print prologue.
+       
+       RegisterRecordPrintPrologue( context );
+       
+       // Start operation.
+       
+       err = DNSServiceRegisterRecord( context->conRef, &context->recordRef, context->flags, context->ifIndex,
+               context->recordName, context->recordType, kDNSServiceClass_IN, (uint16_t) context->dataLen, context->dataPtr,
+               context->ttl, RegisterRecordCallback, context );
+       if( err )
+       {
+               FPrintF( stderr, "DNSServiceRegisterRecord() returned %#m\n", err );
+               goto exit;
+       }
+       
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) RegisterRecordContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     RegisterRecordPrintPrologue
+//===========================================================================================================================
+
+static void    RegisterRecordPrintPrologue( const RegisterRecordContext *inContext )
+{
+       int                     infinite;
+       char            ifName[ kInterfaceNameBufLen ];
+       
+       InterfaceIndexToName( inContext->ifIndex, ifName );
+       
+       FPrintF( stdout, "Flags:       %#{flags}\n",    inContext->flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:   %d (%s)\n",              (int32_t) inContext->ifIndex, ifName );
+       FPrintF( stdout, "Name:        %s\n",                   inContext->recordName );
+       FPrintF( stdout, "Type:        %s (%u)\n",              RecordTypeToString( inContext->recordType ), inContext->recordType );
+       FPrintF( stdout, "TTL:         %u\n",                   inContext->ttl );
+       FPrintF( stdout, "Data:        %#H\n",                  inContext->dataPtr, (int) inContext->dataLen, INT_MAX );
+       infinite = ( inContext->lifetimeMs < 0 ) ? true : false;
+       FPrintF( stdout, "Lifetime:    %?s%?d ms\n",    infinite, "∞", !infinite, inContext->lifetimeMs );
+       if( inContext->updateDataPtr )
+       {
+               FPrintF( stdout, "\nUpdate record:\n" );
+               FPrintF( stdout, "    Delay:    %d ms\n",       ( inContext->updateDelayMs >= 0 ) ? inContext->updateDelayMs : 0 );
+               FPrintF( stdout, "    TTL:      %u%?s\n",
+                       inContext->updateTTL, inContext->updateTTL == 0, " (system will use a default value.)" );
+               FPrintF( stdout, "    RData:    %#H\n",         inContext->updateDataPtr, (int) inContext->updateDataLen, INT_MAX );
+       }
+       FPrintF( stdout, "Start time:  %{du:time}\n",   NULL );
+       FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+//     RegisterRecordContextFree
+//===========================================================================================================================
+
+static void    RegisterRecordContextFree( RegisterRecordContext *inContext )
+{
+       DNSServiceForget( &inContext->conRef );
+       ForgetMem( &inContext->dataPtr );
+       ForgetMem( &inContext->updateDataPtr );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     RegisterRecordCallback
+//===========================================================================================================================
+
+static void
+       RegisterRecordCallback(
+               DNSServiceRef           inSDRef,
+               DNSRecordRef            inRecordRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               void *                          inContext )
+{
+       RegisterRecordContext *         context = (RegisterRecordContext *) inContext;
+       struct timeval                          now;
+       
+       Unused( inSDRef );
+       Unused( inRecordRef );
+       Unused( inFlags );
+       Unused( context );
+       
+       gettimeofday( &now, NULL );
+       FPrintF( stdout, "%{du:time} Record registration result (error %#m)\n", &now, inError );
+       
+       if( !context->didRegister && !inError )
+       {
+               context->didRegister = true;
+               if( context->updateDataPtr )
+               {
+                       if( context->updateDelayMs > 0 )
+                       {
+                               dispatch_after_f( dispatch_time_milliseconds( context->updateDelayMs ), dispatch_get_main_queue(),
+                                       context, RegisterRecordUpdate );
+                       }
+                       else
+                       {
+                               RegisterRecordUpdate( context );
+                       }
+               }
+               if( context->lifetimeMs == 0 )
+               {
+                       Exit( kExitReason_TimeLimit );
+               }
+               else if( context->lifetimeMs > 0 )
+               {
+                       dispatch_after_f( dispatch_time_milliseconds( context->lifetimeMs ), dispatch_get_main_queue(),
+                               kExitReason_TimeLimit, Exit );
+               }
+       }
+}
+
+//===========================================================================================================================
+//     RegisterRecordUpdate
+//===========================================================================================================================
+
+static void    RegisterRecordUpdate( void *inContext )
+{
+       OSStatus                                                        err;
+       RegisterRecordContext * const           context = (RegisterRecordContext *) inContext;
+       
+       err = DNSServiceUpdateRecord( context->conRef, context->recordRef, 0, (uint16_t) context->updateDataLen,
+               context->updateDataPtr, context->updateTTL );
+       require_noerr( err, exit );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     ResolveCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSServiceRef           mainRef;                // Main sdRef for shared connections.
+       DNSServiceRef           opRef;                  // sdRef for the DNSServiceResolve operation.
+       DNSServiceFlags         flags;                  // Flags argument for DNSServiceResolve().
+       const char *            name;                   // Service name argument for DNSServiceResolve().
+       const char *            type;                   // Service type argument for DNSServiceResolve().
+       const char *            domain;                 // Domain argument for DNSServiceResolve().
+       uint32_t                        ifIndex;                // Interface index argument for DNSServiceResolve().
+       int                                     timeLimitSecs;  // Time limit for the DNSServiceResolve operation in seconds.
+       
+}      ResolveContext;
+
+static void    ResolvePrintPrologue( const ResolveContext *inContext );
+static void    ResolveContextFree( ResolveContext *inContext );
+static void DNSSD_API
+       ResolveCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               uint16_t                                inTXTLen,
+               const unsigned char *   inTXTPtr,
+               void *                                  inContext );
+
+static void    ResolveCmd( void )
+{
+       OSStatus                                err;
+       DNSServiceRef                   sdRef;
+       ResolveContext *                context                 = NULL;
+       dispatch_source_t               signalSource    = NULL;
+       int                                             useMainConnection;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Create context.
+       
+       context = (ResolveContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       // Check command parameters.
+       
+       if( gResolve_TimeLimitSecs < 0 )
+       {
+               FPrintF( stderr, "Invalid time limit: %d seconds.\n", gResolve_TimeLimitSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create main connection.
+       
+       if( gConnectionOpt )
+       {
+               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+               require_noerr_quiet( err, exit );
+               useMainConnection = true;
+       }
+       else
+       {
+               useMainConnection = false;
+       }
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+       
+       // Get interface index.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Set remaining parameters.
+       
+       context->name                   = gResolve_Name;
+       context->type                   = gResolve_Type;
+       context->domain                 = gResolve_Domain;
+       context->timeLimitSecs  = gResolve_TimeLimitSecs;
+       
+       // Print prologue.
+       
+       ResolvePrintPrologue( context );
+       
+       // Start operation.
+       
+       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+       err = DNSServiceResolve( &sdRef, context->flags, context->ifIndex, context->name, context->type, context->domain,
+               ResolveCallback, NULL );
+       require_noerr( err, exit );
+       
+       context->opRef = sdRef;
+       if( !useMainConnection )
+       {
+               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+               require_noerr( err, exit );
+       }
+       
+       // Set time limit.
+       
+       if( context->timeLimitSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+                       kExitReason_TimeLimit, Exit );
+       }
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) ResolveContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     ReconfirmCmd
+//===========================================================================================================================
+
+static void    ReconfirmCmd( void )
+{
+       OSStatus                        err;
+       uint8_t *                       rdataPtr = NULL;
+       size_t                          rdataLen = 0;
+       DNSServiceFlags         flags;
+       uint32_t                        ifIndex;
+       uint16_t                        type, class;
+       char                            ifName[ kInterfaceNameBufLen ];
+       
+       // Get flags.
+       
+       flags = GetDNSSDFlagsFromOpts();
+       
+       // Get interface index.
+       
+       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Get record type.
+       
+       err = RecordTypeFromArgString( gReconfirmRecord_Type, &type );
+       require_noerr( err, exit );
+       
+       // Get record data.
+       
+       if( gReconfirmRecord_Data )
+       {
+               err = RecordDataFromArgString( gReconfirmRecord_Data, &rdataPtr, &rdataLen );
+               require_noerr_quiet( err, exit );
+       }
+       
+       // Get record class.
+       
+       if( gReconfirmRecord_Class )
+       {
+               err = RecordClassFromArgString( gReconfirmRecord_Class, &class );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               class = kDNSServiceClass_IN;
+       }
+       
+       // Print prologue.
+       
+       FPrintF( stdout, "Flags:     %#{flags}\n",      flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface: %d (%s)\n",        (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+       FPrintF( stdout, "Name:      %s\n",                     gReconfirmRecord_Name );
+       FPrintF( stdout, "Type:      %s (%u)\n",        RecordTypeToString( type ), type );
+       FPrintF( stdout, "Class:     %s (%u)\n",        ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
+       FPrintF( stdout, "Data:      %#H\n",            rdataPtr, (int) rdataLen, INT_MAX );
+       FPrintF( stdout, "---\n" );
+       
+       err = DNSServiceReconfirmRecord( flags, ifIndex, gReconfirmRecord_Name, type, class, (uint16_t) rdataLen, rdataPtr );
+       FPrintF( stdout, "Error:     %#m\n", err );
+       
+exit:
+       FreeNullSafe( rdataPtr );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     ResolvePrintPrologue
+//===========================================================================================================================
+
+static void    ResolvePrintPrologue( const ResolveContext *inContext )
+{
+       const int               timeLimitSecs = inContext->timeLimitSecs;
+       char                    ifName[ kInterfaceNameBufLen ];
+       
+       InterfaceIndexToName( inContext->ifIndex, ifName );
+       
+       FPrintF( stdout, "Flags:      %#{flags}\n",             inContext->flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:  %d (%s)\n",               (int32_t) inContext->ifIndex, ifName );
+       FPrintF( stdout, "Name:       %s\n",                    inContext->name );
+       FPrintF( stdout, "Type:       %s\n",                    inContext->type );
+       FPrintF( stdout, "Domain:     %s\n",                    inContext->domain );
+       FPrintF( stdout, "Time limit: " );
+       if( timeLimitSecs > 0 ) FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+       else                                    FPrintF( stdout, "∞\n" );
+       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
+       FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+//     ResolveContextFree
+//===========================================================================================================================
+
+static void    ResolveContextFree( ResolveContext *inContext )
+{
+       DNSServiceForget( &inContext->opRef );
+       DNSServiceForget( &inContext->mainRef );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     ResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       ResolveCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               uint16_t                                inTXTLen,
+               const unsigned char *   inTXTPtr,
+               void *                                  inContext )
+{
+       struct timeval          now;
+       char                            errorStr[ 64 ];
+       
+       Unused( inSDRef );
+       Unused( inFlags );
+       Unused( inContext );
+       
+       gettimeofday( &now, NULL );
+       
+       if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " error %#m", inError );
+       
+       FPrintF( stdout, "%{du:time}: %s can be reached at %s:%u (interface %d)%?s\n",
+               &now, inFullName, inHostname, ntohs( inPort ), (int32_t) inInterfaceIndex, inError, errorStr );
+       if( inTXTLen == 1 )
+       {
+               FPrintF( stdout, " TXT record: %#H\n", inTXTPtr, (int) inTXTLen, INT_MAX );
+       }
+       else
+       {
+               FPrintF( stdout, " TXT record: %#{txt}\n", inTXTPtr, (size_t) inTXTLen );
+       }
+}
+
+//===========================================================================================================================
+//     GetAddrInfoPOSIXCmd
+//===========================================================================================================================
+
+#define AddressFamilyStr( X ) (                                \
+       ( (X) == AF_INET )              ? "inet"        :       \
+       ( (X) == AF_INET6 )             ? "inet6"       :       \
+       ( (X) == AF_UNSPEC )    ? "unspec"      :       \
+                                                         "???" )
+
+typedef struct
+{
+    unsigned int               flag;
+    const char *        str;
+
+}   FlagStringPair;
+
+#define CaseFlagStringify( X )         { (X), # X }
+
+const FlagStringPair           kGAIPOSIXFlagStringPairs[] =
+{
+#if( defined( AI_UNUSABLE ) )
+       CaseFlagStringify( AI_UNUSABLE ),
+#endif
+       CaseFlagStringify( AI_NUMERICSERV ),
+       CaseFlagStringify( AI_V4MAPPED ),
+       CaseFlagStringify( AI_ADDRCONFIG ),
+#if( defined( AI_V4MAPPED_CFG ) )
+       CaseFlagStringify( AI_V4MAPPED_CFG ),
+#endif
+       CaseFlagStringify( AI_ALL ),
+       CaseFlagStringify( AI_NUMERICHOST ),
+       CaseFlagStringify( AI_CANONNAME ),
+       CaseFlagStringify( AI_PASSIVE ),
+       { 0, NULL }
+};
+
+static void    GetAddrInfoPOSIXCmd( void )
+{
+       OSStatus                                        err;
+       struct addrinfo                         hints;
+       struct timeval                          now;
+       const struct addrinfo *         addrInfo;
+       struct addrinfo *                       addrInfoList = NULL;
+       const FlagStringPair *          pair;
+       
+       memset( &hints, 0, sizeof( hints ) );
+       hints.ai_socktype = SOCK_STREAM;
+       
+       // Set hints address family.
+       
+       if( !gGAIPOSIX_Family )                                                                         hints.ai_family = AF_UNSPEC;
+       else if( strcasecmp( gGAIPOSIX_Family, "inet" ) == 0 )          hints.ai_family = AF_INET;
+       else if( strcasecmp( gGAIPOSIX_Family, "inet6" ) == 0 )         hints.ai_family = AF_INET6;
+       else if( strcasecmp( gGAIPOSIX_Family, "unspec" ) == 0 )        hints.ai_family = AF_UNSPEC;
+       else
+       {
+               FPrintF( stderr, "Invalid address family: %s.\n", gGAIPOSIX_Family );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Set hints flags.
+       
+       if( gGAIPOSIXFlag_AddrConfig )  hints.ai_flags |= AI_ADDRCONFIG;
+       if( gGAIPOSIXFlag_All )                 hints.ai_flags |= AI_ALL;
+       if( gGAIPOSIXFlag_CanonName )   hints.ai_flags |= AI_CANONNAME;
+       if( gGAIPOSIXFlag_NumericHost ) hints.ai_flags |= AI_NUMERICHOST;
+       if( gGAIPOSIXFlag_NumericServ ) hints.ai_flags |= AI_NUMERICSERV;
+       if( gGAIPOSIXFlag_Passive )             hints.ai_flags |= AI_PASSIVE;
+       if( gGAIPOSIXFlag_V4Mapped )    hints.ai_flags |= AI_V4MAPPED;
+#if( defined( AI_V4MAPPED_CFG ) )
+       if( gGAIPOSIXFlag_V4MappedCFG ) hints.ai_flags |= AI_V4MAPPED_CFG;
+#endif
+#if( defined( AI_DEFAULT ) )
+       if( gGAIPOSIXFlag_Default )             hints.ai_flags |= AI_DEFAULT;
+#endif
+#if( defined( AI_UNUSABLE ) )
+       if( gGAIPOSIXFlag_Unusable )    hints.ai_flags |= AI_UNUSABLE;
+#endif
+       
+       // Print prologue.
+       
+       FPrintF( stdout, "Hostname:       %s\n",        gGAIPOSIX_HostName );
+       FPrintF( stdout, "Servname:       %s\n",        gGAIPOSIX_ServName );
+       FPrintF( stdout, "Address family: %s\n",        AddressFamilyStr( hints.ai_family ) );
+       FPrintF( stdout, "Flags:          0x%X < ",     hints.ai_flags );
+       for( pair = kGAIPOSIXFlagStringPairs; pair->str != NULL; ++pair )
+       {
+               if( ( (unsigned int) hints.ai_flags ) & pair->flag ) FPrintF( stdout, "%s ", pair->str );
+       }
+       FPrintF( stdout, ">\n" );
+       FPrintF( stdout, "Start time:     %{du:time}\n", NULL );
+       FPrintF( stdout, "---\n" );
+       
+       // Call getaddrinfo().
+       
+       err = getaddrinfo( gGAIPOSIX_HostName, gGAIPOSIX_ServName, &hints, &addrInfoList );
+       gettimeofday( &now, NULL );
+       if( err )
+       {
+               FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
+       }
+       else
+       {
+               int             addrCount = 0;
+               
+               for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next ) { ++addrCount; }
+               
+               FPrintF( stdout, "Addresses (%d total):\n", addrCount );
+               for( addrInfo = addrInfoList; addrInfo; addrInfo = addrInfo->ai_next )
+               {
+                       FPrintF( stdout, "%##a\n", addrInfo->ai_addr );
+               }
+       }
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "End time:       %{du:time}\n", &now );
+       
+exit:
+       if( addrInfoList ) freeaddrinfo( addrInfoList );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     ReverseLookupCmd
+//===========================================================================================================================
+
+#define kIP6ARPADomainStr              "ip6.arpa."
+
+static void    ReverseLookupCmd( void )
+{
+       OSStatus                                        err;
+       QueryRecordContext *            context                 = NULL;
+       DNSServiceRef                           sdRef;
+       dispatch_source_t                       signalSource    = NULL;
+       uint32_t                                        ipv4Addr;
+       uint8_t                                         ipv6Addr[ 16 ];
+       char                                            recordName[ ( 16 * 4 ) + sizeof( kIP6ARPADomainStr ) ];
+       int                                                     useMainConnection;
+       const char *                            endPtr;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Create context.
+       
+       context = (QueryRecordContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       // Check command parameters.
+       
+       if( gReverseLookup_TimeLimitSecs < 0 )
+       {
+               FPrintF( stderr, "Invalid time limit: %d s.\n", gReverseLookup_TimeLimitSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create main connection.
+       
+       if( gConnectionOpt )
+       {
+               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+               require_noerr_quiet( err, exit );
+               useMainConnection = true;
+       }
+       else
+       {
+               useMainConnection = false;
+       }
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+       
+       // Get interface index.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Create reverse lookup record name.
+       
+       err = _StringToIPv4Address( gReverseLookup_IPAddr, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix,
+               &ipv4Addr, NULL, NULL, NULL, &endPtr );
+       if( err || ( *endPtr != '\0' ) )
+       {
+               char *          dst;
+               int                     i;
+               
+               err = _StringToIPv6Address( gReverseLookup_IPAddr,
+                       kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
+                       ipv6Addr, NULL, NULL, NULL, &endPtr );
+               if( err || ( *endPtr != '\0' ) )
+               {
+                       FPrintF( stderr, "Invalid IP address: \"%s\".\n", gReverseLookup_IPAddr );
+                       err = kParamErr;
+                       goto exit;
+               }
+               dst = recordName;
+               for( i = 15; i >= 0; --i )
+               {
+                       *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] & 0x0F ];
+                       *dst++ = '.';
+                       *dst++ = kHexDigitsLowercase[ ipv6Addr[ i ] >> 4 ];
+                       *dst++ = '.';
+               }
+               strcpy_literal( dst, kIP6ARPADomainStr );
+               check( ( strlen( recordName ) + 1 ) <= sizeof( recordName ) );
+       }
+       else
+       {
+               SNPrintF( recordName, sizeof( recordName ), "%u.%u.%u.%u.in-addr.arpa.",
+                         ipv4Addr         & 0xFF,
+                       ( ipv4Addr >>  8 ) & 0xFF,
+                       ( ipv4Addr >> 16 ) & 0xFF,
+                       ( ipv4Addr >> 24 ) & 0xFF );
+       }
+       
+       // Set remaining parameters.
+       
+       context->recordName             = recordName;
+       context->recordType             = kDNSServiceType_PTR;
+       context->timeLimitSecs  = gReverseLookup_TimeLimitSecs;
+       context->oneShotMode    = gReverseLookup_OneShot ? true : false;
+       
+       // Print prologue.
+       
+       QueryRecordPrintPrologue( context );
+       
+       // Start operation.
+       
+       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+       err = DNSServiceQueryRecord( &sdRef, context->flags, context->ifIndex, context->recordName, context->recordType,
+               kDNSServiceClass_IN, QueryRecordCallback, context );
+       require_noerr( err, exit );
+       
+       context->opRef = sdRef;
+       if( !useMainConnection )
+       {
+               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+               require_noerr( err, exit );
+       }
+       
+       // Set time limit.
+       
+       if( context->timeLimitSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(),
+                       kExitReason_TimeLimit, Exit );
+       }
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) QueryRecordContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     PortMappingCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSServiceRef                   mainRef;                // Main sdRef for shared connection.
+       DNSServiceRef                   opRef;                  // sdRef for the DNSServiceNATPortMappingCreate operation.
+       DNSServiceFlags                 flags;                  // Flags for DNSServiceNATPortMappingCreate operation.
+       uint32_t                                ifIndex;                // Interface index argument for DNSServiceNATPortMappingCreate operation.
+       DNSServiceProtocol              protocols;              // Protocols argument for DNSServiceNATPortMappingCreate operation.
+       uint32_t                                ttl;                    // TTL argument for DNSServiceNATPortMappingCreate operation.
+       uint16_t                                internalPort;   // Internal port argument for DNSServiceNATPortMappingCreate operation.
+       uint16_t                                externalPort;   // External port argument for DNSServiceNATPortMappingCreate operation.
+       Boolean                                 printedHeader;  // True if results header was printed.
+       
+}      PortMappingContext;
+
+static void    PortMappingPrintPrologue( const PortMappingContext *inContext );
+static void    PortMappingContextFree( PortMappingContext *inContext );
+static void DNSSD_API
+       PortMappingCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inError,
+               uint32_t                        inExternalIPv4Address,
+               DNSServiceProtocol      inProtocol,
+               uint16_t                        inInternalPort,
+               uint16_t                        inExternalPort,
+               uint32_t                        inTTL,
+               void *                          inContext );
+
+static void    PortMappingCmd( void )
+{
+       OSStatus                                        err;
+       PortMappingContext *            context                 = NULL;
+       DNSServiceRef                           sdRef;
+       dispatch_source_t                       signalSource    = NULL;
+       int                                                     useMainConnection;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Create context.
+       
+       context = (PortMappingContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       // Check command parameters.
+       
+       if( ( gPortMapping_InternalPort < 0 ) || ( gPortMapping_InternalPort > UINT16_MAX ) )
+       {
+               FPrintF( stderr, "Internal port number %d is out-of-range.\n", gPortMapping_InternalPort );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       if( ( gPortMapping_ExternalPort < 0 ) || ( gPortMapping_ExternalPort > UINT16_MAX ) )
+       {
+               FPrintF( stderr, "External port number %d is out-of-range.\n", gPortMapping_ExternalPort );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create main connection.
+       
+       if( gConnectionOpt )
+       {
+               err = CreateConnectionFromArgString( gConnectionOpt, dispatch_get_main_queue(), &context->mainRef, NULL );
+               require_noerr_quiet( err, exit );
+               useMainConnection = true;
+       }
+       else
+       {
+               useMainConnection = false;
+       }
+       
+       // Get flags.
+       
+       context->flags = GetDNSSDFlagsFromOpts();
+       if( useMainConnection ) context->flags |= kDNSServiceFlagsShareConnection;
+       
+       // Get interface index.
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Set remaining parameters.
+       
+       if( gPortMapping_ProtocolTCP ) context->protocols |= kDNSServiceProtocol_TCP;
+       if( gPortMapping_ProtocolUDP ) context->protocols |= kDNSServiceProtocol_UDP;
+       context->ttl                    = (uint32_t) gPortMapping_TTL;
+       context->internalPort   = (uint16_t) gPortMapping_InternalPort;
+       context->externalPort   = (uint16_t) gPortMapping_ExternalPort;
+       
+       // Print prologue.
+       
+       PortMappingPrintPrologue( context );
+       
+       // Start operation.
+       
+       sdRef = useMainConnection ? context->mainRef : kBadDNSServiceRef;
+       err = DNSServiceNATPortMappingCreate( &sdRef, context->flags, context->ifIndex, context->protocols,
+               htons( context->internalPort ), htons( context->externalPort ), context->ttl, PortMappingCallback, context );
+       require_noerr( err, exit );
+       
+       context->opRef = sdRef;
+       if( !useMainConnection )
+       {
+               err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+               require_noerr( err, exit );
+       }
+       
+       dispatch_main();
+       
+exit:
+       dispatch_source_forget( &signalSource );
+       if( context ) PortMappingContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     PortMappingPrintPrologue
+//===========================================================================================================================
+
+static void    PortMappingPrintPrologue( const PortMappingContext *inContext )
+{
+       char            ifName[ kInterfaceNameBufLen ];
+       
+       InterfaceIndexToName( inContext->ifIndex, ifName );
+       
+       FPrintF( stdout, "Flags:         %#{flags}\n",          inContext->flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:     %d (%s)\n",            (int32_t) inContext->ifIndex, ifName );
+       FPrintF( stdout, "Protocols:     %#{flags}\n",          inContext->protocols, kDNSServiceProtocolDescriptors );
+       FPrintF( stdout, "Internal Port: %u\n",                         inContext->internalPort );
+       FPrintF( stdout, "External Port: %u\n",                         inContext->externalPort );
+       FPrintF( stdout, "TTL:           %u%?s\n",                      inContext->ttl, !inContext->ttl,
+               " (system will use a default value.)" );
+       FPrintF( stdout, "Start time:    %{du:time}\n", NULL );
+       FPrintF( stdout, "---\n" );
+       
+}
+
+//===========================================================================================================================
+//     PortMappingContextFree
+//===========================================================================================================================
+
+static void    PortMappingContextFree( PortMappingContext *inContext )
+{
+       DNSServiceForget( &inContext->opRef );
+       DNSServiceForget( &inContext->mainRef );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     PortMappingCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       PortMappingCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inError,
+               uint32_t                        inExternalIPv4Address,
+               DNSServiceProtocol      inProtocol,
+               uint16_t                        inInternalPort,
+               uint16_t                        inExternalPort,
+               uint32_t                        inTTL,
+               void *                          inContext )
+{
+       PortMappingContext * const              context = (PortMappingContext *) inContext;
+       struct timeval                                  now;
+       char                                                    errorStr[ 128 ];
+       
+       Unused( inSDRef );
+       Unused( inFlags );
+       
+       gettimeofday( &now, NULL );
+       
+       if( inError ) SNPrintF( errorStr, sizeof( errorStr ), " (error: %#m)", inError );
+       if( !context->printedHeader )
+       {
+               FPrintF( stdout, "%-26s  IF %7s %15s %7s %6s Protocol\n", "Timestamp", "IntPort", "ExtAddr", "ExtPort", "TTL" );
+               context->printedHeader = true;
+       }
+       FPrintF( stdout, "%{du:time}  %2u %7u %15.4a %7u %6u %#{flags}%?s\n",
+               &now, inInterfaceIndex, ntohs( inInternalPort), &inExternalIPv4Address, ntohs( inExternalPort ), inTTL,
+               inProtocol, kDNSServiceProtocolDescriptors, inError, errorStr );
+}
+
+//===========================================================================================================================
+//     BrowseAllCmd
+//===========================================================================================================================
+
+typedef struct BrowseAllConnection             BrowseAllConnection;
+
+typedef struct
+{
+       ServiceBrowserRef                       browser;                                // Service browser.
+       ServiceBrowserResults *         results;                                // Results from the service browser.
+       BrowseAllConnection *           connectionList;                 // List of connections.
+       dispatch_source_t                       connectionTimer;                // Timer for connection timeout.
+       int                                                     connectionPendingCount; // Number of pending connections.
+       int                                                     connectionTimeoutSecs;  // Timeout value for connections in seconds.
+       
+}      BrowseAllContext;
+
+struct BrowseAllConnection
+{
+       BrowseAllConnection *           next;                           // Next connection object in list.
+       sockaddr_ip                                     sip;                            // IPv4 or IPv6 address to connect to.
+       uint16_t                                        port;                           // TCP port to connect to.
+       AsyncConnectionRef                      asyncCnx;                       // AsyncConnection object to handle the actual connection.
+       OSStatus                                        status;                         // Status of connection. NoErr means connection succeeded.
+       CFTimeInterval                          connectTimeSecs;        // Time it took to connect in seconds.
+       int32_t                                         refCount;                       // This object's reference count.
+       BrowseAllContext *                      context;                        // Back pointer to parent context.
+};
+
+static void    _BrowseAllContextFree( BrowseAllContext *inContext );
+static void    _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext );
+static OSStatus
+       _BrowseAllConnectionCreate(
+               const struct sockaddr * inSockAddr,
+               uint16_t                                inPort,
+               BrowseAllContext *              inContext,
+               BrowseAllConnection **  outConnection );
+static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection );
+static void    _BrowseAllConnectionRelease( BrowseAllConnection *inConnection );
+static void    _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg );
+static void    _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg );
+static void    _BrowseAllExit( void *inContext );
+
+static Boolean _IsServiceTypeTCP( const char *inServiceType );
+
+static void    BrowseAllCmd( void )
+{
+       OSStatus                                err;
+       BrowseAllContext *              context = NULL;
+       size_t                                  i;
+       uint32_t                                ifIndex;
+       char                                    ifName[ kInterfaceNameBufLen ];
+       
+       // Check parameters.
+       
+       if( gBrowseAll_BrowseTimeSecs <= 0 )
+       {
+               FPrintF( stdout, "Invalid browse time: %d seconds.\n", gBrowseAll_BrowseTimeSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       context = (BrowseAllContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->connectionTimeoutSecs  = gBrowseAll_ConnectTimeout;
+#if( TARGET_OS_POSIX )
+       // Increase the open file descriptor limit for connection sockets.
+       
+       if( context->connectionTimeoutSecs > 0 )
+       {
+               struct rlimit           fdLimits;
+               
+               err = getrlimit( RLIMIT_NOFILE, &fdLimits );
+               err = map_global_noerr_errno( err );
+               require_noerr( err, exit );
+               
+               if( fdLimits.rlim_cur < 4096 )
+               {
+                       fdLimits.rlim_cur = 4096;
+                       err = setrlimit( RLIMIT_NOFILE, &fdLimits );
+                       err = map_global_noerr_errno( err );
+                       require_noerr( err, exit );
+               }
+       }
+#endif
+       
+       // Get interface index.
+       
+       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       // Print prologue.
+       
+       FPrintF( stdout, "Interface:       %d (%s)\n",  (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+       FPrintF( stdout, "Service types:   ");
+       if( gBrowseAll_ServiceTypesCount > 0 )
+       {
+               FPrintF( stdout, "%s", gBrowseAll_ServiceTypes[ 0 ] );
+               for( i = 1; i < gBrowseAll_ServiceTypesCount; ++i )
+               {
+                       FPrintF( stdout, ", %s", gBrowseAll_ServiceTypes[ i ] );
+               }
+               FPrintF( stdout, "\n" );
+       }
+       else
+       {
+               FPrintF( stdout, "all services\n" );
+       }
+       FPrintF( stdout, "Domain:          %s\n", gBrowseAll_Domain ? gBrowseAll_Domain : "default domains" );
+       FPrintF( stdout, "Browse time:     %d second%?c\n", gBrowseAll_BrowseTimeSecs, gBrowseAll_BrowseTimeSecs != 1, 's' );
+       FPrintF( stdout, "Connect timeout: %d second%?c\n",
+               context->connectionTimeoutSecs, context->connectionTimeoutSecs != 1, 's' );
+       FPrintF( stdout, "IncludeAWDL:     %s\n", gDNSSDFlag_IncludeAWDL ? "yes" : "no" );
+       FPrintF( stdout, "Start time:      %{du:time}\n", NULL );
+       FPrintF( stdout, "---\n" );
+       
+       err = ServiceBrowserCreate( dispatch_get_main_queue(), ifIndex, gBrowseAll_Domain,
+               (unsigned int) gBrowseAll_BrowseTimeSecs, gDNSSDFlag_IncludeAWDL ? true : false, &context->browser );
+       require_noerr( err, exit );
+       
+       for( i = 0; i < gBrowseAll_ServiceTypesCount; ++i )
+       {
+               err = ServiceBrowserAddServiceType( context->browser, gBrowseAll_ServiceTypes[ i ] );
+               require_noerr( err, exit );
+       }
+       ServiceBrowserSetCallback( context->browser, _BrowseAllServiceBrowserCallback, context );
+       ServiceBrowserStart( context->browser );
+       dispatch_main();
+       
+exit:
+       if( context ) _BrowseAllContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     _BrowseAllContextFree
+//===========================================================================================================================
+
+static void    _BrowseAllContextFree( BrowseAllContext *inContext )
+{
+       check( !inContext->browser );
+       check( !inContext->connectionTimer );
+       check( !inContext->connectionList );
+       ForgetServiceBrowserResults( &inContext->results );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     _BrowseAllServiceBrowserCallback
+//===========================================================================================================================
+
+#define kDiscardProtocolPort           9
+
+static void    _BrowseAllServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
+{
+       OSStatus                                                err;
+       BrowseAllContext * const                context = (BrowseAllContext *) inContext;
+       SBRDomain *                                             domain;
+       SBRServiceType *                                type;
+       SBRServiceInstance *                    instance;
+       SBRIPAddress *                                  ipaddr;
+       
+       Unused( inError );
+       
+       require_action( inResults, exit, err = kUnexpectedErr );
+       
+       check( !context->results );
+       context->results = inResults;
+       ServiceBrowserResultsRetain( context->results );
+       
+       check( context->connectionPendingCount == 0 );
+       if( context->connectionTimeoutSecs > 0 )
+       {
+               BrowseAllConnection *                   connection;
+               BrowseAllConnection **                  connectionPtr = &context->connectionList;
+               char                                                    destination[ kSockAddrStringMaxSize ];
+               
+               for( domain = context->results->domainList; domain; domain = domain->next )
+               {
+                       for( type = domain->typeList; type; type = type->next )
+                       {
+                               if( !_IsServiceTypeTCP( type->name ) ) continue;
+                               for( instance = type->instanceList; instance; instance = instance->next )
+                               {
+                                       if( instance->port == kDiscardProtocolPort ) continue;
+                                       for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
+                                       {
+                                               err = _BrowseAllConnectionCreate( &ipaddr->sip.sa, instance->port, context, &connection );
+                                               require_noerr( err, exit );
+                                               
+                                               *connectionPtr = connection;
+                                                connectionPtr = &connection->next;
+                                               
+                                               err = SockAddrToString( &ipaddr->sip, kSockAddrStringFlagsNoPort, destination );
+                                               check_noerr( err );
+                                               if( !err )
+                                               {
+                                                       err = AsyncConnection_Connect( &connection->asyncCnx, destination, -instance->port,
+                                                               kAsyncConnectionFlag_P2P, kAsyncConnectionNoTimeout,
+                                                               kSocketBufferSize_DontSet, kSocketBufferSize_DontSet,
+                                                               _BrowseAllConnectionProgress, connection, _BrowseAllConnectionHandler, connection,
+                                                               dispatch_get_main_queue() );
+                                                       check_noerr( err );
+                                               }
+                                               if( !err )
+                                               {
+                                                       _BrowseAllConnectionRetain( connection );
+                                                       connection->status = kInProgressErr;
+                                                       ++context->connectionPendingCount;
+                                               }
+                                               else
+                                               {
+                                                       connection->status = err;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       if( context->connectionPendingCount > 0 )
+       {
+               check( !context->connectionTimer );
+               err = DispatchTimerCreate( dispatch_time_seconds( context->connectionTimeoutSecs ), DISPATCH_TIME_FOREVER,
+                       100 * kNanosecondsPerMillisecond, NULL, _BrowseAllExit, NULL, context, &context->connectionTimer );
+               require_noerr( err, exit );
+               dispatch_resume( context->connectionTimer );
+       }
+       else
+       {
+               dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
+       }
+       err = kNoErr;
+       
+exit:
+       ForgetCF( &context->browser );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     _BrowseAllConnectionCreate
+//===========================================================================================================================
+
+static OSStatus
+       _BrowseAllConnectionCreate(
+               const struct sockaddr * inSockAddr,
+               uint16_t                                inPort,
+               BrowseAllContext *              inContext,
+               BrowseAllConnection **  outConnection )
+{
+       OSStatus                                        err;
+       BrowseAllConnection *           obj;
+       
+       obj = (BrowseAllConnection *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->refCount   = 1;
+       SockAddrCopy( inSockAddr, &obj->sip );
+       obj->port               = inPort;
+       obj->context    = inContext;
+       
+       *outConnection = obj;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _BrowseAllConnectionRetain
+//===========================================================================================================================
+
+static void _BrowseAllConnectionRetain( BrowseAllConnection *inConnection )
+{
+       ++inConnection->refCount;
+}
+
+//===========================================================================================================================
+//     _BrowseAllConnectionRelease
+//===========================================================================================================================
+
+static void    _BrowseAllConnectionRelease( BrowseAllConnection *inConnection )
+{
+       if( --inConnection->refCount == 0 ) free( inConnection );
+}
+
+//===========================================================================================================================
+//     _BrowseAllConnectionProgress
+//===========================================================================================================================
+
+static void    _BrowseAllConnectionProgress( int inPhase, const void *inDetails, void *inArg )
+{
+       BrowseAllConnection * const             connection = (BrowseAllConnection *) inArg;
+       
+       if( inPhase == kAsyncConnectionPhase_Connected )
+       {
+               const AsyncConnectedInfo * const                info = (AsyncConnectedInfo *) inDetails;
+               
+               connection->connectTimeSecs = info->connectSecs;
+       }
+}
+
+//===========================================================================================================================
+//     _BrowseAllConnectionHandler
+//===========================================================================================================================
+
+static void    _BrowseAllConnectionHandler( SocketRef inSock, OSStatus inError, void *inArg )
+{
+       BrowseAllConnection * const             connection      = (BrowseAllConnection *) inArg;
+       BrowseAllContext * const                context         = connection->context;
+       
+       connection->status = inError;
+       ForgetSocket( &inSock );
+       if( context )
+       {
+               check( context->connectionPendingCount > 0 );
+               if( ( --context->connectionPendingCount == 0 ) && context->connectionTimer )
+               {
+                       dispatch_source_forget( &context->connectionTimer );
+                       dispatch_async_f( dispatch_get_main_queue(), context, _BrowseAllExit );
+               }
+       }
+       _BrowseAllConnectionRelease( connection );
+}
+
+//===========================================================================================================================
+//     _BrowseAllExit
+//===========================================================================================================================
+
+#define Indent( X )            ( (X) * 4 ), ""
+
+static void    _BrowseAllExit( void *inContext )
+{
+       BrowseAllContext * const                context         = (BrowseAllContext *) inContext;
+       SBRDomain *                                             domain;
+       SBRServiceType *                                type;
+       SBRServiceInstance *                    instance;
+       SBRIPAddress *                                  ipaddr;
+       char                                                    textBuf[ 512 ];
+#if( TARGET_OS_POSIX )
+       const Boolean                                   useColor        = isatty( STDOUT_FILENO ) ? true : false;
+#endif
+       
+       dispatch_source_forget( &context->connectionTimer );
+       
+       for( domain = context->results->domainList; domain; domain = domain->next )
+       {
+               FPrintF( stdout, "%s\n\n", domain->name );
+               
+               for( type = domain->typeList; type; type = type->next )
+               {
+                       const char *            description;
+                       const Boolean           serviceTypeIsTCP = _IsServiceTypeTCP( type->name );
+                       
+                       description = ServiceTypeDescription( type->name );
+                       if( description )       FPrintF( stdout, "%*s" "%s (%s)\n\n",   Indent( 1 ), description, type->name );
+                       else                            FPrintF( stdout, "%*s" "%s\n\n",                Indent( 1 ), type->name );
+                       
+                       for( instance = type->instanceList; instance; instance = instance->next )
+                       {
+                               char *                          dst = textBuf;
+                               char * const            lim = &textBuf[ countof( textBuf ) ];
+                               char                            ifname[ IF_NAMESIZE + 1 ];
+                               
+                               SNPrintF_Add( &dst, lim, "%s via ", instance->name );
+                               if( instance->ifIndex == 0 )
+                               {
+                                       SNPrintF_Add( &dst, lim, "the Internet" );
+                               }
+                               else if( if_indextoname( instance->ifIndex, ifname ) )
+                               {
+                                       NetTransportType                netType;
+                                       
+                                       SocketGetInterfaceInfo( kInvalidSocketRef, ifname, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &netType );
+                                       SNPrintF_Add( &dst, lim, "%s (%s)",
+                                               ( netType == kNetTransportType_Ethernet ) ? "Ethernet" : NetTransportTypeToString( netType ),
+                                               ifname );
+                               }
+                               else
+                               {
+                                       SNPrintF_Add( &dst, lim, "interface index %u", instance->ifIndex );
+                               }
+                               FPrintF( stdout, "%*s" "%-55s %4llu.%03llu ms\n\n",
+                                       Indent( 2 ), textBuf, instance->discoverTimeUs / 1000, instance->discoverTimeUs % 1000 );
+                               
+                               if( instance->hostname )
+                               {
+                                       SNPrintF( textBuf, sizeof( textBuf ), "%s:%u", instance->hostname, instance->port );
+                                       FPrintF( stdout, "%*s" "%-51s %4llu.%03llu ms\n",
+                                               Indent( 3 ), textBuf, instance->resolveTimeUs / 1000, instance->resolveTimeUs % 1000 );
+                               }
+                               else
+                               {
+                                       FPrintF( stdout, "%*s" "%s:%u\n", Indent( 3 ), instance->hostname, instance->port );
+                               }
+                               
+                               for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
+                               {
+                                       BrowseAllConnection *           conn;
+                                       BrowseAllConnection **          connPtr;
+                                       
+                                       FPrintF( stdout, "%*s" "%-##47a %4llu.%03llu ms",
+                                               Indent( 4 ), &ipaddr->sip.sa, ipaddr->resolveTimeUs / 1000, ipaddr->resolveTimeUs % 1000 );
+                                       
+                                       conn = NULL;
+                                       if( serviceTypeIsTCP && ( instance->port != kDiscardProtocolPort ) )
+                                       {
+                                               for( connPtr = &context->connectionList; ( conn = *connPtr ) != NULL; connPtr = &conn->next )
+                                               {
+                                                       if( ( conn->port == instance->port ) &&
+                                                               ( SockAddrCompareAddr( &conn->sip, &ipaddr->sip ) == 0 ) ) break;
+                                               }
+                                               if( conn )
+                                               {
+                                                       if( conn->status == kInProgressErr ) conn->status = kTimeoutErr;
+                                                       *connPtr = conn->next;
+                                                       conn->context = NULL;
+                                                       AsyncConnection_Forget( &conn->asyncCnx );
+                                               }
+                                       }
+                                       
+                                       if( conn )
+                                       {
+                                               if( conn->status == kNoErr )
+                                               {
+                                                       FPrintF( stdout, " (%sconnected%s in %.3f ms)\n",
+                                                               useColor ? kANSIGreen : "", useColor ? kANSINormal : "", conn->connectTimeSecs * 1000 );
+                                               }
+                                               else
+                                               {
+                                                       FPrintF( stdout, " (%scould not connect%s: %m)\n",
+                                                               useColor ? kANSIRed : "", useColor ? kANSINormal : "", conn->status );
+                                               }
+                                               _BrowseAllConnectionRelease( conn );
+                                       }
+                                       else
+                                       {
+                                               FPrintF( stdout, " (no connection attempted)\n" );
+                                       }
+                               }
+                               
+                               FPrintF( stdout, "\n" );
+                               if( instance->txtLen == 0 ) continue;
+                               
+                               FPrintF( stdout, "%*s" "TXT record (%zu byte%?c):\n",
+                                       Indent( 3 ), instance->txtLen, instance->txtLen != 1, 's' );
+                               if( instance->txtLen > 1 )
+                               {
+                                       FPrintF( stdout, "%3{txt}", instance->txtPtr, instance->txtLen );
+                               }
+                               else
+                               {
+                                       FPrintF( stdout, "%*s" "%#H\n", Indent( 3 ), instance->txtPtr, (int) instance->txtLen, INT_MAX );
+                               }
+                               FPrintF( stdout, "\n" );
+                       }
+                       FPrintF( stdout, "\n" );
+               }
+       }
+       
+       _BrowseAllContextFree( context );
+       Exit( NULL );
+}
+
+//===========================================================================================================================
+//     _IsServiceTypeTCP
+//===========================================================================================================================
+
+static Boolean _IsServiceTypeTCP( const char *inServiceType )
+{
+       OSStatus                        err;
+       const uint8_t *         secondLabel;
+       uint8_t                         name[ kDomainNameLengthMax ];
+       
+       err = DomainNameFromString( name, inServiceType, NULL );
+       if( !err )
+       {
+               secondLabel = DomainNameGetNextLabel( name );
+               if( secondLabel && DomainNameEqual( secondLabel, (const uint8_t *) "\x04" "_tcp" ) ) return( true );
+       }
+       return( false );
+}
+
+//===========================================================================================================================
+//     GetNameInfoCmd
+//===========================================================================================================================
+
+const FlagStringPair           kGetNameInfoFlagStringPairs[] =
+{
+       CaseFlagStringify( NI_NUMERICSCOPE ),
+       CaseFlagStringify( NI_DGRAM ),
+       CaseFlagStringify( NI_NUMERICSERV ),
+       CaseFlagStringify( NI_NAMEREQD ),
+       CaseFlagStringify( NI_NUMERICHOST ),
+       CaseFlagStringify( NI_NOFQDN ),
+       { 0, NULL }
+};
+
+static void    GetNameInfoCmd( void )
+{
+       OSStatus                                        err;
+       sockaddr_ip                                     sip;
+       size_t                                          sockAddrLen;
+       unsigned int                            flags;
+       const FlagStringPair *          pair;
+       struct timeval                          now;
+       char                                            host[ NI_MAXHOST ];
+       char                                            serv[ NI_MAXSERV ];
+       
+       err = StringToSockAddr( gGetNameInfo_IPAddress, &sip, sizeof( sip ), &sockAddrLen );
+       check_noerr( err );
+       if( err )
+       {
+               FPrintF( stderr, "Failed to convert \"%s\" to a sockaddr.\n", gGetNameInfo_IPAddress );
+               goto exit;
+       }
+       
+       flags = 0;
+       if( gGetNameInfoFlag_DGram )            flags |= NI_DGRAM;
+       if( gGetNameInfoFlag_NameReqd )         flags |= NI_NAMEREQD;
+       if( gGetNameInfoFlag_NoFQDN )           flags |= NI_NOFQDN;
+       if( gGetNameInfoFlag_NumericHost )      flags |= NI_NUMERICHOST;
+       if( gGetNameInfoFlag_NumericScope )     flags |= NI_NUMERICSCOPE;
+       if( gGetNameInfoFlag_NumericServ )      flags |= NI_NUMERICSERV;
+       
+       // Print prologue.
+       
+       FPrintF( stdout, "SockAddr:   %##a\n",  &sip.sa );
+       FPrintF( stdout, "Flags:      0x%X < ", flags );
+       for( pair = kGetNameInfoFlagStringPairs; pair->str != NULL; ++pair )
+       {
+               if( flags & pair->flag ) FPrintF( stdout, "%s ", pair->str );
+       }
+       FPrintF( stdout, ">\n" );
+       FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+       FPrintF( stdout, "---\n" );
+       
+       // Call getnameinfo().
+       
+       err = getnameinfo( &sip.sa, (socklen_t) sockAddrLen, host, (socklen_t) sizeof( host ), serv, (socklen_t) sizeof( serv ),
+               (int) flags );
+       gettimeofday( &now, NULL );
+       if( err )
+       {
+               FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
+       }
+       else
+       {
+               FPrintF( stdout, "host: %s\n", host );
+               FPrintF( stdout, "serv: %s\n", serv );
+       }
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "End time:   %{du:time}\n", &now );
+       
+exit:
+       gExitCode = err ? 1 : 0;
+}
+
+//===========================================================================================================================
+//     GetAddrInfoStressCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSServiceRef                   mainRef;
+       DNSServiceRef                   sdRef;
+       DNSServiceFlags                 flags;
+       unsigned int                    interfaceIndex;
+       unsigned int                    connectionNumber;
+       unsigned int                    requestCount;
+       unsigned int                    requestCountMax;
+       unsigned int                    requestCountLimit;
+       unsigned int                    durationMinMs;
+       unsigned int                    durationMaxMs;
+       
+}      GAIStressContext;
+
+static void    GetAddrInfoStressEvent( void *inContext );
+static void    DNSSD_API
+       GetAddrInfoStressCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+
+static void    GetAddrInfoStressCmd( void )
+{
+       OSStatus                                err;
+       GAIStressContext *              context = NULL;
+       int                                             i;
+       DNSServiceFlags                 flags;
+       uint32_t                                ifIndex;
+       char                                    ifName[ kInterfaceNameBufLen ];
+       
+       if( gGAIStress_TestDurationSecs < 0 )
+       {
+               FPrintF( stdout, "Invalid test duration: %d s.\n", gGAIStress_TestDurationSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       if( gGAIStress_ConnectionCount <= 0 )
+       {
+               FPrintF( stdout, "Invalid simultaneous connection count: %d.\n", gGAIStress_ConnectionCount );
+               err = kParamErr;
+               goto exit;
+       }
+       if( gGAIStress_DurationMinMs <= 0 )
+       {
+               FPrintF( stdout, "Invalid minimum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMinMs );
+               err = kParamErr;
+               goto exit;
+       }
+       if( gGAIStress_DurationMaxMs <= 0 )
+       {
+               FPrintF( stdout, "Invalid maximum DNSServiceGetAddrInfo() duration: %d ms.\n", gGAIStress_DurationMaxMs );
+               err = kParamErr;
+               goto exit;
+       }
+       if( gGAIStress_DurationMinMs > gGAIStress_DurationMaxMs )
+       {
+               FPrintF( stdout, "Invalid minimum and maximum DNSServiceGetAddrInfo() durations: %d ms and %d ms.\n",
+                       gGAIStress_DurationMinMs, gGAIStress_DurationMaxMs );
+               err = kParamErr;
+               goto exit;
+       }
+       if( gGAIStress_RequestCountMax <= 0 )
+       {
+               FPrintF( stdout, "Invalid maximum request count: %d.\n", gGAIStress_RequestCountMax );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Set flags.
+       
+       flags = GetDNSSDFlagsFromOpts();
+       
+       // Set interface index.
+       
+       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       for( i = 0; i < gGAIStress_ConnectionCount; ++i )
+       {
+               context = (GAIStressContext *) calloc( 1, sizeof( *context ) );
+               require_action( context, exit, err = kNoMemoryErr );
+               
+               context->flags                          = flags;
+               context->interfaceIndex         = ifIndex;
+               context->connectionNumber       = (unsigned int)( i + 1 );
+               context->requestCountMax        = (unsigned int) gGAIStress_RequestCountMax;
+               context->durationMinMs          = (unsigned int) gGAIStress_DurationMinMs;
+               context->durationMaxMs          = (unsigned int) gGAIStress_DurationMaxMs;
+               
+               dispatch_async_f( dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
+               context = NULL;
+       }
+       
+       if( gGAIStress_TestDurationSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( gGAIStress_TestDurationSecs ), dispatch_get_main_queue(), NULL, Exit );
+       }
+       
+       FPrintF( stdout, "Flags:                %#{flags}\n",   flags, kDNSServiceFlagsDescriptors );
+       FPrintF( stdout, "Interface:            %d (%s)\n",             (int32_t) ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+       FPrintF( stdout, "Test duration:        " );
+       if( gGAIStress_TestDurationSecs == 0 )
+       {
+               FPrintF( stdout, "∞\n" );
+       }
+       else
+       {
+               FPrintF( stdout, "%d s\n", gGAIStress_TestDurationSecs );
+       }
+       FPrintF( stdout, "Connection count:     %d\n",                  gGAIStress_ConnectionCount );
+       FPrintF( stdout, "Request duration min: %d ms\n",               gGAIStress_DurationMinMs );
+       FPrintF( stdout, "Request duration max: %d ms\n",               gGAIStress_DurationMaxMs );
+       FPrintF( stdout, "Request count max:    %d\n",                  gGAIStress_RequestCountMax );
+       FPrintF( stdout, "Start time:           %{du:time}\n",  NULL);
+       FPrintF( stdout, "---\n" );
+       
+       dispatch_main();
+       
+exit:
+       FreeNullSafe( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     GetAddrInfoStressEvent
+//===========================================================================================================================
+
+#define kStressRandStrLen              5
+
+#define kLowercaseAlphaCharSet         "abcdefghijklmnopqrstuvwxyz"
+
+static void    GetAddrInfoStressEvent( void *inContext )
+{
+       GAIStressContext * const                context = (GAIStressContext *) inContext;
+       OSStatus                                                err;
+       DNSServiceRef                                   sdRef;
+       unsigned int                                    nextMs;
+       char                                                    randomStr[ kStressRandStrLen + 1 ];
+       char                                                    hostname[ kStressRandStrLen + 4 + 1 ];
+       Boolean                                                 isConnectionNew = false;
+       static Boolean                                  printedHeader   = false;
+       
+       if( !context->mainRef || ( context->requestCount >= context->requestCountLimit ) )
+       {
+               DNSServiceForget( &context->mainRef );
+               context->sdRef                          = NULL;
+               context->requestCount           = 0;
+               context->requestCountLimit      = RandomRange( 1, context->requestCountMax );
+               
+               err = DNSServiceCreateConnection( &context->mainRef );
+               require_noerr( err, exit );
+               
+               err = DNSServiceSetDispatchQueue( context->mainRef, dispatch_get_main_queue() );
+               require_noerr( err, exit );
+               
+               isConnectionNew = true;
+       }
+       
+       RandomString( kLowercaseAlphaCharSet, sizeof_string( kLowercaseAlphaCharSet ), 2, kStressRandStrLen, randomStr );
+       SNPrintF( hostname, sizeof( hostname ), "%s.com", randomStr );
+       
+       nextMs = RandomRange( context->durationMinMs, context->durationMaxMs );
+       
+       if( !printedHeader )
+       {
+               FPrintF( stdout, "%-26s Conn  Hostname Dur (ms)\n", "Timestamp" );
+               printedHeader = true;
+       }
+       FPrintF( stdout, "%{du:time} %3u%c %9s %8u\n",
+               NULL, context->connectionNumber, isConnectionNew ? '*': ' ', hostname, nextMs );
+       
+       DNSServiceForget( &context->sdRef );
+       sdRef = context->mainRef;
+       err = DNSServiceGetAddrInfo( &sdRef, context->flags | kDNSServiceFlagsShareConnection, context->interfaceIndex,
+               kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, hostname, GetAddrInfoStressCallback, NULL );
+       require_noerr( err, exit );
+       context->sdRef = sdRef;
+       
+       context->requestCount++;
+       
+       dispatch_after_f( dispatch_time_milliseconds( nextMs ), dispatch_get_main_queue(), context, GetAddrInfoStressEvent );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     GetAddrInfoStressCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       GetAddrInfoStressCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       Unused( inSDRef );
+       Unused( inFlags );
+       Unused( inInterfaceIndex );
+       Unused( inError );
+       Unused( inHostname );
+       Unused( inSockAddr );
+       Unused( inTTL );
+       Unused( inContext );
+}
+
+//===========================================================================================================================
+//     DNSQueryCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       sockaddr_ip                             serverAddr;
+       uint64_t                                sendTicks;
+       uint8_t *                               msgPtr;
+       size_t                                  msgLen;
+       size_t                                  msgOffset;
+       const char *                    name;
+       dispatch_source_t               readSource;
+       SocketRef                               sock;
+       int                                             timeLimitSecs;
+       uint16_t                                queryID;
+       uint16_t                                type;
+       Boolean                                 haveTCPLen;
+       Boolean                                 useTCP;
+       Boolean                                 printRawRData;  // True if RDATA results are not to be formatted.
+       uint8_t                                 msgBuf[ 512 ];
+       
+}      DNSQueryContext;
+
+static void    DNSQueryPrintPrologue( const DNSQueryContext *inContext );
+static void    DNSQueryReadHandler( void *inContext );
+static void    DNSQueryCancelHandler( void *inContext );
+
+static void    DNSQueryCmd( void )
+{
+       OSStatus                                err;
+       DNSQueryContext *               context = NULL;
+       uint8_t *                               msgPtr;
+       size_t                                  msgLen, sendLen;
+       
+       // Check command parameters.
+       
+       if( gDNSQuery_TimeLimitSecs < -1 )
+       {
+               FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSQuery_TimeLimitSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       if( ( gDNSQuery_Flags < INT16_MIN ) || ( gDNSQuery_Flags > UINT16_MAX ) )
+       {
+               FPrintF( stdout, "DNS flags-and-codes value is out of the unsigned 16-bit range: 0x%08X.\n", gDNSQuery_Flags );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create context.
+       
+       context = (DNSQueryContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->name                   = gDNSQuery_Name;
+       context->sock                   = kInvalidSocketRef;
+       context->timeLimitSecs  = gDNSQuery_TimeLimitSecs;
+       context->queryID                = (uint16_t) Random32();
+       context->useTCP                 = gDNSQuery_UseTCP       ? true : false;
+       context->printRawRData  = gDNSQuery_RawRData ? true : false;
+       
+#if( TARGET_OS_DARWIN )
+       if( gDNSQuery_Server )
+#endif
+       {
+               err = StringToSockAddr( gDNSQuery_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
+               require_noerr( err, exit );
+       }
+#if( TARGET_OS_DARWIN )
+       else
+       {
+               err = GetDefaultDNSServer( &context->serverAddr );
+               require_noerr( err, exit );
+       }
+#endif
+       if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSPort );
+       
+       err = RecordTypeFromArgString( gDNSQuery_Type, &context->type );
+       require_noerr( err, exit );
+       
+       // Write query message.
+       
+       check_compile_time_code( sizeof( context->msgBuf ) >= ( kDNSQueryMessageMaxLen + 2 ) );
+       
+       msgPtr = context->useTCP ? &context->msgBuf[ 2 ] : context->msgBuf;
+       err = WriteDNSQueryMessage( msgPtr, context->queryID, (uint16_t) gDNSQuery_Flags, context->name, context->type,
+               kDNSServiceClass_IN, &msgLen );
+       require_noerr( err, exit );
+       check( msgLen <= UINT16_MAX );
+       
+       if( context->useTCP )
+       {
+               WriteBig16( context->msgBuf, msgLen );
+               sendLen = 2 + msgLen;
+       }
+       else
+       {
+               sendLen = msgLen;
+       }
+       
+       DNSQueryPrintPrologue( context );
+       
+       if( gDNSQuery_Verbose )
+       {
+               FPrintF( stdout, "DNS message to send:\n\n%{du:dnsmsg}", msgPtr, msgLen );
+               FPrintF( stdout, "---\n" );
+       }
+       
+       if( context->useTCP )
+       {
+               // Create TCP socket.
+               
+               context->sock = socket( context->serverAddr.sa.sa_family, SOCK_STREAM, IPPROTO_TCP );
+               err = map_socket_creation_errno( context->sock );
+               require_noerr( err, exit );
+               
+               err = SocketConnect( context->sock, &context->serverAddr, 5 );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               // Create UDP socket.
+               
+               err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &context->sock );
+               require_noerr( err, exit );
+       }
+       
+       context->sendTicks = UpTicks();
+       err = _SocketWriteAll( context->sock, context->msgBuf, sendLen, 5 );
+       require_noerr( err, exit );
+       
+       if( context->timeLimitSecs == 0 ) goto exit;
+       
+       err = DispatchReadSourceCreate( context->sock, NULL, DNSQueryReadHandler, DNSQueryCancelHandler, context,
+               &context->readSource );
+       require_noerr( err, exit );
+       dispatch_resume( context->readSource );
+       
+       if( context->timeLimitSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+                       Exit );
+       }
+       dispatch_main();
+       
+exit:
+       if( context )
+       {
+               dispatch_source_forget( &context->readSource );
+               ForgetSocket( &context->sock );
+               free( context );
+       }
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     DNSQueryPrintPrologue
+//===========================================================================================================================
+
+static void    DNSQueryPrintPrologue( const DNSQueryContext *inContext )
+{
+       const int               timeLimitSecs = inContext->timeLimitSecs;
+       
+       FPrintF( stdout, "Name:        %s\n",           inContext->name );
+       FPrintF( stdout, "Type:        %s (%u)\n",      RecordTypeToString( inContext->type ), inContext->type );
+       FPrintF( stdout, "Server:      %##a\n",         &inContext->serverAddr );
+       FPrintF( stdout, "Transport:   %s\n",           inContext->useTCP ? "TCP" : "UDP" );
+       FPrintF( stdout, "Time limit:  " );
+       if( timeLimitSecs >= 0 )        FPrintF( stdout, "%d second%?c\n", timeLimitSecs, timeLimitSecs != 1, 's' );
+       else                                            FPrintF( stdout, "∞\n" );
+       FPrintF( stdout, "Start time:  %{du:time}\n", NULL );
+       FPrintF( stdout, "---\n" );
+}
+
+//===========================================================================================================================
+//     DNSQueryReadHandler
+//===========================================================================================================================
+
+static void    DNSQueryReadHandler( void *inContext )
+{
+       OSStatus                                        err;
+       struct timeval                          now;
+       const uint64_t                          nowTicks        = UpTicks();
+       DNSQueryContext * const         context         = (DNSQueryContext *) inContext;
+       
+       gettimeofday( &now, NULL );
+       
+       if( context->useTCP )
+       {
+               if( !context->haveTCPLen )
+               {
+                       err = SocketReadData( context->sock, &context->msgBuf, 2, &context->msgOffset );
+                       if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
+                       require_noerr( err, exit );
+                       
+                       context->msgOffset      = 0;
+                       context->msgLen         = ReadBig16( context->msgBuf );
+                       context->haveTCPLen     = true;
+                       if( context->msgLen <= sizeof( context->msgBuf ) )
+                       {
+                               context->msgPtr = context->msgBuf;
+                       }
+                       else
+                       {
+                               context->msgPtr = (uint8_t *) malloc( context->msgLen );
+                               require_action( context->msgPtr, exit, err = kNoMemoryErr );
+                       }
+               }
+               
+               err = SocketReadData( context->sock, context->msgPtr, context->msgLen, &context->msgOffset );
+               if( err == EWOULDBLOCK ) { err = kNoErr; goto exit; }
+               require_noerr( err, exit );
+               context->msgOffset      = 0;
+               context->haveTCPLen     = false;
+       }
+       else
+       {
+               sockaddr_ip             fromAddr;
+               
+               context->msgPtr = context->msgBuf;
+               err = SocketRecvFrom( context->sock, context->msgPtr, sizeof( context->msgBuf ), &context->msgLen, &fromAddr,
+                       sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+               require_noerr( err, exit );
+               
+               check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+       }
+       
+       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
+       FPrintF( stdout, "Source:       %##a\n",                &context->serverAddr );
+       FPrintF( stdout, "Message size: %zu\n",                 context->msgLen );
+       FPrintF( stdout, "RTT:          %llu ms\n\n",   UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+       FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgPtr, context->msgLen );
+       
+       if( ( context->msgLen >= kDNSHeaderLength ) && ( DNSHeaderGetID( (DNSHeader *) context->msgPtr ) == context->queryID ) )
+       {
+               Exit( kExitReason_ReceivedResponse );
+       }
+       
+exit:
+       if( err ) dispatch_source_forget( &context->readSource );
+}
+
+//===========================================================================================================================
+//     DNSQueryCancelHandler
+//===========================================================================================================================
+
+static void    DNSQueryCancelHandler( void *inContext )
+{
+       DNSQueryContext * const         context = (DNSQueryContext *) inContext;
+       
+       check( !context->readSource );
+       ForgetSocket( &context->sock );
+       if( context->msgPtr != context->msgBuf ) ForgetMem( &context->msgPtr );
+       free( context );
+       dispatch_async_f( dispatch_get_main_queue(), NULL, Exit );
+}
+
+#if( DNSSDUTIL_INCLUDE_DNSCRYPT )
+//===========================================================================================================================
+//     DNSCryptCmd
+//===========================================================================================================================
+
+#define kDNSCryptPort          443
+
+#define kDNSCryptMinPadLength                          8
+#define kDNSCryptMaxPadLength                          256
+#define kDNSCryptBlockSize                                     64
+#define kDNSCryptCertMinimumLength                     124
+#define kDNSCryptClientMagicLength                     8
+#define kDNSCryptResolverMagicLength           8
+#define kDNSCryptHalfNonceLength                       12
+#define kDNSCryptCertMagicLength                       4
+
+check_compile_time( ( kDNSCryptHalfNonceLength * 2 ) == crypto_box_NONCEBYTES );
+
+static const uint8_t           kDNSCryptCertMagic[ kDNSCryptCertMagicLength ] = { 'D', 'N', 'S', 'C' };
+static const uint8_t           kDNSCryptResolverMagic[ kDNSCryptResolverMagicLength ] =
+{
+       0x72, 0x36, 0x66, 0x6e, 0x76, 0x57, 0x6a, 0x38
+};
+
+typedef struct
+{
+       uint8_t         certMagic[ kDNSCryptCertMagicLength ];
+       uint8_t         esVersion[ 2 ];
+       uint8_t         minorVersion[ 2 ];
+       uint8_t         signature[ crypto_sign_BYTES ];
+       uint8_t         publicKey[ crypto_box_PUBLICKEYBYTES ];
+       uint8_t         clientMagic[ kDNSCryptClientMagicLength ];
+       uint8_t         serial[ 4 ];
+       uint8_t         startTime[ 4 ];
+       uint8_t         endTime[ 4 ];
+       uint8_t         extensions[ 1 ];        // Variably-sized extension data.
+       
+}      DNSCryptCert;
+
+check_compile_time( offsetof( DNSCryptCert, extensions ) == kDNSCryptCertMinimumLength );
+
+typedef struct
+{
+       uint8_t         clientMagic[ kDNSCryptClientMagicLength ];
+       uint8_t         clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
+       uint8_t         clientNonce[ kDNSCryptHalfNonceLength ];
+       uint8_t         poly1305MAC[ 16 ];
+       
+}      DNSCryptQueryHeader;
+
+check_compile_time( sizeof( DNSCryptQueryHeader ) == 68 );
+check_compile_time( sizeof( DNSCryptQueryHeader ) >= crypto_box_ZEROBYTES );
+check_compile_time( ( sizeof( DNSCryptQueryHeader ) - crypto_box_ZEROBYTES + crypto_box_BOXZEROBYTES ) ==
+       offsetof( DNSCryptQueryHeader, poly1305MAC ) );
+
+typedef struct
+{
+       uint8_t         resolverMagic[ kDNSCryptResolverMagicLength ];
+       uint8_t         clientNonce[ kDNSCryptHalfNonceLength ];
+       uint8_t         resolverNonce[ kDNSCryptHalfNonceLength ];
+       uint8_t         poly1305MAC[ 16 ];
+       
+}      DNSCryptResponseHeader;
+
+check_compile_time( sizeof( DNSCryptResponseHeader ) == 48 );
+check_compile_time( offsetof( DNSCryptResponseHeader, poly1305MAC ) >= crypto_box_BOXZEROBYTES );
+check_compile_time( ( offsetof( DNSCryptResponseHeader, poly1305MAC ) - crypto_box_BOXZEROBYTES + crypto_box_ZEROBYTES ) ==
+       sizeof( DNSCryptResponseHeader ) );
+
+typedef struct
+{
+       sockaddr_ip                             serverAddr;
+       uint64_t                                sendTicks;
+       const char *                    providerName;
+       const char *                    qname;
+       const uint8_t *                 certPtr;
+       size_t                                  certLen;
+       dispatch_source_t               readSource;
+       size_t                                  msgLen;
+       int                                             timeLimitSecs;
+       uint16_t                                queryID;
+       uint16_t                                qtype;
+       Boolean                                 printRawRData;
+       uint8_t                                 serverPublicSignKey[ crypto_sign_PUBLICKEYBYTES ];
+       uint8_t                                 serverPublicKey[ crypto_box_PUBLICKEYBYTES ];
+       uint8_t                                 clientPublicKey[ crypto_box_PUBLICKEYBYTES ];
+       uint8_t                                 clientSecretKey[ crypto_box_SECRETKEYBYTES ];
+       uint8_t                                 clientMagic[ kDNSCryptClientMagicLength ];
+       uint8_t                                 clientNonce[ kDNSCryptHalfNonceLength ];
+       uint8_t                                 nmKey[ crypto_box_BEFORENMBYTES ];
+       uint8_t                                 msgBuf[ 512 ];
+       
+}      DNSCryptContext;
+
+static void            DNSCryptReceiveCertHandler( void *inContext );
+static void            DNSCryptReceiveResponseHandler( void *inContext );
+static void            DNSCryptProceed( void *inContext );
+static OSStatus        DNSCryptProcessCert( DNSCryptContext *inContext );
+static OSStatus        DNSCryptBuildQuery( DNSCryptContext *inContext );
+static OSStatus        DNSCryptSendQuery( DNSCryptContext *inContext );
+static void            DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen );
+
+static void    DNSCryptCmd( void )
+{
+       OSStatus                                err;
+       DNSCryptContext *               context         = NULL;
+       size_t                                  writtenBytes;
+       size_t                                  totalBytes;
+       SocketContext *                 sockCtx;
+       SocketRef                               sock            = kInvalidSocketRef;
+       const char *                    ptr;
+       
+       // Check command parameters.
+       
+       if( gDNSCrypt_TimeLimitSecs < -1 )
+       {
+               FPrintF( stdout, "Invalid time limit: %d seconds.\n", gDNSCrypt_TimeLimitSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create context.
+       
+       context = (DNSCryptContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->providerName   = gDNSCrypt_ProviderName;
+       context->qname                  = gDNSCrypt_Name;
+       context->timeLimitSecs  = gDNSCrypt_TimeLimitSecs;
+       context->printRawRData  = gDNSCrypt_RawRData ? true : false;
+       
+       err = crypto_box_keypair( context->clientPublicKey, context->clientSecretKey );
+       require_noerr( err, exit );
+       
+       err = HexToData( gDNSCrypt_ProviderKey, kSizeCString, kHexToData_DefaultFlags,
+               context->serverPublicSignKey, sizeof( context->serverPublicSignKey ), &writtenBytes, &totalBytes, &ptr );
+       if( err || ( *ptr != '\0' ) )
+       {
+               FPrintF( stderr, "Failed to parse public signing key hex string (%s).\n", gDNSCrypt_ProviderKey );
+               goto exit;
+       }
+       else if( totalBytes != sizeof( context->serverPublicSignKey ) )
+       {
+               FPrintF( stderr, "Public signing key contains incorrect number of hex bytes (%zu != %zu)\n",
+                       totalBytes, sizeof( context->serverPublicSignKey ) );
+               err = kSizeErr;
+               goto exit;
+       }
+       check( writtenBytes == totalBytes );
+       
+       err = StringToSockAddr( gDNSCrypt_Server, &context->serverAddr, sizeof( context->serverAddr ), NULL );
+       require_noerr( err, exit );
+       if( SockAddrGetPort( &context->serverAddr ) == 0 ) SockAddrSetPort( &context->serverAddr, kDNSCryptPort );
+       
+       err = RecordTypeFromArgString( gDNSCrypt_Type, &context->qtype );
+       require_noerr( err, exit );
+       
+       // Write query message.
+       
+       context->queryID = (uint16_t) Random32();
+       err = WriteDNSQueryMessage( context->msgBuf, context->queryID, kDNSHeaderFlag_RecursionDesired, context->providerName,
+               kDNSServiceType_TXT, kDNSServiceClass_IN, &context->msgLen );
+       require_noerr( err, exit );
+       
+       // Create UDP socket.
+       
+       err = UDPClientSocketOpen( AF_UNSPEC, &context->serverAddr, 0, -1, NULL, &sock );
+       require_noerr( err, exit );
+       
+       // Send DNS query.
+       
+       context->sendTicks = UpTicks();
+       err = _SocketWriteAll( sock, context->msgBuf, context->msgLen, 5 );
+       require_noerr( err, exit );
+       
+       err = SocketContextCreate( sock, context, &sockCtx );
+       require_noerr( err, exit );
+       sock = kInvalidSocketRef;
+       
+       err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveCertHandler, SocketContextCancelHandler, sockCtx,
+               &context->readSource );
+       if( err ) ForgetSocketContext( &sockCtx );
+       require_noerr( err, exit );
+       
+       dispatch_resume( context->readSource );
+       
+       if( context->timeLimitSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->timeLimitSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+                       Exit );
+       }
+       dispatch_main();
+       
+exit:
+       if( context ) free( context );
+       ForgetSocket( &sock );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     DNSCryptReceiveCertHandler
+//===========================================================================================================================
+
+static void    DNSCryptReceiveCertHandler( void *inContext )
+{
+       OSStatus                                        err;
+       struct timeval                          now;
+       const uint64_t                          nowTicks        = UpTicks();
+       SocketContext * const           sockCtx         = (SocketContext *) inContext;
+       DNSCryptContext * const         context         = (DNSCryptContext *) sockCtx->userContext;
+       const DNSHeader *                       hdr;
+       sockaddr_ip                                     fromAddr;
+       const uint8_t *                         ptr;
+       const uint8_t *                         txtPtr;
+       size_t                                          txtLen;
+       unsigned int                            answerCount, i;
+       uint8_t                                         targetName[ kDomainNameLengthMax ];
+       
+       gettimeofday( &now, NULL );
+       
+       dispatch_source_forget( &context->readSource );
+       
+       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
+               &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+       require_noerr( err, exit );
+       check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+       
+       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
+       FPrintF( stdout, "Source:       %##a\n",                &context->serverAddr );
+       FPrintF( stdout, "Message size: %zu\n",                 context->msgLen );
+       FPrintF( stdout, "RTT:          %llu ms\n\n",   UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+       FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, context->msgBuf, context->msgLen );
+       
+       require_action_quiet( context->msgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+       
+       hdr = (DNSHeader *) context->msgBuf;
+       require_action_quiet( DNSHeaderGetID( hdr ) == context->queryID, exit, err = kMismatchErr );
+       
+       err = DNSMessageGetAnswerSection( context->msgBuf, context->msgLen, &ptr );
+       require_noerr( err, exit );
+       
+       err = DomainNameFromString( targetName, context->providerName, NULL );
+       require_noerr( err, exit );
+       
+       answerCount = DNSHeaderGetAnswerCount( hdr );
+       for( i = 0; i < answerCount; ++i )
+       {
+               uint16_t                type;
+               uint16_t                class;
+               uint8_t                 name[ kDomainNameLengthMax ];
+               
+               err = DNSMessageExtractRecord( context->msgBuf, context->msgLen, ptr, name, &type, &class, NULL, &txtPtr, &txtLen,
+                       &ptr );
+               require_noerr( err, exit );
+               
+               if( ( type == kDNSServiceType_TXT ) && ( class == kDNSServiceClass_IN ) && DomainNameEqual( name, targetName ) )
+               {
+                       break;
+               }
+       }
+       
+       if( txtLen < ( 1 + kDNSCryptCertMinimumLength ) )
+       {
+               FPrintF( stderr, "TXT record length is too short (%u < %u)\n", txtLen, kDNSCryptCertMinimumLength + 1 );
+               err = kSizeErr;
+               goto exit;
+       }
+       if( txtPtr[ 0 ] < kDNSCryptCertMinimumLength )
+       {
+               FPrintF( stderr, "TXT record value length is too short (%u < %u)\n", txtPtr[ 0 ], kDNSCryptCertMinimumLength );
+               err = kSizeErr;
+               goto exit;
+       }
+       
+       context->certLen = txtPtr[ 0 ];
+       context->certPtr = &txtPtr[ 1 ];
+       
+       dispatch_async_f( dispatch_get_main_queue(), context, DNSCryptProceed );
+       
+exit:
+       if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+//     DNSCryptReceiveResponseHandler
+//===========================================================================================================================
+
+static void    DNSCryptReceiveResponseHandler( void *inContext )
+{
+       OSStatus                                                err;
+       struct timeval                                  now;
+       const uint64_t                                  nowTicks        = UpTicks();
+       SocketContext * const                   sockCtx         = (SocketContext *) inContext;
+       DNSCryptContext * const                 context         = (DNSCryptContext *) sockCtx->userContext;
+       sockaddr_ip                                             fromAddr;
+       DNSCryptResponseHeader *                hdr;
+       const uint8_t *                                 end;
+       uint8_t *                                               ciphertext;
+       uint8_t *                                               plaintext;
+       const uint8_t *                                 response;
+       uint8_t                                                 nonce[ crypto_box_NONCEBYTES ];
+       
+       gettimeofday( &now, NULL );
+       
+       dispatch_source_forget( &context->readSource );
+       
+       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &context->msgLen,
+               &fromAddr, sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+       require_noerr( err, exit );
+       check( SockAddrCompareAddr( &fromAddr, &context->serverAddr ) == 0 );
+       
+       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
+       FPrintF( stdout, "Source:       %##a\n",                &context->serverAddr );
+       FPrintF( stdout, "Message size: %zu\n",                 context->msgLen );
+       FPrintF( stdout, "RTT:          %llu ms\n\n",   UpTicksToMilliseconds( nowTicks - context->sendTicks ) );
+       
+       if( context->msgLen < sizeof( DNSCryptResponseHeader ) )
+       {
+               FPrintF( stderr, "DNSCrypt response is too short.\n" );
+               err = kSizeErr;
+               goto exit;
+       }
+       
+       hdr = (DNSCryptResponseHeader *) context->msgBuf;
+       
+       if( memcmp( hdr->resolverMagic, kDNSCryptResolverMagic, kDNSCryptResolverMagicLength ) != 0 )
+       {
+               FPrintF( stderr, "DNSCrypt response resolver magic %#H != %#H\n",
+                       hdr->resolverMagic,             kDNSCryptResolverMagicLength, INT_MAX,
+                       kDNSCryptResolverMagic, kDNSCryptResolverMagicLength, INT_MAX );
+               err = kValueErr;
+               goto exit;
+       }
+       
+       if( memcmp( hdr->clientNonce, context->clientNonce, kDNSCryptHalfNonceLength ) != 0 )
+       {
+               FPrintF( stderr, "DNSCrypt response client nonce mismatch.\n" );
+               err = kValueErr;
+               goto exit;
+       }
+       
+       memcpy( nonce, hdr->clientNonce, crypto_box_NONCEBYTES );
+       
+       ciphertext = hdr->poly1305MAC - crypto_box_BOXZEROBYTES;
+       memset( ciphertext, 0, crypto_box_BOXZEROBYTES );
+       
+       plaintext = (uint8_t *)( hdr + 1 ) - crypto_box_ZEROBYTES;
+       check( plaintext == ciphertext );
+       
+       end = context->msgBuf + context->msgLen;
+       
+       err = crypto_box_open_afternm( plaintext, ciphertext, (size_t)( end - ciphertext ), nonce, context->nmKey );
+       require_noerr( err, exit );
+       
+       response = plaintext + crypto_box_ZEROBYTES;
+       FPrintF( stdout, "%.*{du:dnsmsg}", context->printRawRData ? 1 : 0, response, (size_t)( end - response ) );
+       Exit( kExitReason_ReceivedResponse );
+       
+exit:
+       if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+//     DNSCryptProceed
+//===========================================================================================================================
+
+static void    DNSCryptProceed( void *inContext )
+{
+       OSStatus                                        err;
+       DNSCryptContext * const         context = (DNSCryptContext *) inContext;
+       
+       err = DNSCryptProcessCert( context );
+       require_noerr_quiet( err, exit );
+       
+       err = DNSCryptBuildQuery( context );
+       require_noerr_quiet( err, exit );
+       
+       err = DNSCryptSendQuery( context );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       if( err ) Exit( NULL );
+}
+
+//===========================================================================================================================
+//     DNSCryptProcessCert
+//===========================================================================================================================
+
+static OSStatus        DNSCryptProcessCert( DNSCryptContext *inContext )
+{
+       OSStatus                                                err;
+       const DNSCryptCert * const              cert    = (DNSCryptCert *) inContext->certPtr;
+       const uint8_t * const                   certEnd = inContext->certPtr + inContext->certLen;
+       struct timeval                                  now;
+       time_t                                                  startTimeSecs, endTimeSecs;
+       size_t                                                  signedLen;
+       uint8_t *                                               tempBuf;
+       unsigned long long                              tempLen;
+       
+       DNSCryptPrintCertificate( cert, inContext->certLen );
+       
+       if( memcmp( cert->certMagic, kDNSCryptCertMagic, kDNSCryptCertMagicLength ) != 0 )
+       {
+               FPrintF( stderr, "DNSCrypt certificate magic %#H != %#H\n",
+                       cert->certMagic,        kDNSCryptCertMagicLength, INT_MAX,
+                       kDNSCryptCertMagic, kDNSCryptCertMagicLength, INT_MAX );
+               err = kValueErr;
+               goto exit;
+       }
+       
+       startTimeSecs   = (time_t) ReadBig32( cert->startTime );
+       endTimeSecs             = (time_t) ReadBig32( cert->endTime );
+       
+       gettimeofday( &now, NULL );
+       if( now.tv_sec < startTimeSecs )
+       {
+               FPrintF( stderr, "DNSCrypt certificate start time is in the future.\n" );
+               err = kDateErr;
+               goto exit;
+       }
+       if( now.tv_sec >= endTimeSecs )
+       {
+               FPrintF( stderr, "DNSCrypt certificate has expired.\n" );
+               err = kDateErr;
+               goto exit;
+       }
+       
+       signedLen = (size_t)( certEnd - cert->signature );
+       tempBuf = (uint8_t *) malloc( signedLen );
+       require_action( tempBuf, exit, err = kNoMemoryErr );
+       err = crypto_sign_open( tempBuf, &tempLen, cert->signature, signedLen, inContext->serverPublicSignKey );
+       free( tempBuf );
+       if( err )
+       {
+               FPrintF( stderr, "DNSCrypt certificate failed verification.\n" );
+               err = kAuthenticationErr;
+               goto exit;
+       }
+       
+       memcpy( inContext->serverPublicKey,     cert->publicKey,        crypto_box_PUBLICKEYBYTES );
+       memcpy( inContext->clientMagic,         cert->clientMagic,      kDNSCryptClientMagicLength );
+       
+       err = crypto_box_beforenm( inContext->nmKey, inContext->serverPublicKey, inContext->clientSecretKey );
+       require_noerr( err, exit );
+       
+       inContext->certPtr      = NULL;
+       inContext->certLen      = 0;
+       inContext->msgLen       = 0;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSCryptBuildQuery
+//===========================================================================================================================
+
+static OSStatus        DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen );
+
+static OSStatus        DNSCryptBuildQuery( DNSCryptContext *inContext )
+{
+       OSStatus                                                err;
+       DNSCryptQueryHeader * const             hdr                     = (DNSCryptQueryHeader *) inContext->msgBuf;
+       uint8_t * const                                 queryPtr        = (uint8_t *)( hdr + 1 );
+       size_t                                                  queryLen;
+       size_t                                                  paddedQueryLen;
+       const uint8_t * const                   msgLimit        = inContext->msgBuf + sizeof( inContext->msgBuf );
+       const uint8_t *                                 padLimit;
+       uint8_t                                                 nonce[ crypto_box_NONCEBYTES ];
+       
+       check_compile_time_code( sizeof( inContext->msgBuf ) >= ( sizeof( DNSCryptQueryHeader ) + kDNSQueryMessageMaxLen ) );
+       
+       inContext->queryID = (uint16_t) Random32();
+       err = WriteDNSQueryMessage( queryPtr, inContext->queryID, kDNSHeaderFlag_RecursionDesired, inContext->qname,
+               inContext->qtype, kDNSServiceClass_IN, &queryLen );
+       require_noerr( err, exit );
+       
+       padLimit = &queryPtr[ queryLen + kDNSCryptMaxPadLength ];
+       if( padLimit > msgLimit ) padLimit = msgLimit;
+       
+       err = DNSCryptPadQuery( queryPtr, queryLen, (size_t)( padLimit - queryPtr ), &paddedQueryLen );
+       require_noerr( err, exit );
+       
+       memset( queryPtr - crypto_box_ZEROBYTES, 0, crypto_box_ZEROBYTES );
+       RandomBytes( inContext->clientNonce, kDNSCryptHalfNonceLength );
+       memcpy( nonce, inContext->clientNonce, kDNSCryptHalfNonceLength );
+       memset( &nonce[ kDNSCryptHalfNonceLength ], 0, kDNSCryptHalfNonceLength );
+       
+       err = crypto_box_afternm( queryPtr - crypto_box_ZEROBYTES, queryPtr - crypto_box_ZEROBYTES,
+               paddedQueryLen + crypto_box_ZEROBYTES, nonce, inContext->nmKey );
+       require_noerr( err, exit );
+       
+       memcpy( hdr->clientMagic,               inContext->clientMagic,         kDNSCryptClientMagicLength );
+       memcpy( hdr->clientPublicKey,   inContext->clientPublicKey,     crypto_box_PUBLICKEYBYTES );
+       memcpy( hdr->clientNonce,               nonce,                                          kDNSCryptHalfNonceLength );
+       
+       inContext->msgLen = (size_t)( &queryPtr[ paddedQueryLen ] - inContext->msgBuf );
+       
+exit:
+       return( err );
+}
+
+static OSStatus        DNSCryptPadQuery( uint8_t *inMsgPtr, size_t inMsgLen, size_t inMaxLen, size_t *outPaddedLen )
+{
+       OSStatus                err;
+       size_t                  paddedLen;
+       
+       require_action_quiet( ( inMsgLen + kDNSCryptMinPadLength ) <= inMaxLen, exit, err = kSizeErr );
+       
+       paddedLen = inMsgLen + kDNSCryptMinPadLength +
+               arc4random_uniform( (uint32_t)( inMaxLen - ( inMsgLen + kDNSCryptMinPadLength ) + 1 ) );
+       paddedLen += ( kDNSCryptBlockSize - ( paddedLen % kDNSCryptBlockSize ) );
+       if( paddedLen > inMaxLen ) paddedLen = inMaxLen;
+       
+       inMsgPtr[ inMsgLen ] = 0x80;
+       memset( &inMsgPtr[ inMsgLen + 1 ], 0, paddedLen - ( inMsgLen + 1 ) );
+       
+       if( outPaddedLen ) *outPaddedLen = paddedLen;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSCryptSendQuery
+//===========================================================================================================================
+
+static OSStatus        DNSCryptSendQuery( DNSCryptContext *inContext )
+{
+       OSStatus                        err;
+       SocketContext *         sockCtx;
+       SocketRef                       sock = kInvalidSocketRef;
+       
+       check( inContext->msgLen > 0 );
+       check( !inContext->readSource );
+       
+       err = UDPClientSocketOpen( AF_UNSPEC, &inContext->serverAddr, 0, -1, NULL, &sock );
+       require_noerr( err, exit );
+       
+       inContext->sendTicks = UpTicks();
+       err = _SocketWriteAll( sock, inContext->msgBuf, inContext->msgLen, 5 );
+       require_noerr( err, exit );
+       
+       err = SocketContextCreate( sock, inContext, &sockCtx );
+       require_noerr( err, exit );
+       sock = kInvalidSocketRef;
+       
+       err = DispatchReadSourceCreate( sockCtx->sock, NULL, DNSCryptReceiveResponseHandler, SocketContextCancelHandler, sockCtx,
+               &inContext->readSource );
+       if( err ) ForgetSocketContext( &sockCtx );
+       require_noerr( err, exit );
+       
+       dispatch_resume( inContext->readSource );
+       
+exit:
+       ForgetSocket( &sock );
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSCryptPrintCertificate
+//===========================================================================================================================
+
+#define kCertTimeStrBufLen             32
+
+static char *  CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] );
+
+static void    DNSCryptPrintCertificate( const DNSCryptCert *inCert, size_t inLen )
+{
+       time_t          startTime, endTime;
+       int                     extLen;
+       char            timeBuf[ kCertTimeStrBufLen ];
+       
+       check( inLen >= kDNSCryptCertMinimumLength );
+       
+       startTime       = (time_t) ReadBig32( inCert->startTime );
+       endTime         = (time_t) ReadBig32( inCert->endTime );
+       
+       FPrintF( stdout, "DNSCrypt certificate (%zu bytes):\n", inLen );
+       FPrintF( stdout, "Cert Magic:    %#H\n", inCert->certMagic, kDNSCryptCertMagicLength, INT_MAX );
+       FPrintF( stdout, "ES Version:    %u\n", ReadBig16( inCert->esVersion ) );
+       FPrintF( stdout, "Minor Version: %u\n", ReadBig16( inCert->minorVersion ) );
+       FPrintF( stdout, "Signature:     %H\n", inCert->signature, crypto_sign_BYTES / 2, INT_MAX );
+       FPrintF( stdout, "               %H\n", &inCert->signature[ crypto_sign_BYTES / 2 ], crypto_sign_BYTES / 2, INT_MAX );
+       FPrintF( stdout, "Public Key:    %H\n", inCert->publicKey, sizeof( inCert->publicKey ), INT_MAX );
+       FPrintF( stdout, "Client Magic:  %H\n", inCert->clientMagic, kDNSCryptClientMagicLength, INT_MAX );
+       FPrintF( stdout, "Serial:        %u\n", ReadBig32( inCert->serial ) );
+       FPrintF( stdout, "Start Time:    %u (%s)\n", (uint32_t) startTime, CertTimeStr( startTime, timeBuf ) );
+       FPrintF( stdout, "End Time:      %u (%s)\n", (uint32_t) endTime, CertTimeStr( endTime, timeBuf ) );
+       
+       if( inLen > kDNSCryptCertMinimumLength )
+       {
+               extLen = (int)( inLen - kDNSCryptCertMinimumLength );
+               FPrintF( stdout, "Extensions:    %.1H\n", inCert->extensions, extLen, extLen );
+       }
+       FPrintF( stdout, "\n" );
+}
+
+static char *  CertTimeStr( time_t inTime, char inBuffer[ kCertTimeStrBufLen ] )
+{
+       struct tm *             tm;
+       
+       tm = localtime( &inTime );
+       if( !tm )
+       {
+               dlogassert( "localtime() returned a NULL pointer.\n" );
+               *inBuffer = '\0';
+       }
+       else
+       {
+               strftime( inBuffer, kCertTimeStrBufLen, "%a %b %d %H:%M:%S %Z %Y", tm );
+       }
+       
+       return( inBuffer );
+}
+
+#endif // DNSSDUTIL_INCLUDE_DNSCRYPT
+
+//===========================================================================================================================
+//     MDNSQueryCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       const char *                    qnameStr;                                                       // Name (QNAME) of the record being queried as a C string.
+       dispatch_source_t               readSourceV4;                                           // Read dispatch source for IPv4 socket.
+       dispatch_source_t               readSourceV6;                                           // Read dispatch source for IPv6 socket.
+       int                                             localPort;                                                      // The port number to which the sockets are bound.
+       int                                             receiveSecs;                                            // After send, the amount of time to spend receiving.
+       uint32_t                                ifIndex;                                                        // Index of the interface over which to send the query.
+       uint16_t                                qtype;                                                          // The type (QTYPE) of the record being queried.
+       Boolean                                 isQU;                                                           // True if the query is QU, i.e., requests unicast responses.
+       Boolean                                 allResponses;                                           // True if all mDNS messages received should be printed.
+       Boolean                                 printRawRData;                                          // True if RDATA should be printed as hexdumps.
+       Boolean                                 useIPv4;                                                        // True if the query should be sent via IPv4 multicast.
+       Boolean                                 useIPv6;                                                        // True if the query should be sent via IPv6 multicast.
+       char                                    ifName[ IF_NAMESIZE + 1 ];                      // Name of the interface over which to send the query.
+       uint8_t                                 qname[ kDomainNameLengthMax ];          // Buffer to hold the QNAME in DNS label format.
+       uint8_t                                 msgBuf[ kMDNSMessageSizeMax ];          // mDNS message buffer.
+       
+}      MDNSQueryContext;
+
+static void    MDNSQueryPrintPrologue( const MDNSQueryContext *inContext );
+static void    MDNSQueryReadHandler( void *inContext );
+
+static void    MDNSQueryCmd( void )
+{
+       OSStatus                                err;
+       MDNSQueryContext *              context;
+       SocketRef                               sockV4 = kInvalidSocketRef;
+       SocketRef                               sockV6 = kInvalidSocketRef;
+       ssize_t                                 n;
+       const char *                    ifname;
+       size_t                                  msgLen;
+       unsigned int                    sendCount;
+       
+       // Check command parameters.
+       
+       if( gMDNSQuery_ReceiveSecs < -1 )
+       {
+               FPrintF( stdout, "Invalid receive time value: %d seconds.\n", gMDNSQuery_ReceiveSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       context = (MDNSQueryContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->qnameStr               = gMDNSQuery_Name;
+       context->receiveSecs    = gMDNSQuery_ReceiveSecs;
+       context->isQU                   = gMDNSQuery_IsQU                 ? true : false;
+       context->allResponses   = gMDNSQuery_AllResponses ? true : false;
+       context->printRawRData  = gMDNSQuery_RawRData     ? true : false;
+       context->useIPv4                = ( gMDNSQuery_UseIPv4 || !gMDNSQuery_UseIPv6 ) ? true : false;
+       context->useIPv6                = ( gMDNSQuery_UseIPv6 || !gMDNSQuery_UseIPv4 ) ? true : false;
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       ifname = if_indextoname( context->ifIndex, context->ifName );
+       require_action( ifname, exit, err = kNameErr );
+       
+       err = RecordTypeFromArgString( gMDNSQuery_Type, &context->qtype );
+       require_noerr( err, exit );
+       
+       // Set up IPv4 socket.
+       
+       if( context->useIPv4 )
+       {
+               err = CreateMulticastSocket( GetMDNSMulticastAddrV4(),
+                       gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
+                       ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV4 );
+               require_noerr( err, exit );
+       }
+       
+       // Set up IPv6 socket.
+       
+       if( context->useIPv6 )
+       {
+               err = CreateMulticastSocket( GetMDNSMulticastAddrV6(),
+                       gMDNSQuery_SourcePort ? gMDNSQuery_SourcePort : ( context->isQU ? context->localPort : kMDNSPort ),
+                       ifname, context->ifIndex, !context->isQU, &context->localPort, &sockV6 );
+               require_noerr( err, exit );
+       }
+       
+       // Craft mDNS query message.
+       
+       check_compile_time_code( sizeof( context->msgBuf ) >= kDNSQueryMessageMaxLen );
+       err = WriteDNSQueryMessage( context->msgBuf, kDefaultMDNSMessageID, kDefaultMDNSQueryFlags, context->qnameStr,
+               context->qtype, context->isQU ? ( kDNSServiceClass_IN | kQClassUnicastResponseBit ) : kDNSServiceClass_IN, &msgLen );
+       require_noerr( err, exit );
+       
+       // Print prologue.
+       
+       MDNSQueryPrintPrologue( context );
+       
+       // Send mDNS query message.
+       
+       sendCount = 0;
+       if( IsValidSocket( sockV4 ) )
+       {
+               const struct sockaddr * const           mcastAddr4 = GetMDNSMulticastAddrV4();
+               
+               n = sendto( sockV4, context->msgBuf, msgLen, 0, mcastAddr4, SockAddrGetSize( mcastAddr4 ) );
+               err = map_socket_value_errno( sockV4, n == (ssize_t) msgLen, n );
+               if( err )
+               {
+                       FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
+                       ForgetSocket( &sockV4 );
+               }
+               else
+               {
+                       ++sendCount;
+               }
+       }
+       if( IsValidSocket( sockV6 ) )
+       {
+               const struct sockaddr * const           mcastAddr6 = GetMDNSMulticastAddrV6();
+               
+               n = sendto( sockV6, context->msgBuf, msgLen, 0, mcastAddr6, SockAddrGetSize( mcastAddr6 ) );
+               err = map_socket_value_errno( sockV6, n == (ssize_t) msgLen, n );
+               if( err )
+               {
+                       FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
+                       ForgetSocket( &sockV6 );
+               }
+               else
+               {
+                       ++sendCount;
+               }
+       }
+       require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
+       
+       // If there's no wait period after the send, then exit.
+       
+       if( context->receiveSecs == 0 ) goto exit;
+       
+       // Create dispatch read sources for socket(s).
+       
+       if( IsValidSocket( sockV4 ) )
+       {
+               SocketContext *         sockCtx;
+               
+               err = SocketContextCreate( sockV4, context, &sockCtx );
+               require_noerr( err, exit );
+               sockV4 = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
+                       &context->readSourceV4 );
+               if( err ) ForgetSocketContext( &sockCtx );
+               require_noerr( err, exit );
+               
+               dispatch_resume( context->readSourceV4 );
+       }
+       
+       if( IsValidSocket( sockV6 ) )
+       {
+               SocketContext *         sockCtx;
+               
+               err = SocketContextCreate( sockV6, context, &sockCtx );
+               require_noerr( err, exit );
+               sockV6 = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, NULL, MDNSQueryReadHandler, SocketContextCancelHandler, sockCtx,
+                       &context->readSourceV6 );
+               if( err ) ForgetSocketContext( &sockCtx );
+               require_noerr( err, exit );
+               
+               dispatch_resume( context->readSourceV6 );
+       }
+       
+       if( context->receiveSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+                       Exit );
+       }
+       dispatch_main();
+       
+exit:
+       ForgetSocket( &sockV4 );
+       ForgetSocket( &sockV6 );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     MDNSColliderCmd
+//===========================================================================================================================
+
+static void    _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError );
+
+static void    MDNSColliderCmd( void )
+{
+       OSStatus                                        err;
+       MDNSColliderRef                         collider = NULL;
+       uint8_t *                                       rdataPtr = NULL;
+       size_t                                          rdataLen = 0;
+       const char *                            ifname;
+       uint32_t                                        ifIndex;
+       MDNSColliderProtocols           protocols;
+       uint16_t                                        type;
+       char                                            ifName[ IF_NAMESIZE + 1 ];
+       uint8_t                                         name[ kDomainNameLengthMax ];
+       
+       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       ifname = if_indextoname( ifIndex, ifName );
+       if( !ifname )
+       {
+               FPrintF( stderr, "error: Invalid interface name or index: %s\n", gInterface );
+               err = kNameErr;
+               goto exit;
+       }
+       
+       err = DomainNameFromString( name, gMDNSCollider_Name, NULL );
+       if( err )
+       {
+               FPrintF( stderr, "error: Invalid record name: %s\n", gMDNSCollider_Name );
+               goto exit;
+       }
+       
+       err = RecordTypeFromArgString( gMDNSCollider_Type, &type );
+       require_noerr_quiet( err, exit );
+       
+       if( gMDNSCollider_RecordData )
+       {
+               err = RecordDataFromArgString( gMDNSCollider_RecordData, &rdataPtr, &rdataLen );
+               require_noerr_quiet( err, exit );
+       }
+       
+       err = MDNSColliderCreate( dispatch_get_main_queue(), &collider );
+       require_noerr( err, exit );
+       
+       err = MDNSColliderSetProgram( collider, gMDNSCollider_Program );
+       if( err )
+       {
+               FPrintF( stderr, "error: Failed to set program string: '%s'\n", gMDNSCollider_Program );
+               goto exit;
+       }
+       
+       err = MDNSColliderSetRecord( collider, name, type, rdataPtr, rdataLen );
+       require_noerr( err, exit );
+       ForgetMem( &rdataPtr );
+       
+       protocols = kMDNSColliderProtocol_None;
+       if( gMDNSCollider_UseIPv4 || !gMDNSCollider_UseIPv6 ) protocols |= kMDNSColliderProtocol_IPv4;
+       if( gMDNSCollider_UseIPv6 || !gMDNSCollider_UseIPv4 ) protocols |= kMDNSColliderProtocol_IPv6;
+       MDNSColliderSetProtocols( collider, protocols );
+       MDNSColliderSetInterfaceIndex( collider, ifIndex );
+       MDNSColliderSetStopHandler( collider, _MDNSColliderCmdStopHandler, collider );
+       
+       err = MDNSColliderStart( collider );
+       require_noerr( err, exit );
+       
+       dispatch_main();
+       
+exit:
+       FreeNullSafe( rdataPtr );
+       CFReleaseNullSafe( collider );
+       if( err ) exit( 1 );
+}
+
+static void    _MDNSColliderCmdStopHandler( void *inContext, OSStatus inError )
+{
+       MDNSColliderRef const           collider = (MDNSColliderRef) inContext;
+       
+       CFRelease( collider );
+       exit( inError ? 1 : 0 );
+}
+
+//===========================================================================================================================
+//     MDNSQueryPrintPrologue
+//===========================================================================================================================
+
+static void    MDNSQueryPrintPrologue( const MDNSQueryContext *inContext )
+{
+       const int               receiveSecs = inContext->receiveSecs;
+       
+       FPrintF( stdout, "Interface:        %d (%s)\n",         (int32_t) inContext->ifIndex, inContext->ifName );
+       FPrintF( stdout, "Name:             %s\n",                      inContext->qnameStr );
+       FPrintF( stdout, "Type:             %s (%u)\n",         RecordTypeToString( inContext->qtype ), inContext->qtype );
+       FPrintF( stdout, "Class:            IN (%s)\n",         inContext->isQU ? "QU" : "QM" );
+       FPrintF( stdout, "Local port:       %d\n",                      inContext->localPort );
+       FPrintF( stdout, "IP protocols:     %?s%?s%?s\n",
+               inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
+       FPrintF( stdout, "Receive duration: " );
+       if( receiveSecs >= 0 )  FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
+       else                                    FPrintF( stdout, "∞\n" );
+       FPrintF( stdout, "Start time:       %{du:time}\n",      NULL );
+}
+
+//===========================================================================================================================
+//     MDNSQueryReadHandler
+//===========================================================================================================================
+
+static void    MDNSQueryReadHandler( void *inContext )
+{
+       OSStatus                                                err;
+       struct timeval                                  now;
+       SocketContext * const                   sockCtx = (SocketContext *) inContext;
+       MDNSQueryContext * const                context = (MDNSQueryContext *) sockCtx->userContext;
+       size_t                                                  msgLen;
+       sockaddr_ip                                             fromAddr;
+       Boolean                                                 foundAnswer     = false;
+       
+       gettimeofday( &now, NULL );
+       
+       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &fromAddr,
+               sizeof( fromAddr ), NULL, NULL, NULL, NULL );
+       require_noerr( err, exit );
+       
+       if( !context->allResponses && ( msgLen >= kDNSHeaderLength ) )
+       {
+               const uint8_t *                         ptr;
+               const DNSHeader * const         hdr = (DNSHeader *) context->msgBuf;
+               unsigned int                            rrCount, i;
+               uint16_t                                        type, class;
+               uint8_t                                         name[ kDomainNameLengthMax ];
+               
+               err = DNSMessageGetAnswerSection( context->msgBuf, msgLen, &ptr );
+               require_noerr( err, exit );
+               
+               if( context->qname[ 0 ] == 0 )
+               {
+                       err = DomainNameAppendString( context->qname, context->qnameStr, NULL );
+                       require_noerr( err, exit );
+               }
+               
+               rrCount = DNSHeaderGetAnswerCount( hdr ) + DNSHeaderGetAuthorityCount( hdr ) + DNSHeaderGetAdditionalCount( hdr );
+               for( i = 0; i < rrCount; ++i )
+               {
+                       err = DNSMessageExtractRecord( context->msgBuf, msgLen, ptr, name, &type, &class, NULL, NULL, NULL, &ptr );
+                       require_noerr( err, exit );
+                       
+                       if( ( ( context->qtype == kDNSServiceType_ANY ) || ( type == context->qtype ) ) &&
+                               DomainNameEqual( name, context->qname ) )
+                       {
+                               foundAnswer = true;
+                               break;
+                       }
+               }
+       }
+       if( context->allResponses || foundAnswer )
+       {
+               FPrintF( stdout, "---\n" );
+               FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
+               FPrintF( stdout, "Source:       %##a\n",                &fromAddr );
+               FPrintF( stdout, "Message size: %zu\n\n%#.*{du:dnsmsg}",
+                       msgLen, context->printRawRData ? 1 : 0, context->msgBuf, msgLen );
+       }
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     PIDToUUIDCmd
+//===========================================================================================================================
+
+static void    PIDToUUIDCmd( void )
+{
+       OSStatus                                                        err;
+       int                                                                     n;
+       struct proc_uniqidentifierinfo          info;
+       
+       n = proc_pidinfo( gPIDToUUID_PID, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof( info ) );
+       require_action_quiet( n == (int) sizeof( info ), exit, err = kUnknownErr );
+       
+       FPrintF( stdout, "%#U\n", info.p_uuid );
+       err = kNoErr;
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     DNSServerCmd
+//===========================================================================================================================
+
+typedef struct DNSServerPrivate *              DNSServerRef;
+
+typedef struct
+{
+       DNSServerRef                    server;                 // Reference to the DNS server.
+       dispatch_source_t               sigIntSource;   // Dispatch SIGINT source.
+       dispatch_source_t               sigTermSource;  // Dispatch SIGTERM source.
+       const char *                    domainOverride; // If non-NULL, the server is to use this domain instead of "d.test.".
+#if( TARGET_OS_DARWIN )
+       dispatch_source_t               processMonitor; // Process monitor source for process being followed, if any.
+       pid_t                                   followPID;              // PID of process being followed, if any. (If it exits, we exit).
+       Boolean                                 addedResolver;  // True if system DNS settings contains a resolver entry for server.
+#endif
+       Boolean                                 loopbackOnly;   // True if the server should be bound to the loopback interface.
+       
+}      DNSServerCmdContext;
+
+typedef enum
+{
+       kDNSServerEvent_Started = 1,
+       kDNSServerEvent_Stopped = 2
+       
+}      DNSServerEventType;
+
+typedef void ( *DNSServerEventHandler_f )( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
+
+CFTypeID       DNSServerGetTypeID( void );
+static OSStatus
+       DNSServerCreate(
+               dispatch_queue_t                inQueue,
+               DNSServerEventHandler_f inEventHandler,
+               void *                                  inEventContext,
+               unsigned int                    inResponseDelayMs,
+               uint32_t                                inDefaultTTL,
+               int                                             inPort,
+               Boolean                                 inLoopbackOnly,
+               const char *                    inDomain,
+               Boolean                                 inBadUDPMode,
+               DNSServerRef *                  outServer );
+static void    DNSServerStart( DNSServerRef inServer );
+static void    DNSServerStop( DNSServerRef inServer );
+
+#define ForgetDNSServer( X )           ForgetCustomEx( X, DNSServerStop, CFRelease )
+
+static void    DNSServerCmdContextFree( DNSServerCmdContext *inContext );
+static void    DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext );
+static void    DNSServerCmdSigIntHandler( void *inContext );
+static void    DNSServerCmdSigTermHandler( void *inContext );
+#if( TARGET_OS_DARWIN )
+static void    DNSServerCmdFollowedProcessHandler( void *inContext );
+#endif
+
+ulog_define_ex( kDNSSDUtilIdentifier, DNSServer, kLogLevelInfo, kLogFlags_None, "DNSServer", NULL );
+#define ds_ulog( LEVEL, ... )          ulog( &log_category_from_name( DNSServer ), (LEVEL), __VA_ARGS__ )
+
+static void    DNSServerCmd( void )
+{
+       OSStatus                                        err;
+       DNSServerCmdContext *           context = NULL;
+       
+       if( gDNSServer_Foreground )
+       {
+               LogControl( "DNSServer:output=file;stdout,DNSServer:flags=time;prefix" );
+       }
+       
+       err = CheckIntegerArgument( gDNSServer_ResponseDelayMs, "response delay (ms)", 0, INT_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gDNSServer_DefaultTTL, "default TTL", 0, INT32_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gDNSServer_Port, "port number", -UINT16_MAX, UINT16_MAX );
+       require_noerr_quiet( err, exit );
+       
+       context = (DNSServerCmdContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->domainOverride = gDNSServer_DomainOverride;
+       context->loopbackOnly   = gDNSServer_LoopbackOnly ? true : false;
+       
+#if( TARGET_OS_DARWIN )
+       if( gDNSServer_FollowPID )
+       {
+               context->followPID = _StringToPID( gDNSServer_FollowPID, &err );
+               if( err || ( context->followPID < 0 ) )
+               {
+                       FPrintF( stderr, "error: Invalid follow PID: %s\n", gDNSServer_FollowPID );
+                       err = kParamErr;
+                       goto exit;
+               }
+               
+               err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
+                       DNSServerCmdFollowedProcessHandler, NULL, context, &context->processMonitor );
+               require_noerr( err, exit );
+               dispatch_resume( context->processMonitor );
+       }
+       else
+       {
+               context->followPID = -1;
+       }
+#endif
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, DNSServerCmdSigIntHandler, context, &context->sigIntSource );
+       require_noerr( err, exit );
+       dispatch_resume( context->sigIntSource );
+       
+       signal( SIGTERM, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGTERM, DNSServerCmdSigTermHandler, context, &context->sigTermSource );
+       require_noerr( err, exit );
+       dispatch_resume( context->sigTermSource );
+       
+       err = DNSServerCreate( dispatch_get_main_queue(), DNSServerCmdEventHandler, context,
+               (unsigned int) gDNSServer_ResponseDelayMs, (uint32_t) gDNSServer_DefaultTTL, gDNSServer_Port, context->loopbackOnly,
+               context->domainOverride, gDNSServer_BadUDPMode ? true : false, &context->server );
+       require_noerr( err, exit );
+       
+       DNSServerStart( context->server );
+       dispatch_main();
+       
+exit:
+       FPrintF( stderr, "Failed to start DNS server: %#m\n", err );
+       if( context ) DNSServerCmdContextFree( context );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     DNSServerCmdContextFree
+//===========================================================================================================================
+
+static void    DNSServerCmdContextFree( DNSServerCmdContext *inContext )
+{
+       ForgetCF( &inContext->server );
+       dispatch_source_forget( &inContext->sigIntSource );
+       dispatch_source_forget( &inContext->sigTermSource );
+#if( TARGET_OS_DARWIN )
+       dispatch_source_forget( &inContext->processMonitor );
+#endif
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     DNSServerCmdEventHandler
+//===========================================================================================================================
+
+#if( TARGET_OS_DARWIN )
+static OSStatus        _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort );
+static OSStatus        _DNSServerCmdLoopbackResolverRemove( void );
+#endif
+
+static void    DNSServerCmdEventHandler( DNSServerEventType inType, uintptr_t inEventData, void *inContext )
+{
+       OSStatus                                                err;
+       DNSServerCmdContext * const             context = (DNSServerCmdContext *) inContext;
+       
+       if( inType == kDNSServerEvent_Started )
+       {
+       #if( TARGET_OS_DARWIN )
+               const int               port = (int) inEventData;
+               
+               err = _DNSServerCmdLoopbackResolverAdd( context->domainOverride ? context->domainOverride : "d.test.", port );
+               if( err )
+               {
+                       ds_ulog( kLogLevelError, "Failed to add loopback resolver to DNS configuration for \"d.test.\" domain: %#m\n",
+                               err );
+                       if( context->loopbackOnly ) ForgetDNSServer( &context->server );
+               }
+               else
+               {
+                       context->addedResolver = true;
+               }
+       #endif
+       }
+       else if( inType == kDNSServerEvent_Stopped )
+       {
+               const OSStatus          stopError = (OSStatus) inEventData;
+               
+               if( stopError ) ds_ulog( kLogLevelError, "The server stopped unexpectedly with error: %#m.\n", stopError );
+               
+               err = kNoErr;
+       #if( TARGET_OS_DARWIN )
+               if( context->addedResolver )
+               {
+                       err = _DNSServerCmdLoopbackResolverRemove();
+                       if( err )
+                       {
+                               ds_ulog( kLogLevelError, "Failed to remove loopback resolver from DNS configuration: %#m\n", err );
+                       }
+                       else
+                       {
+                               context->addedResolver = false;
+                       }
+               }
+               else if( context->loopbackOnly )
+               {
+                       err = kUnknownErr;
+               }
+       #endif
+               DNSServerCmdContextFree( context );
+               exit( ( stopError || err ) ? 1 : 0 );
+       }
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+//     _DNSServerCmdLoopbackResolverAdd
+//===========================================================================================================================
+
+static OSStatus        _DNSServerCmdLoopbackResolverAdd( const char *inDomain, int inPort )
+{
+       OSStatus                                err;
+       SCDynamicStoreRef               store;
+       CFPropertyListRef               plist           = NULL;
+       CFStringRef                             key                     = NULL;
+       const uint32_t                  loopbackV4      = htonl( INADDR_LOOPBACK );
+       Boolean                                 success;
+       
+       store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+       err = map_scerror( store );
+       require_noerr( err, exit );
+       
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+               "{"
+                       "%kO="
+                       "["
+                               "%s"
+                       "]"
+                       "%kO="
+                       "["
+                               "%.4a"
+                               "%.16a"
+                       "]"
+                       "%kO=%i"
+                       "%kO=%O"
+                       "%kO=%O"
+               "}",
+               kSCPropNetDNSSupplementalMatchDomains,  inDomain,
+               kSCPropNetDNSServerAddresses,                   &loopbackV4, in6addr_loopback.s6_addr,
+               kSCPropNetDNSServerPort,                                inPort,
+               kSCPropInterfaceName,                                   CFSTR( "lo0" ),
+       kSCPropNetDNSConfirmedServiceID,                        CFSTR( "com.apple.dnssdutil.server" ) );
+       require_noerr( err, exit );
+       
+       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
+               CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
+       require_action( key, exit, err = kUnknownErr );
+       
+       success = SCDynamicStoreSetValue( store, key, plist );
+       require_action( success, exit, err = kUnknownErr );
+       
+exit:
+       CFReleaseNullSafe( store );
+       CFReleaseNullSafe( plist );
+       CFReleaseNullSafe( key );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _DNSServerCmdLoopbackResolverRemove
+//===========================================================================================================================
+
+static OSStatus        _DNSServerCmdLoopbackResolverRemove( void )
+{
+       OSStatus                                err;
+       SCDynamicStoreRef               store;
+       CFStringRef                             key = NULL;
+       Boolean                                 success;
+       
+       store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+       err = map_scerror( store );
+       require_noerr( err, exit );
+       
+       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState,
+               CFSTR( "com.apple.dnssdutil.server" ), kSCEntNetDNS );
+       require_action( key, exit, err = kUnknownErr );
+       
+       success = SCDynamicStoreRemoveValue( store, key );
+       require_action( success, exit, err = kUnknownErr );
+       
+exit:
+       CFReleaseNullSafe( store );
+       CFReleaseNullSafe( key );
+       return( err );
+}
+#endif
+
+//===========================================================================================================================
+//     DNSServerCmdSigIntHandler
+//===========================================================================================================================
+
+static void    _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal );
+
+static void    DNSServerCmdSigIntHandler( void *inContext )
+{
+       _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGINT );
+}
+
+//===========================================================================================================================
+//     DNSServerCmdSigTermHandler
+//===========================================================================================================================
+
+static void    DNSServerCmdSigTermHandler( void *inContext )
+{
+       _DNSServerCmdShutdown( (DNSServerCmdContext *) inContext, SIGTERM );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+//     DNSServerCmdFollowedProcessHandler
+//===========================================================================================================================
+
+static void    DNSServerCmdFollowedProcessHandler( void *inContext )
+{
+       DNSServerCmdContext * const             context = (DNSServerCmdContext *) inContext;
+       
+       if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT ) _DNSServerCmdShutdown( context, 0 );
+}
+#endif
+
+//===========================================================================================================================
+//     _DNSServerCmdExternalExit
+//===========================================================================================================================
+
+#define SignalNumberToString( X ) (            \
+       ( (X) == SIGINT )  ? "SIGINT"  :        \
+       ( (X) == SIGTERM ) ? "SIGTERM" :        \
+                                                "???" )
+
+static void    _DNSServerCmdShutdown( DNSServerCmdContext *inContext, int inSignal )
+{
+       dispatch_source_forget( &inContext->sigIntSource );
+       dispatch_source_forget( &inContext->sigTermSource );
+#if( TARGET_OS_DARWIN )
+       dispatch_source_forget( &inContext->processMonitor );
+       
+       if( inSignal == 0 )
+       {
+               ds_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited\n", (int64_t) inContext->followPID );
+       }
+       else
+#endif
+       {
+               ds_ulog( kLogLevelNotice, "Exiting: received signal %d (%s)\n", inSignal, SignalNumberToString( inSignal ) );
+       }
+       
+       ForgetDNSServer( &inContext->server );
+}
+
+//===========================================================================================================================
+//     DNSServerCreate
+//===========================================================================================================================
+
+#define kDDotTestDomainName            (const uint8_t *) "\x01" "d" "\x04" "test"
+
+typedef struct DNSDelayedResponse              DNSDelayedResponse;
+struct DNSDelayedResponse
+{
+       DNSDelayedResponse *            next;
+       sockaddr_ip                                     destAddr;
+       uint64_t                                        targetTicks;
+       uint8_t *                                       msgPtr;
+       size_t                                          msgLen;
+};
+
+struct DNSServerPrivate
+{
+       CFRuntimeBase                           base;                           // CF object base.
+       uint8_t *                                       domain;                         // Parent domain of server's resource records.
+       dispatch_queue_t                        queue;                          // Queue for DNS server's events.
+       dispatch_source_t                       readSourceUDPv4;        // Read source for IPv4 UDP socket.
+       dispatch_source_t                       readSourceUDPv6;        // Read source for IPv6 UDP socket.
+       dispatch_source_t                       readSourceTCPv4;        // Read source for IPv4 TCP socket.
+       dispatch_source_t                       readSourceTCPv6;        // Read source for IPv6 TCP socket.
+       SocketRef                                       sockUDPv4;
+       SocketRef                                       sockUDPv6;
+       DNSServerEventHandler_f         eventHandler;
+       void *                                          eventContext;
+       DNSDelayedResponse *            responseList;
+       dispatch_source_t                       responseTimer;
+       unsigned int                            responseDelayMs;
+       uint32_t                                        defaultTTL;
+       uint32_t                                        serial;                         // Serial number for SOA record.
+       int                                                     port;                           // Port to use for receiving and sending DNS messages.
+       OSStatus                                        stopError;
+       Boolean                                         stopped;
+       Boolean                                         loopbackOnly;
+       Boolean                                         badUDPMode;                     // True if the server runs in Bad UDP mode.
+};
+
+static void    _DNSServerUDPReadHandler( void *inContext );
+static void    _DNSServerTCPReadHandler( void *inContext );
+static void    _DNSDelayedResponseFree( DNSDelayedResponse *inResponse );
+static void    _DNSDelayedResponseFreeList( DNSDelayedResponse *inList );
+
+CF_CLASS_DEFINE( DNSServer );
+
+static OSStatus
+       DNSServerCreate(
+               dispatch_queue_t                inQueue,
+               DNSServerEventHandler_f inEventHandler,
+               void *                                  inEventContext,
+               unsigned int                    inResponseDelayMs,
+               uint32_t                                inDefaultTTL,
+               int                                             inPort,
+               Boolean                                 inLoopbackOnly,
+               const char *                    inDomain,
+               Boolean                                 inBadUDPMode,
+               DNSServerRef *                  outServer )
+{
+       OSStatus                        err;
+       DNSServerRef            obj = NULL;
+       
+       require_action_quiet( inDefaultTTL <= INT32_MAX, exit, err = kRangeErr );
+       
+       CF_OBJECT_CREATE( DNSServer, obj, err, exit );
+       
+       ReplaceDispatchQueue( &obj->queue, inQueue );
+       obj->eventHandler               = inEventHandler;
+       obj->eventContext               = inEventContext;
+       obj->responseDelayMs    = inResponseDelayMs;
+       obj->defaultTTL                 = inDefaultTTL;
+       obj->port                               = inPort;
+       obj->loopbackOnly               = inLoopbackOnly;
+       obj->badUDPMode                 = inBadUDPMode;
+       
+       if( inDomain )
+       {
+               err = StringToDomainName( inDomain, &obj->domain, NULL );
+               require_noerr_quiet( err, exit );
+       }
+       else
+       {
+               err = DomainNameDup( kDDotTestDomainName, &obj->domain, NULL );
+               require_noerr_quiet( err, exit );
+       }
+       
+       *outServer = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       CFReleaseNullSafe( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _DNSServerFinalize
+//===========================================================================================================================
+
+static void    _DNSServerFinalize( CFTypeRef inObj )
+{
+       DNSServerRef const              me = (DNSServerRef) inObj;
+       
+       check( !me->readSourceUDPv4 );
+       check( !me->readSourceUDPv6 );
+       check( !me->readSourceTCPv4 );
+       check( !me->readSourceTCPv6 );
+       check( !me->responseTimer );
+       ForgetMem( &me->domain );
+       dispatch_forget( &me->queue );
+}
+
+//===========================================================================================================================
+//     DNSServerStart
+//===========================================================================================================================
+
+static void    _DNSServerStart( void *inContext );
+static void    _DNSServerStop( void *inContext, OSStatus inError );
+
+static void    DNSServerStart( DNSServerRef me )
+{
+       CFRetain( me );
+       dispatch_async_f( me->queue, me, _DNSServerStart );
+}
+
+static void    _DNSServerStart( void *inContext )
+{
+       OSStatus                                err;
+       struct timeval                  now;
+       DNSServerRef const              me                      = (DNSServerRef) inContext;
+       SocketRef                               sock            = kInvalidSocketRef;
+       SocketContext *                 sockCtx         = NULL;
+       const uint32_t                  loopbackV4      = htonl( INADDR_LOOPBACK );
+       int                                             year, month, day;
+       
+       // Create IPv4 UDP socket.
+       // Initially, me->port is the port requested by the user. If it's 0, then the user wants any available ephemeral port.
+       // If it's negative, then the user would like a port number equal to its absolute value, but will settle for any
+       // available ephemeral port, if it's not available. The actual port number that was used will be stored in me->port and
+       // used for the remaining sockets.
+       
+       err = _ServerSocketOpenEx2( AF_INET, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &loopbackV4 : NULL,
+               me->port, &me->port, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
+       require_noerr( err, exit );
+       check( me->port > 0 );
+       
+       // Create read source for IPv4 UDP socket.
+       
+       err = SocketContextCreate( sock, me, &sockCtx );
+       require_noerr( err, exit );
+       sock = kInvalidSocketRef;
+       
+       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
+               &me->readSourceUDPv4 );
+       require_noerr( err, exit );
+       dispatch_resume( me->readSourceUDPv4 );
+       me->sockUDPv4 = sockCtx->sock;
+       sockCtx = NULL;
+       
+       // Create IPv6 UDP socket.
+       
+       err = _ServerSocketOpenEx2( AF_INET6, SOCK_DGRAM, IPPROTO_UDP, me->loopbackOnly ? &in6addr_loopback : NULL,
+               me->port, NULL, kSocketBufferSize_DontSet, me->loopbackOnly ? true : false, &sock );
+       require_noerr( err, exit );
+       
+       // Create read source for IPv6 UDP socket.
+       
+       err = SocketContextCreate( sock, me, &sockCtx );
+       require_noerr( err, exit );
+       sock = kInvalidSocketRef;
+       
+       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerUDPReadHandler, SocketContextCancelHandler, sockCtx,
+               &me->readSourceUDPv6 );
+       require_noerr( err, exit );
+       dispatch_resume( me->readSourceUDPv6 );
+       me->sockUDPv6 = sockCtx->sock;
+       sockCtx = NULL;
+       
+       // Create IPv4 TCP socket.
+       
+       err = _ServerSocketOpenEx2( AF_INET, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &loopbackV4 : NULL,
+               me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
+       require_noerr( err, exit );
+       
+       // Create read source for IPv4 TCP socket.
+       
+       err = SocketContextCreate( sock, me, &sockCtx );
+       require_noerr( err, exit );
+       sock = kInvalidSocketRef;
+       
+       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
+               &me->readSourceTCPv4 );
+       require_noerr( err, exit );
+       dispatch_resume( me->readSourceTCPv4 );
+       sockCtx = NULL;
+       
+       // Create IPv6 TCP socket.
+       
+       err = _ServerSocketOpenEx2( AF_INET6, SOCK_STREAM, IPPROTO_TCP, me->loopbackOnly ? &in6addr_loopback : NULL,
+               me->port, NULL, kSocketBufferSize_DontSet, false, &sock );
+       require_noerr( err, exit );
+       
+       // Create read source for IPv6 TCP socket.
+       
+       err = SocketContextCreate( sock, me, &sockCtx );
+       require_noerr( err, exit );
+       sock = kInvalidSocketRef;
+       
+       err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _DNSServerTCPReadHandler, SocketContextCancelHandler, sockCtx,
+               &me->readSourceTCPv6 );
+       require_noerr( err, exit );
+       dispatch_resume( me->readSourceTCPv6 );
+       sockCtx = NULL;
+       
+       ds_ulog( kLogLevelInfo, "Server is using port %d.\n", me->port );
+       if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Started, (uintptr_t) me->port, me->eventContext );
+       
+       // Create the serial number for the server's SOA record in the YYYMMDDnn convention recommended by
+       // <https://tools.ietf.org/html/rfc1912#section-2.2> using the current time.
+       
+       gettimeofday( &now, NULL );
+       SecondsToYMD_HMS( ( INT64_C_safe( kDaysToUnixEpoch ) * kSecondsPerDay ) + now.tv_sec, &year, &month, &day,
+               NULL, NULL, NULL );
+       me->serial = (uint32_t)( ( year * 1000000 ) + ( month * 10000 ) + ( day * 100 ) + 1 );
+       
+exit:
+       ForgetSocket( &sock );
+       if( sockCtx ) SocketContextRelease( sockCtx );
+       if( err ) _DNSServerStop( me, err );
+}
+
+//===========================================================================================================================
+//     DNSServerStop
+//===========================================================================================================================
+
+static void    _DNSServerUserStop( void *inContext );
+static void    _DNSServerStop2( void *inContext );
+
+static void    DNSServerStop( DNSServerRef me )
+{
+       CFRetain( me );
+       dispatch_async_f( me->queue, me, _DNSServerUserStop );
+}
+
+static void    _DNSServerUserStop( void *inContext )
+{
+       DNSServerRef const              me = (DNSServerRef) inContext;
+       
+       _DNSServerStop( me, kNoErr );
+       CFRelease( me );
+}
+
+static void    _DNSServerStop( void *inContext, OSStatus inError )
+{
+       DNSServerRef const              me = (DNSServerRef) inContext;
+       
+       me->stopError = inError;
+       dispatch_source_forget( &me->readSourceUDPv4 );
+       dispatch_source_forget( &me->readSourceUDPv6 );
+       dispatch_source_forget( &me->readSourceTCPv4 );
+       dispatch_source_forget( &me->readSourceTCPv6 );
+       dispatch_source_forget( &me->responseTimer );
+       me->sockUDPv4 = kInvalidSocketRef;
+       me->sockUDPv6 = kInvalidSocketRef;
+       
+       if( me->responseList )
+       {
+               _DNSDelayedResponseFreeList( me->responseList );
+               me->responseList = NULL;
+       }
+       dispatch_async_f( me->queue, me, _DNSServerStop2 );
+}
+
+static void    _DNSServerStop2( void *inContext )
+{
+       DNSServerRef const              me = (DNSServerRef) inContext;
+       
+       if( !me->stopped )
+       {
+               me->stopped = true;
+               if( me->eventHandler ) me->eventHandler( kDNSServerEvent_Stopped, (uintptr_t) me->stopError, me->eventContext );
+               CFRelease( me );
+       }
+       CFRelease( me );
+}
+
+//===========================================================================================================================
+//     _DNSDelayedResponseFree
+//===========================================================================================================================
+
+static void    _DNSDelayedResponseFree( DNSDelayedResponse *inResponse )
+{
+       ForgetMem( &inResponse->msgPtr );
+       free( inResponse );
+}
+
+//===========================================================================================================================
+//     _DNSDelayedResponseFreeList
+//===========================================================================================================================
+
+static void    _DNSDelayedResponseFreeList( DNSDelayedResponse *inList )
+{
+       DNSDelayedResponse *            response;
+       
+       while( ( response = inList ) != NULL )
+       {
+               inList = response->next;
+               _DNSDelayedResponseFree( response );
+       }
+}
+
+//===========================================================================================================================
+//     _DNSServerUDPReadHandler
+//===========================================================================================================================
+
+static OSStatus
+       _DNSServerAnswerQuery(
+               DNSServerRef    inServer,
+               const uint8_t * inQueryPtr,
+               size_t                  inQueryLen,
+               Boolean                 inForTCP,
+               uint8_t **              outResponsePtr,
+               size_t *                outResponseLen );
+
+#define _DNSServerAnswerQueryForUDP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
+       _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, false, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
+
+#define _DNSServerAnswerQueryForTCP( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, IN_RESPONSE_PTR, IN_RESPONSE_LEN ) \
+       _DNSServerAnswerQuery( IN_SERVER, IN_QUERY_PTR, IN_QUERY_LEN, true, IN_RESPONSE_PTR, IN_RESPONSE_LEN )
+
+static OSStatus
+       _DNSServerScheduleDelayedResponse(
+               DNSServerRef                    inServer,
+               const struct sockaddr * inDestAddr,
+               uint8_t *                               inMsgPtr,
+               size_t                                  inMsgLen );
+static void    _DNSServerUDPDelayedSend( void *inContext );
+
+static void    _DNSServerUDPReadHandler( void *inContext )
+{
+       OSStatus                                        err;
+       SocketContext * const           sockCtx         = (SocketContext *) inContext;
+       DNSServerRef const                      me                      = (DNSServerRef) sockCtx->userContext;
+       struct timeval                          now;
+       ssize_t                                         n;
+       sockaddr_ip                                     clientAddr;
+       socklen_t                                       clientAddrLen;
+       uint8_t *                                       responsePtr     = NULL; // malloc'd
+       size_t                                          responseLen;
+       uint8_t                                         msg[ 512 ];
+       
+       gettimeofday( &now, NULL );
+       
+       // Receive message.
+       
+       clientAddrLen = (socklen_t) sizeof( clientAddr );
+       n = recvfrom( sockCtx->sock, (char *) msg, sizeof( msg ), 0, &clientAddr.sa, &clientAddrLen );
+       err = map_socket_value_errno( sockCtx->sock, n >= 0, n );
+       require_noerr( err, exit );
+       
+       ds_ulog( kLogLevelInfo, "UDP server received %zd bytes from %##a at %{du:time}.\n", n, &clientAddr, &now );
+       
+       if( n < kDNSHeaderLength )
+       {
+               ds_ulog( kLogLevelInfo, "UDP DNS message is too small (%zd < %d).\n", n, kDNSHeaderLength );
+               goto exit;
+       }
+       
+       ds_ulog( kLogLevelInfo, "UDP received message:\n\n%1{du:dnsmsg}", msg, (size_t) n );
+       
+       // Create response.
+       
+       err = _DNSServerAnswerQueryForUDP( me, msg, (size_t) n, &responsePtr, &responseLen );
+       require_noerr_quiet( err, exit );
+       
+       // Schedule response.
+       
+       if( me->responseDelayMs > 0 )
+       {
+               err = _DNSServerScheduleDelayedResponse( me, &clientAddr.sa, responsePtr, responseLen );
+               require_noerr( err, exit );
+               responsePtr = NULL;
+       }
+       else
+       {
+               ds_ulog( kLogLevelInfo, "UDP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
+               
+               n = sendto( sockCtx->sock, (char *) responsePtr, responseLen, 0, &clientAddr.sa, clientAddrLen );
+               err = map_socket_value_errno( sockCtx->sock, n == (ssize_t) responseLen, n );
+               require_noerr( err, exit );
+       }
+       
+exit:
+       FreeNullSafe( responsePtr );
+       return;
+}
+
+static OSStatus
+       _DNSServerScheduleDelayedResponse(
+               DNSServerRef                    me,
+               const struct sockaddr * inDestAddr,
+               uint8_t *                               inMsgPtr,
+               size_t                                  inMsgLen )
+{
+       OSStatus                                        err;
+       DNSDelayedResponse *            response;
+       DNSDelayedResponse **           responsePtr;
+       DNSDelayedResponse *            newResponse;
+       uint64_t                                        targetTicks;
+       
+       targetTicks = UpTicks() + MillisecondsToUpTicks( me->responseDelayMs );
+       
+       newResponse = (DNSDelayedResponse *) calloc( 1, sizeof( *newResponse ) );
+       require_action( newResponse, exit, err = kNoMemoryErr );
+       
+       if( !me->responseList || ( targetTicks < me->responseList->targetTicks ) )
+       {
+               dispatch_source_forget( &me->responseTimer );
+               
+               err = DispatchTimerCreate( dispatch_time_milliseconds( me->responseDelayMs ), DISPATCH_TIME_FOREVER,
+                       ( (uint64_t) me->responseDelayMs ) * kNanosecondsPerMillisecond / 10, me->queue, _DNSServerUDPDelayedSend,
+                       NULL, me, &me->responseTimer );
+               require_noerr( err, exit );
+               dispatch_resume( me->responseTimer );
+       }
+       
+       SockAddrCopy( inDestAddr, &newResponse->destAddr );
+       newResponse->targetTicks        = targetTicks;
+       newResponse->msgPtr                     = inMsgPtr;
+       newResponse->msgLen                     = inMsgLen;
+       
+       for( responsePtr = &me->responseList; ( response = *responsePtr ) != NULL; responsePtr = &response->next )
+       {
+               if( newResponse->targetTicks < response->targetTicks ) break;
+       }
+       newResponse->next = response;
+       *responsePtr = newResponse;
+       newResponse = NULL;
+       err = kNoErr;
+       
+exit:
+       if( newResponse ) _DNSDelayedResponseFree( newResponse );
+       return( err );
+}
+
+static void    _DNSServerUDPDelayedSend( void *inContext )
+{
+       OSStatus                                        err;
+       DNSServerRef const                      me                      = (DNSServerRef) inContext;
+       DNSDelayedResponse *            response;
+       SocketRef                                       sock;
+       ssize_t                                         n;
+       uint64_t                                        nowTicks;
+       uint64_t                                        remainingNs;
+       DNSDelayedResponse *            freeList        = NULL;
+       
+       dispatch_source_forget( &me->responseTimer );
+       
+       nowTicks = UpTicks();
+       while( ( ( response = me->responseList ) != NULL ) && ( response->targetTicks <= nowTicks ) )
+       {
+               me->responseList = response->next;
+               
+               ds_ulog( kLogLevelInfo, "UDP sending %zu byte response (delayed):\n\n%1{du:dnsmsg}",
+                       response->msgLen, response->msgPtr, response->msgLen );
+               
+               sock = ( response->destAddr.sa.sa_family == AF_INET ) ? me->sockUDPv4 : me->sockUDPv6;
+               n = sendto( sock, (char *) response->msgPtr, response->msgLen, 0, &response->destAddr.sa,
+                       SockAddrGetSize( &response->destAddr ) );
+               err = map_socket_value_errno( sock, n == (ssize_t) response->msgLen, n );
+               check_noerr( err );
+               
+               response->next  = freeList;
+               freeList                = response;
+               nowTicks = UpTicks();
+       }
+       
+       if( response )
+       {
+               check( response->targetTicks > nowTicks );
+               remainingNs = UpTicksToNanoseconds( response->targetTicks - nowTicks );
+               if( remainingNs > INT64_MAX ) remainingNs = INT64_MAX;
+               
+               err = DispatchTimerCreate( dispatch_time( DISPATCH_TIME_NOW, (int64_t) remainingNs ), DISPATCH_TIME_FOREVER, 0,
+                       me->queue, _DNSServerUDPDelayedSend, NULL, me, &me->responseTimer );
+               require_noerr( err, exit );
+               dispatch_resume( me->responseTimer );
+       }
+       
+exit:
+       if( freeList ) _DNSDelayedResponseFreeList( freeList );
+}
+
+//===========================================================================================================================
+//     _DNSServerAnswerQuery
+//===========================================================================================================================
+
+#define kLabelPrefix_Alias                     "alias"
+#define kLabelPrefix_AliasTTL          "alias-ttl"
+#define kLabelPrefix_Count                     "count-"
+#define kLabelPrefix_Tag                       "tag-"
+#define kLabelPrefix_TTL                       "ttl-"
+#define kLabel_IPv4                                    "ipv4"
+#define kLabel_IPv6                                    "ipv6"
+#define kLabelPrefix_SRV                       "srv-"
+
+#define kMaxAliasTTLCount              ( ( kDomainLabelLengthMax - sizeof_string( kLabelPrefix_AliasTTL ) ) / 2 )
+#define kMaxParsedSRVCount             ( kDomainNameLengthMax / ( 1 + sizeof_string( kLabelPrefix_SRV ) + 5 ) )
+
+typedef struct
+{
+       uint16_t                        priority;       // Priority from SRV label.
+       uint16_t                        weight;         // Weight from SRV label.
+       uint16_t                        port;           // Port number from SRV label.
+       uint16_t                        targetLen;      // Total length of the target hostname labels that follow an SRV label.
+       const uint8_t *         targetPtr;      // Pointer to the target hostname embedded in a domain name.
+       
+}      ParsedSRV;
+
+static OSStatus
+       _DNSServerInitializeResponseMessage(
+               DataBuffer *    inDB,
+               unsigned int    inID,
+               unsigned int    inFlags,
+               const uint8_t * inQName,
+               unsigned int    inQType,
+               unsigned int    inQClass );
+static OSStatus
+       _DNSServerAnswerQueryDynamically(
+               DNSServerRef    inServer,
+               const uint8_t * inQName,
+               unsigned int    inQType,
+               unsigned int    inQClass,
+               Boolean                 inForTCP,
+               DataBuffer *    inDB );
+static Boolean
+       _DNSServerNameIsSRVName(
+               DNSServerRef            inServer,
+               const uint8_t *         inName,
+               const uint8_t **        outDomainPtr,
+               size_t *                        outDomainLen,
+               ParsedSRV                       inSRVArray[ kMaxParsedSRVCount ],
+               size_t *                        outSRVCount );
+static Boolean
+       _DNSServerNameIsHostname(
+               DNSServerRef    inServer,
+               const uint8_t * inName,
+               uint32_t *              outAliasCount,
+               uint32_t                inAliasTTLs[ kMaxAliasTTLCount ],
+               size_t *                outAliasTTLCount,
+               unsigned int *  outCount,
+               unsigned int *  outRandCount,
+               uint32_t *              outTTL,
+               Boolean *               outHasA,
+               Boolean *               outHasAAAA,
+               Boolean *               outHasSOA );
+
+static OSStatus
+       _DNSServerAnswerQuery(
+               DNSServerRef                    me,
+               const uint8_t * const   inQueryPtr,
+               const size_t                    inQueryLen,
+               Boolean                                 inForTCP,
+               uint8_t **                              outResponsePtr,
+               size_t *                                outResponseLen )
+{
+       OSStatus                                                                err;
+       DataBuffer                                                              dataBuf;
+       const uint8_t *                                                 ptr;
+       const uint8_t * const                                   queryEnd = &inQueryPtr[ inQueryLen ];
+       const DNSHeader *                                               qhdr;
+       const dns_fixed_fields_question *               fields;
+       unsigned int                                                    msgID, qflags, qtype, qclass, rflags;
+       uint8_t                                                                 qname[ kDomainNameLengthMax ];
+       
+       DataBuffer_Init( &dataBuf, NULL, 0, kDNSMaxTCPMessageSize );
+       
+       require_action_quiet( inQueryLen >= kDNSHeaderLength, exit, err = kUnderrunErr );
+       
+       qhdr    = (const DNSHeader *) inQueryPtr;
+       msgID   = DNSHeaderGetID( qhdr );
+       qflags  = DNSHeaderGetFlags( qhdr );
+       
+       // Minimal checking of the query message's header.
+       
+       if( ( qflags & kDNSHeaderFlag_Response ) ||                                     // The message must be a query, not a response.
+               ( DNSFlagsGetOpCode( qflags ) != kDNSOpCode_Query ) ||  // OPCODE must be QUERY (standard query).
+               ( DNSHeaderGetQuestionCount( qhdr ) != 1 ) )                    // There should be a single question.
+       {
+               err = kRequestErr;
+               goto exit;
+       }
+       
+       // Get QNAME.
+       
+       ptr = (const uint8_t *) &qhdr[ 1 ];
+       err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, ptr, qname, &ptr );
+       require_noerr( err, exit );
+       
+       // Get QTYPE and QCLASS.
+       
+       require_action_quiet( ( (size_t)( queryEnd - ptr ) ) >= sizeof( *fields ), exit, err = kUnderrunErr );
+       fields  = (const dns_fixed_fields_question *) ptr;
+       qtype   = dns_fixed_fields_question_get_type( fields );
+       qclass  = dns_fixed_fields_question_get_class( fields );
+       
+       // Create a tentative response message.
+       
+       rflags = kDNSHeaderFlag_Response;
+       if( qflags & kDNSHeaderFlag_RecursionDesired ) rflags |= kDNSHeaderFlag_RecursionDesired;
+       DNSFlagsSetOpCode( rflags, kDNSOpCode_Query );
+       
+       if( me->badUDPMode && !inForTCP ) msgID = (uint16_t)( msgID + 1 );
+       err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
+       require_noerr( err, exit );
+       
+       err = _DNSServerAnswerQueryDynamically( me, qname, qtype, qclass, inForTCP, &dataBuf );
+       if( err )
+       {
+               DNSFlagsSetRCode( rflags, kDNSRCode_ServerFailure );
+               err = _DNSServerInitializeResponseMessage( &dataBuf, msgID, rflags, qname, qtype, qclass );
+               require_noerr( err, exit );
+       }
+       
+       err = DataBuffer_Detach( &dataBuf, outResponsePtr, outResponseLen );
+       require_noerr( err, exit );
+       
+exit:
+       DataBuffer_Free( &dataBuf );
+       return( err );
+}
+
+static OSStatus
+       _DNSServerInitializeResponseMessage(
+               DataBuffer *    inDB,
+               unsigned int    inID,
+               unsigned int    inFlags,
+               const uint8_t * inQName,
+               unsigned int    inQType,
+               unsigned int    inQClass )
+{
+       OSStatus                err;
+       DNSHeader               header;
+       
+       DataBuffer_Reset( inDB );
+       
+       memset( &header, 0, sizeof( header ) );
+       DNSHeaderSetID( &header, inID );
+       DNSHeaderSetFlags( &header, inFlags );
+       DNSHeaderSetQuestionCount( &header, 1 );
+       
+       err = DataBuffer_Append( inDB, &header, sizeof( header ) );
+       require_noerr( err, exit );
+       
+       err = _DataBuffer_AppendDNSQuestion( inDB, inQName, DomainNameLength( inQName ), (uint16_t) inQType,
+               (uint16_t) inQClass );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+static OSStatus
+       _DNSServerAnswerQueryDynamically(
+               DNSServerRef                    me,
+               const uint8_t * const   inQName,
+               const unsigned int              inQType,
+               const unsigned int              inQClass,
+               const Boolean                   inForTCP,
+               DataBuffer * const              inDB )
+{
+       OSStatus                                        err;
+       DNSHeader *                                     hdr;
+       unsigned int                            flags, rcode;
+       uint32_t                                        aliasCount, i;
+       uint32_t                                        aliasTTLs[ kMaxAliasTTLCount ];
+       size_t                                          aliasTTLCount;
+       unsigned int                            addrCount, randCount;
+       uint32_t                                        ttl;
+       ParsedSRV                                       srvArray[ kMaxParsedSRVCount ];
+       size_t                                          srvCount;
+       const uint8_t *                         srvDomainPtr;
+       size_t                                          srvDomainLen;
+       unsigned int                            answerCount;
+       Boolean                                         notImplemented, truncated;
+       Boolean                                         useAliasTTLs, nameExists, nameHasA, nameHasAAAA, nameHasSRV, nameHasSOA;
+       uint8_t                                         namePtr[ 2 ];
+       dns_fixed_fields_record         fields;
+       
+       answerCount     = 0;
+       truncated       = false;
+       nameExists      = false;
+       require_action_quiet( inQClass == kDNSServiceClass_IN, done, notImplemented = true );
+       
+       notImplemented  = false;
+       aliasCount              = 0;
+       nameHasA                = false;
+       nameHasAAAA             = false;
+       nameHasSOA              = false;
+       useAliasTTLs    = false;
+       nameHasSRV              = false;
+       srvDomainLen    = 0;
+       srvCount                = 0;
+       
+       if( _DNSServerNameIsHostname( me, inQName, &aliasCount, aliasTTLs, &aliasTTLCount, &addrCount, &randCount, &ttl,
+               &nameHasA, &nameHasAAAA, &nameHasSOA ) )
+       {
+               check( !( ( aliasCount > 0 ) && ( aliasTTLCount > 0 ) ) );
+               check( ( addrCount >= 1 ) && ( addrCount <= 255 ) );
+               check( ( randCount == 0 ) || ( ( randCount >= addrCount ) && ( randCount <= 255 ) ) );
+               check( nameHasA || nameHasAAAA );
+               
+               if( aliasTTLCount > 0 )
+               {
+                       aliasCount              = (uint32_t) aliasTTLCount;
+                       useAliasTTLs    = true;
+               }
+               nameExists = true;
+       }
+       else if( _DNSServerNameIsSRVName( me, inQName, &srvDomainPtr, &srvDomainLen, srvArray, &srvCount ) )
+       {
+               nameHasSRV = true;
+               nameExists = true;
+       }
+       require_quiet( nameExists, done );
+       
+       if( aliasCount > 0 )
+       {
+               size_t                          nameOffset;
+               uint8_t                         rdataLabel[ 1 + kDomainLabelLengthMax + 1 ];
+               
+               // If aliasCount is non-zero, then the first label of QNAME is either "alias" or "alias-<N>". superPtr is a name
+               // compression pointer to the second label of QNAME, i.e., the immediate superdomain name of QNAME. It's used for
+               // the RDATA of CNAME records whose canonical name ends with the superdomain name. It may also be used to construct
+               // CNAME record names, when the offset to the previous CNAME's RDATA doesn't fit in a compression pointer.
+               
+               const uint8_t           superPtr[ 2 ] = { 0xC0, (uint8_t)( kDNSHeaderLength + 1 + inQName[ 0 ] ) };
+               
+               // The name of the first CNAME record is equal to QNAME, so nameOffset is set to offset of QNAME.
+               
+               nameOffset = kDNSHeaderLength;
+               
+               for( i = aliasCount; i >= 1; --i )
+               {
+                       size_t                  nameLen;
+                       size_t                  rdataLen;
+                       uint32_t                j;
+                       uint32_t                aliasTTL;
+                       uint8_t                 nameLabel[ 1 + kDomainLabelLengthMax ];
+                       
+                       if( nameOffset <= kDNSCompressionOffsetMax )
+                       {
+                               DNSMessageWriteLabelPointer( namePtr, nameOffset );
+                               nameLen = sizeof( namePtr );
+                       }
+                       else
+                       {
+                               memcpy( nameLabel, rdataLabel, 1 + rdataLabel[ 0 ] );
+                               nameLen = 1 + nameLabel[ 0 ] + sizeof( superPtr );
+                       }
+                       
+                       if( i >= 2 )
+                       {
+                               char *                          dst = (char *) &rdataLabel[ 1 ];
+                               char * const            lim = (char *) &rdataLabel[ countof( rdataLabel ) ];
+                               
+                               if( useAliasTTLs )
+                               {
+                                       err = SNPrintF_Add( &dst, lim, kLabelPrefix_AliasTTL );
+                                       require_noerr( err, exit );
+                                       
+                                       for( j = aliasCount - ( i - 1 ); j < aliasCount; ++j )
+                                       {
+                                               err = SNPrintF_Add( &dst, lim, "-%u", aliasTTLs[ j ] );
+                                               require_noerr( err, exit );
+                                       }
+                               }
+                               else
+                               {
+                                       err = SNPrintF_Add( &dst, lim, kLabelPrefix_Alias "%?{end}-%u", i == 2, i - 1 );
+                                       require_noerr( err, exit );
+                               }
+                               rdataLabel[ 0 ] = (uint8_t)( dst - (char *) &rdataLabel[ 1 ] );
+                               rdataLen                = 1 + rdataLabel[ 0 ] + sizeof( superPtr );
+                       }
+                       else
+                       {
+                               rdataLen = sizeof( superPtr );
+                       }
+                       
+                       if( !inForTCP )
+                       {
+                               size_t          recordLen = nameLen + sizeof( fields ) + rdataLen;
+                               
+                               if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
+                               {
+                                       truncated = true;
+                                       goto done;
+                               }
+                       }
+                       ++answerCount;
+                       
+                       // Set CNAME record's NAME.
+                       
+                       if( nameOffset <= kDNSCompressionOffsetMax )
+                       {
+                               err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
+                               require_noerr( err, exit );
+                       }
+                       else
+                       {
+                               err = DataBuffer_Append( inDB, nameLabel, 1 + nameLabel[ 0 ] );
+                               require_noerr( err, exit );
+                               
+                               err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
+                               require_noerr( err, exit );
+                       }
+                       
+                       // Set CNAME record's TYPE, CLASS, TTL, and RDLENGTH.
+                       
+                       aliasTTL = useAliasTTLs ? aliasTTLs[ aliasCount - i ] : me->defaultTTL;
+                       dns_fixed_fields_record_init( &fields, kDNSServiceType_CNAME, kDNSServiceClass_IN, aliasTTL,
+                               (uint16_t) rdataLen );
+                       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+                       require_noerr( err, exit );
+                       
+                       // Save offset of CNAME record's RDATA, which may be used for the name of the next CNAME record.
+                       
+                       nameOffset = DataBuffer_GetLen( inDB );
+                       
+                       // Set CNAME record's RDATA.
+                       
+                       if( i >= 2 )
+                       {
+                               err = DataBuffer_Append( inDB, rdataLabel, 1 + rdataLabel[ 0 ] );
+                               require_noerr( err, exit );
+                       }
+                       err = DataBuffer_Append( inDB, superPtr, sizeof( superPtr ) );
+                       require_noerr( err, exit );
+               }
+               
+               namePtr[ 0 ] = superPtr[ 0 ];
+               namePtr[ 1 ] = superPtr[ 1 ];
+       }
+       else
+       {
+               // There are no aliases, so initialize the name compression pointer to point to QNAME.
+               
+               DNSMessageWriteLabelPointer( namePtr, kDNSHeaderLength );
+       }
+       
+       if( ( inQType == kDNSServiceType_A ) || ( inQType == kDNSServiceType_AAAA ) )
+       {
+               uint8_t *               lsb;                                    // Pointer to the least significant byte of record data.
+               size_t                  recordLen;                              // Length of the entire record.
+               size_t                  rdataLen;                               // Length of record's RDATA.
+               uint8_t                 rdata[ 16 ];                    // A buffer that's big enough for either A or AAAA RDATA.
+               uint8_t                 randIntegers[ 255 ];    // Array for random integers in [1, 255].
+               const int               useBadAddrs = ( me->badUDPMode && !inForTCP ) ? true : false;
+               
+               if( inQType == kDNSServiceType_A )
+               {
+                       const uint32_t          baseAddrV4 = useBadAddrs ? kDNSServerBadBaseAddrV4 : kDNSServerBaseAddrV4;
+                       
+                       require_quiet( nameHasA, done );
+                       
+                       rdataLen = 4;
+                       WriteBig32( rdata, baseAddrV4 );
+                       lsb = &rdata[ 3 ];
+               }
+               else
+               {
+                       const uint8_t * const           baseAddrV6 = useBadAddrs ? kDNSServerBadBaseAddrV6 : kDNSServerBaseAddrV6;
+                       
+                       require_quiet( nameHasAAAA, done );
+                       
+                       rdataLen = 16;
+                       memcpy( rdata, baseAddrV6, 16 );
+                       lsb = &rdata[ 15 ];
+               }
+               
+               if( randCount > 0 )
+               {
+                       // Populate the array with all integers between 1 and <randCount>, inclusive.
+                       
+                       for( i = 0; i < randCount; ++i ) randIntegers[ i ] = (uint8_t)( i + 1 );
+                       
+                       // Prevent dubious static analyzer warning.
+                       // Note: _DNSServerNameIsHostname() already enforces randCount >= addrCount. Also, this require_fatal() check
+                       // needs to be placed right before the next for-loop. Any earlier, and the static analyzer warning will persist
+                       // for some reason.
+                       
+                       require_fatal( addrCount <= randCount, "Invalid Count label values: addrCount %u > randCount %u",
+                               addrCount, randCount );
+                       
+                       // Create a contiguous subarray starting at index 0 that contains <addrCount> randomly chosen integers between
+                       // 1 and <randCount>, inclusive.
+                       // Loop invariant 1: Array elements with indexes in [0, i - 1] have been randomly chosen.
+                       // Loop invariant 2: Array elements with indexes in [i, randCount - 1] are candidates for being chosen.
+                       
+                       for( i = 0; i < addrCount; ++i )
+                       {
+                               uint8_t                 tmp;
+                               uint32_t                j;
+                               
+                               j = RandomRange( i, randCount - 1 );
+                               if( i != j )
+                               {
+                                       tmp = randIntegers[ i ];
+                                       randIntegers[ i ] = randIntegers[ j ];
+                                       randIntegers[ j ] = tmp;
+                               }
+                       }
+               }
+               
+               recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
+               for( i = 0; i < addrCount; ++i )
+               {
+                       if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
+                       {
+                               truncated = true;
+                               goto done;
+                       }
+                       
+                       // Set record NAME.
+                       
+                       err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
+                       require_noerr( err, exit );
+                       
+                       // Set record TYPE, CLASS, TTL, and RDLENGTH.
+                       
+                       dns_fixed_fields_record_init( &fields, (uint16_t) inQType, kDNSServiceClass_IN, ttl, (uint16_t) rdataLen );
+                       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+                       require_noerr( err, exit );
+                       
+                       // Set record RDATA.
+                       
+                       *lsb = ( randCount > 0 ) ? randIntegers[ i ] : ( *lsb + 1 );
+                       
+                       err = DataBuffer_Append( inDB, rdata, rdataLen );
+                       require_noerr( err, exit );
+                       
+                       ++answerCount;
+               }
+       }
+       else if( inQType == kDNSServiceType_SRV )
+       {
+               require_quiet( nameHasSRV, done );
+               
+               dns_fixed_fields_record_init( &fields, kDNSServiceType_SRV, kDNSServiceClass_IN, me->defaultTTL, 0 );
+               
+               for( i = 0; i < srvCount; ++i )
+               {
+                       dns_fixed_fields_srv            fieldsSRV;
+                       size_t                                          rdataLen;
+                       size_t                                          recordLen;
+                       const ParsedSRV * const         srv = &srvArray[ i ];
+                       
+                       rdataLen  = sizeof( fieldsSRV ) + srvDomainLen + srv->targetLen + 1;
+                       recordLen = sizeof( namePtr ) + sizeof( fields ) + rdataLen;
+                       
+                       if( !inForTCP && ( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize ) )
+                       {
+                               truncated = true;
+                               goto done;
+                       }
+                       
+                       // Append record NAME.
+                       
+                       err = DataBuffer_Append( inDB, namePtr, sizeof( namePtr ) );
+                       require_noerr( err, exit );
+                       
+                       // Append record TYPE, CLASS, TTL, and RDLENGTH.
+                       
+                       WriteBig16( fields.rdlength, rdataLen );
+                       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+                       require_noerr( err, exit );
+                       
+                       // Append SRV RDATA.
+                       
+                       dns_fixed_fields_srv_init( &fieldsSRV, srv->priority, srv->weight, srv->port );
+                       
+                       err = DataBuffer_Append( inDB, &fieldsSRV, sizeof( fieldsSRV ) );
+                       require_noerr( err, exit );
+                       
+                       if( srv->targetLen > 0 )
+                       {
+                               err = DataBuffer_Append( inDB, srv->targetPtr, srv->targetLen );
+                               require_noerr( err, exit );
+                       }
+                       
+                       if( srvDomainLen > 0 )
+                       {
+                               err = DataBuffer_Append( inDB, srvDomainPtr, srvDomainLen );
+                               require_noerr( err, exit );
+                       }
+                       
+                       err = DataBuffer_Append( inDB, "", 1 ); // Append root label.
+                       require_noerr( err, exit );
+                       
+                       ++answerCount;
+               }
+       }
+       else if( inQType == kDNSServiceType_SOA )
+       {
+               size_t          nameLen, recordLen;
+               
+               require_quiet( nameHasSOA, done );
+               
+               nameLen = DomainNameLength( me->domain );
+               if( !inForTCP )
+               {
+                       err = AppendSOARecord( NULL, me->domain, nameLen, 0, 0, 0, kRootLabel, kRootLabel, 0, 0, 0, 0, 0, &recordLen );
+                       require_noerr( err, exit );
+                       
+                       if( ( DataBuffer_GetLen( inDB ) + recordLen ) > kDNSMaxUDPMessageSize )
+                       {
+                               truncated = true;
+                               goto done;
+                       }
+               }
+               
+               err = AppendSOARecord( inDB, me->domain, nameLen, kDNSServiceType_SOA, kDNSServiceClass_IN, me->defaultTTL,
+                       kRootLabel, kRootLabel, me->serial, 1 * kSecondsPerDay, 2 * kSecondsPerHour, 1000 * kSecondsPerHour,
+                       me->defaultTTL, NULL );
+               require_noerr( err, exit );
+               
+               ++answerCount;
+       }
+       
+done:
+       hdr = (DNSHeader *) DataBuffer_GetPtr( inDB );
+       flags = DNSHeaderGetFlags( hdr );
+       if( notImplemented )
+       {
+               rcode = kDNSRCode_NotImplemented;
+       }
+       else
+       {
+               flags |= kDNSHeaderFlag_AuthAnswer;
+               if( truncated ) flags |= kDNSHeaderFlag_Truncation;
+               rcode = nameExists ? kDNSRCode_NoError : kDNSRCode_NXDomain;
+       }
+       DNSFlagsSetRCode( flags, rcode );
+       DNSHeaderSetFlags( hdr, flags );
+       DNSHeaderSetAnswerCount( hdr, answerCount );
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+static Boolean
+       _DNSServerNameIsHostname(
+               DNSServerRef    me,
+               const uint8_t * inName,
+               uint32_t *              outAliasCount,
+               uint32_t                inAliasTTLs[ kMaxAliasTTLCount ],
+               size_t *                outAliasTTLCount,
+               unsigned int *  outCount,
+               unsigned int *  outRandCount,
+               uint32_t *              outTTL,
+               Boolean *               outHasA,
+               Boolean *               outHasAAAA,
+               Boolean *               outHasSOA )
+{
+       OSStatus                        err;
+       const uint8_t *         label;
+    const uint8_t *            nextLabel;
+       uint32_t                        aliasCount              = 0;    // Arg from Alias label. Valid values are in [2, 2^31 - 1].
+       unsigned int            count                   = 0;    // First arg from Count label. Valid values are in [1, 255].
+       unsigned int            randCount               = 0;    // Second arg from Count label. Valid values are in [count, 255].
+       int32_t                         ttl                             = -1;   // Arg from TTL label. Valid values are in [0, 2^31 - 1].
+       size_t                          aliasTTLCount   = 0;    // Count of TTL args from Alias-TTL label.
+       int                                     hasTagLabel             = false;
+       int                                     hasIPv4Label    = false;
+       int                                     hasIPv6Label    = false;
+       int                                     isNameValid             = false;
+       
+       for( label = inName; label[ 0 ]; label = nextLabel )
+       {
+               uint32_t                arg;
+               
+               nextLabel = &label[ 1 + label[ 0 ] ];
+               
+               // Check if the first label is a valid alias TTL sequence label.
+               
+               if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_AliasTTL ) == 0 ) )
+               {
+                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_AliasTTL ) ];
+                       const char * const              end = (const char *) nextLabel;
+                       const char *                    next;
+                       
+                       check( label[ 0 ] <= kDomainLabelLengthMax );
+                       
+                       while( ptr < end )
+                       {
+                               if( *ptr != '-' ) break;
+                               ++ptr;
+                               err = DecimalTextToUInt32( ptr, end, &arg, &next );
+                               if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
+                               inAliasTTLs[ aliasTTLCount++ ] = arg;
+                               ptr = next;
+                       }
+                       if( ( aliasTTLCount == 0 ) || ( ptr != end ) ) break;
+               }
+               
+               // Check if the first label is a valid alias label.
+               
+               else if( ( label == inName ) && ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Alias ) == 0 ) )
+               {
+                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Alias ) ];
+                       const char * const              end = (const char *) nextLabel;
+                       
+                       if( ptr < end )
+                       {
+                               if( *ptr++ != '-' ) break;
+                               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+                               if( err || ( arg < 2 ) || ( arg > INT32_MAX ) ) break;  // Alias count must be in [2, 2^31 - 1].
+                               aliasCount = arg;
+                               if( ptr != end ) break;
+                       }
+                       else
+                       {
+                               aliasCount = 1;
+                       }
+               }
+               
+               // Check if this label is a valid count label.
+               
+               else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Count ) == 0  )
+               {
+                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_Count ) ];
+                       const char * const              end = (const char *) nextLabel;
+                       
+                       if( count > 0 ) break;  // Count cannot be specified more than once.
+                       
+                       err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+                       if( err || ( arg < 1 ) || ( arg > 255 ) ) break;        // Count must be in [1, 255].
+                       count = (unsigned int) arg;
+                       
+                       if( ptr < end )
+                       {
+                               if( *ptr++ != '-' ) break;
+                               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+                               if( err || ( arg < (uint32_t) count ) || ( arg > 255 ) ) break; // Rand count must be in [count, 255].
+                               randCount = (unsigned int) arg;
+                               if( ptr != end ) break;
+                       }
+               }
+               
+               // Check if this label is a valid TTL label.
+               
+               else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_TTL ) == 0  )
+               {
+                       const char *                    ptr = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_TTL ) ];
+                       const char * const              end = (const char *) nextLabel;
+                       
+                       if( ttl >= 0 ) break;   // TTL cannot be specified more than once.
+                       
+                       err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+                       if( err || ( arg > INT32_MAX ) ) break; // TTL must be in [0, 2^31 - 1].
+                       ttl = (int32_t) arg;
+                       if( ptr != end ) break;
+               }
+               
+               // Check if this label is a valid IPv4 label.
+               
+               else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv4 ) == 0 )
+               {
+                       if( hasIPv4Label || hasIPv6Label ) break;       // Valid names have at most one IPv4 or IPv6 label.
+                       hasIPv4Label = true;
+               }
+               
+               // Check if this label is a valid IPv6 label.
+               
+               else if( strnicmpx( &label[ 1 ], label[ 0 ], kLabel_IPv6 ) == 0 )
+               {
+                       if( hasIPv4Label || hasIPv6Label ) break;       // Valid names have at most one IPv4 or IPv6 label.
+                       hasIPv6Label = true;
+               }
+               
+               // Check if this label is a valid tag label.
+               
+               else if( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_Tag ) == 0  )
+               {
+                       hasTagLabel = true;
+               }
+               
+               // If this and the remaining labels are equal to "d.test.", then the name exists. Otherwise, this label is invalid.
+               // In both cases, there are no more labels to check.
+               
+               else
+               {
+                       if( DomainNameEqual( label, me->domain ) ) isNameValid = true;
+                       break;
+               }
+       }
+       require_quiet( isNameValid, exit );
+       
+       if( outAliasCount )             *outAliasCount          = aliasCount;
+       if( outAliasTTLCount )  *outAliasTTLCount       = aliasTTLCount;
+       if( outCount )                  *outCount                       = ( count > 0 ) ? count : 1;
+       if( outRandCount )              *outRandCount           = randCount;
+       if( outTTL )                    *outTTL                         = ( ttl >= 0 ) ? ( (uint32_t) ttl ) : me->defaultTTL;
+       if( outHasA )                   *outHasA                        = ( hasIPv4Label || !hasIPv6Label ) ? true : false;
+       if( outHasAAAA )                *outHasAAAA                     = ( hasIPv6Label || !hasIPv4Label ) ? true : false;
+       if( outHasSOA )
+       {
+               *outHasSOA = ( !count && ( ttl < 0 ) && !hasIPv4Label && !hasIPv6Label && !hasTagLabel ) ? true : false;
+       }
+       
+exit:
+       return( isNameValid ? true : false );
+}
+
+static Boolean
+       _DNSServerNameIsSRVName(
+               DNSServerRef            me,
+               const uint8_t *         inName,
+               const uint8_t **        outDomainPtr,
+               size_t *                        outDomainLen,
+               ParsedSRV                       inSRVArray[ kMaxParsedSRVCount ],
+               size_t *                        outSRVCount )
+{
+       OSStatus                        err;
+       const uint8_t *         label;
+       const uint8_t *         domainPtr;
+       size_t                          domainLen;
+       size_t                          srvCount;
+       uint32_t                        arg;
+       int                                     isNameValid = false;
+       
+       label = inName;
+       
+       // Ensure that first label, i.e, the service label, begins with a '_' character.
+       
+       require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
+       label = DomainNameGetNextLabel( label );
+       
+       // Ensure that the second label, i.e., the proto label, begins with a '_' character (usually _tcp or _udp).
+       
+       require_quiet( ( label[ 0 ] > 0 ) && ( label[ 1 ] == '_' ), exit );
+       label = DomainNameGetNextLabel( label );
+       
+       // Parse the domain name, if any.
+       
+       domainPtr = label;
+       while( *label )
+       {
+               if( DomainNameEqual( label, me->domain ) ||
+                       ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
+               label = DomainNameGetNextLabel( label );
+       }
+       require_quiet( *label, exit );
+       
+       domainLen = (size_t)( label - domainPtr );
+       
+       // Parse SRV labels, if any.
+       
+       srvCount = 0;
+       while( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 )
+       {
+               const uint8_t * const   nextLabel       = DomainNameGetNextLabel( label );
+               const char *                    ptr                     = (const char *) &label[ 1 + sizeof_string( kLabelPrefix_SRV ) ];
+               const char * const              end                     = (const char *) nextLabel;
+               const uint8_t *                 target;
+               unsigned int                    priority, weight, port;
+               
+               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+               require_quiet( !err && ( arg <= UINT16_MAX ), exit );
+               priority = (unsigned int) arg;
+               
+               require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+               ++ptr;
+               
+               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+               require_quiet( !err && ( arg <= UINT16_MAX ), exit );
+               weight = (unsigned int) arg;
+               
+               require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+               ++ptr;
+               
+               err = DecimalTextToUInt32( ptr, end, &arg, &ptr );
+               require_quiet( !err && ( arg <= UINT16_MAX ), exit );
+               port = (unsigned int) arg;
+               
+               require_quiet( ptr == end, exit );
+               
+               target = nextLabel;
+               for( label = nextLabel; *label; label = DomainNameGetNextLabel( label ) )
+               {
+                       if( DomainNameEqual( label, me->domain ) ||
+                               ( strnicmp_prefix( &label[ 1 ], label[ 0 ], kLabelPrefix_SRV ) == 0 ) ) break;
+               }
+               require_quiet( *label, exit );
+               
+               if( inSRVArray )
+               {
+                       inSRVArray[ srvCount ].priority         = (uint16_t) priority;
+                       inSRVArray[ srvCount ].weight           = (uint16_t) weight;
+                       inSRVArray[ srvCount ].port                     = (uint16_t) port;
+                       inSRVArray[ srvCount ].targetPtr        = target;
+                       inSRVArray[ srvCount ].targetLen        = (uint16_t)( label - target );
+               }
+               ++srvCount;
+       }
+       require_quiet( DomainNameEqual( label, me->domain ), exit );
+       isNameValid = true;
+       
+       if( outDomainPtr )      *outDomainPtr   = domainPtr;
+       if( outDomainLen )      *outDomainLen   = domainLen;
+       if( outSRVCount )       *outSRVCount    = srvCount;
+       
+exit:
+       return( isNameValid ? true : false );
+}
+
+//===========================================================================================================================
+//     _DNSServerTCPReadHandler
+//===========================================================================================================================
+
+typedef struct
+{
+       DNSServerRef                    server;                 // Reference to DNS server object.
+       sockaddr_ip                             clientAddr;             // Client's address.
+       dispatch_source_t               readSource;             // Dispatch read source for client socket.
+       dispatch_source_t               writeSource;    // Dispatch write source for client socket.
+       size_t                                  offset;                 // Offset into receive buffer.
+       void *                                  msgPtr;                 // Pointer to dynamically allocated message buffer.
+       size_t                                  msgLen;                 // Length of message buffer.
+       Boolean                                 readSuspended;  // True if the read source is currently suspended.
+       Boolean                                 writeSuspended; // True if the write source is currently suspended.
+       Boolean                                 receivedLength; // True if receiving DNS message as opposed to the message length.
+       uint8_t                                 lenBuf[ 2 ];    // Buffer for two-octet message length field.
+       iovec_t                                 iov[ 2 ];               // IO vector for writing response message.
+       iovec_t *                               iovPtr;                 // Vector pointer for SocketWriteData().
+       int                                             iovCount;               // Vector count for SocketWriteData().
+       
+}      TCPConnectionContext;
+
+static void    TCPConnectionStop( TCPConnectionContext *inContext );
+static void    TCPConnectionContextFree( TCPConnectionContext *inContext );
+static void    TCPConnectionReadHandler( void *inContext );
+static void    TCPConnectionWriteHandler( void *inContext );
+
+#define        TCPConnectionForget( X )                ForgetCustomEx( X, TCPConnectionStop, TCPConnectionContextFree )
+
+static void    _DNSServerTCPReadHandler( void *inContext )
+{
+       OSStatus                                        err;
+       SocketContext * const           sockCtx         = (SocketContext *) inContext;
+       DNSServerRef const                      me                      = (DNSServerRef) sockCtx->userContext;
+       TCPConnectionContext *          connection;
+       socklen_t                                       clientAddrLen;
+       SocketRef                                       newSock         = kInvalidSocketRef;
+       SocketContext *                         newSockCtx      = NULL;
+       
+       connection = (TCPConnectionContext *) calloc( 1, sizeof( *connection ) );
+       require_action( connection, exit, err = kNoMemoryErr );
+       
+       CFRetain( me );
+       connection->server = me;
+       
+       clientAddrLen = (socklen_t) sizeof( connection->clientAddr );
+       newSock = accept( sockCtx->sock, &connection->clientAddr.sa, &clientAddrLen );
+       err = map_socket_creation_errno( newSock );
+       require_noerr( err, exit );
+       
+       err = SocketContextCreate( newSock, connection, &newSockCtx );
+       require_noerr( err, exit );
+       newSock = kInvalidSocketRef;
+       
+       err = DispatchReadSourceCreate( newSockCtx->sock, me->queue, TCPConnectionReadHandler, SocketContextCancelHandler,
+               newSockCtx, &connection->readSource );
+       require_noerr( err, exit );
+       SocketContextRetain( newSockCtx );
+       dispatch_resume( connection->readSource );
+       
+       err = DispatchWriteSourceCreate( newSockCtx->sock, me->queue, TCPConnectionWriteHandler, SocketContextCancelHandler,
+               newSockCtx, &connection->writeSource );
+       require_noerr( err, exit );
+       SocketContextRetain( newSockCtx );
+       connection->writeSuspended = true;
+       connection = NULL;
+       
+exit:
+       ForgetSocket( &newSock );
+       SocketContextRelease( newSockCtx );
+       TCPConnectionForget( &connection );
+}
+
+//===========================================================================================================================
+//     TCPConnectionStop
+//===========================================================================================================================
+
+static void    TCPConnectionStop( TCPConnectionContext *inContext )
+{
+       dispatch_source_forget_ex( &inContext->readSource, &inContext->readSuspended );
+       dispatch_source_forget_ex( &inContext->writeSource, &inContext->writeSuspended );
+}
+
+//===========================================================================================================================
+//     TCPConnectionContextFree
+//===========================================================================================================================
+
+static void    TCPConnectionContextFree( TCPConnectionContext *inContext )
+{
+       check( !inContext->readSource );
+       check( !inContext->writeSource );
+       ForgetCF( &inContext->server );
+       ForgetMem( &inContext->msgPtr );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     TCPConnectionReadHandler
+//===========================================================================================================================
+
+static void    TCPConnectionReadHandler( void *inContext )
+{
+       OSStatus                                        err;
+       SocketContext * const           sockCtx         = (SocketContext *) inContext;
+       TCPConnectionContext *          connection      = (TCPConnectionContext *) sockCtx->userContext;
+       struct timeval                          now;
+       uint8_t *                                       responsePtr     = NULL; // malloc'd
+       size_t                                          responseLen;
+       
+       // Receive message length.
+       
+       if( !connection->receivedLength )
+       {
+               err = SocketReadData( sockCtx->sock, connection->lenBuf, sizeof( connection->lenBuf ), &connection->offset );
+               if( err == EWOULDBLOCK ) goto exit;
+               require_noerr( err, exit );
+               
+               connection->offset = 0;
+               connection->msgLen = ReadBig16( connection->lenBuf );
+               connection->msgPtr = malloc( connection->msgLen );
+               require_action( connection->msgPtr, exit, err = kNoMemoryErr );
+               connection->receivedLength = true;
+       }
+       
+       // Receive message.
+       
+       err = SocketReadData( sockCtx->sock, connection->msgPtr, connection->msgLen, &connection->offset );
+       if( err == EWOULDBLOCK ) goto exit;
+       require_noerr( err, exit );
+       
+       gettimeofday( &now, NULL );
+       dispatch_suspend( connection->readSource );
+       connection->readSuspended = true;
+       
+       ds_ulog( kLogLevelInfo, "TCP server received %zu bytes from %##a at %{du:time}.\n",
+               connection->msgLen, &connection->clientAddr, &now );
+       
+       if( connection->msgLen < kDNSHeaderLength )
+       {
+               ds_ulog( kLogLevelInfo, "TCP DNS message is too small (%zu < %d).\n", connection->msgLen, kDNSHeaderLength );
+               goto exit;
+       }
+       
+       ds_ulog( kLogLevelInfo, "TCP received message:\n\n%1{du:dnsmsg}", connection->msgPtr, connection->msgLen );
+       
+       // Create response.
+       
+       err = _DNSServerAnswerQueryForTCP( connection->server, connection->msgPtr, connection->msgLen, &responsePtr,
+               &responseLen );
+       require_noerr_quiet( err, exit );
+       
+       // Send response.
+       
+       ds_ulog( kLogLevelInfo, "TCP sending %zu byte response:\n\n%1{du:dnsmsg}", responseLen, responsePtr, responseLen );
+       
+       free( connection->msgPtr );
+       connection->msgPtr = responsePtr;
+       connection->msgLen = responseLen;
+       responsePtr = NULL;
+       
+       check( connection->msgLen <= UINT16_MAX );
+       WriteBig16( connection->lenBuf, connection->msgLen );
+       connection->iov[ 0 ].iov_base   = connection->lenBuf;
+       connection->iov[ 0 ].iov_len    = sizeof( connection->lenBuf );
+       connection->iov[ 1 ].iov_base   = connection->msgPtr;
+       connection->iov[ 1 ].iov_len    = connection->msgLen;
+       
+       connection->iovPtr              = connection->iov;
+       connection->iovCount    = 2;
+       
+       check( connection->writeSuspended );
+       dispatch_resume( connection->writeSource );
+       connection->writeSuspended = false;
+       
+exit:
+       FreeNullSafe( responsePtr );
+       if( err && ( err != EWOULDBLOCK ) ) TCPConnectionForget( &connection );
+}
+
+//===========================================================================================================================
+//     TCPConnectionWriteHandler
+//===========================================================================================================================
+
+static void    TCPConnectionWriteHandler( void *inContext )
+{
+       OSStatus                                        err;
+       SocketContext * const           sockCtx         = (SocketContext *) inContext;
+       TCPConnectionContext *          connection      = (TCPConnectionContext *) sockCtx->userContext;
+       
+       err = SocketWriteData( sockCtx->sock, &connection->iovPtr, &connection->iovCount );
+       if( err == EWOULDBLOCK ) goto exit;
+       check_noerr( err );
+       
+       TCPConnectionForget( &connection );
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     MDNSReplierCmd
+//===========================================================================================================================
+
+typedef struct
+{
+       uint8_t *                               hostname;                       // Used as the base name for hostnames and service names.
+       uint8_t *                               serviceLabel;           // Label containing the base service name.
+       unsigned int                    maxInstanceCount;       // Maximum number of service instances and hostnames.
+       uint64_t *                              bitmaps;                        // Array of 64-bit bitmaps for keeping track of needed responses.
+       size_t                                  bitmapCount;            // Number of 64-bit bitmaps.
+       dispatch_source_t               readSourceV4;           // Read dispatch source for IPv4 socket.
+       dispatch_source_t               readSourceV6;           // Read dispatch source for IPv6 socket.
+       uint32_t                                ifIndex;                        // Index of the interface to run on.
+       unsigned int                    recordCountA;           // Number of A records per hostname.
+       unsigned int                    recordCountAAAA;        // Number of AAAA records per hostname.
+       unsigned int                    maxDropCount;           // If > 0, the drop rates apply to only the first <maxDropCount> responses.
+       double                                  ucastDropRate;          // Probability of dropping a unicast response.
+       double                                  mcastDropRate;          // Probability of dropping a multicast query or response.
+       uint8_t *                               dropCounters;           // If maxDropCount > 0, array of <maxInstanceCount> response drop counters.
+       Boolean                                 noAdditionals;          // True if responses are to not include additional records.
+       Boolean                                 useIPv4;                        // True if the replier is to use IPv4.
+       Boolean                                 useIPv6;                        // True if the replier is to use IPv6.
+       uint8_t                                 msgBuf[ kMDNSMessageSizeMax ];  // Buffer for received mDNS message.
+#if( TARGET_OS_DARWIN )
+       dispatch_source_t               processMonitor;         // Process monitor source for process being followed, if any.
+       pid_t                                   followPID;                      // PID of process being followed, if any. (If it exits, we exit).
+#endif
+       
+}      MDNSReplierContext;
+
+typedef struct MRResourceRecord                MRResourceRecord;
+struct MRResourceRecord
+{
+       MRResourceRecord *              next;           // Next item in list.
+       uint8_t *                               name;           // Resource record name.
+       uint16_t                                type;           // Resource record type.
+       uint16_t                                class;          // Resource record class.
+       uint32_t                                ttl;            // Resource record TTL.
+       uint16_t                                rdlength;       // Resource record data length.
+       uint8_t *                               rdata;          // Resource record data.
+       const uint8_t *                 target;         // For SRV records, pointer to target in RDATA.
+};
+
+typedef struct MRNameOffsetItem                MRNameOffsetItem;
+struct MRNameOffsetItem
+{
+       MRNameOffsetItem *      next;           // Next item in list.
+       uint16_t                        offset;         // Offset of domain name in response message.
+       uint8_t                         name[ 1 ];      // Variable-length array for domain name.
+};
+
+#if( TARGET_OS_DARWIN )
+static void            _MDNSReplierFollowedProcessHandler( void *inContext );
+#endif
+static void            _MDNSReplierReadHandler( void *inContext );
+static OSStatus
+       _MDNSReplierAnswerQuery(
+               MDNSReplierContext *    inContext,
+               const uint8_t *                 inQueryPtr,
+               size_t                                  inQueryLen,
+               sockaddr_ip *                   inSender,
+               SocketRef                               inSock,
+               unsigned int                    inIndex );
+static OSStatus
+       _MDNSReplierAnswerListAdd(
+               MDNSReplierContext *    inContext,
+               MRResourceRecord **             inAnswerList,
+               unsigned int                    inIndex,
+               const uint8_t *                 inName,
+               unsigned int                    inType,
+               unsigned int                    inClass );
+static void
+       _MDNSReplierAnswerListRemovePTR(
+               MRResourceRecord **     inAnswerListPtr,
+               const uint8_t *         inName,
+               const uint8_t *         inRData );
+static OSStatus
+       _MDNSReplierSendOrDropResponse(
+               MDNSReplierContext *    inContext,
+               MRResourceRecord *              inAnswerList,
+               sockaddr_ip *                   inQuerier,
+               SocketRef                               inSock,
+               unsigned int                    inIndex,
+               Boolean                                 inUnicast );
+static OSStatus
+       _MDNSReplierCreateResponse(
+               MDNSReplierContext *    inContext,
+               MRResourceRecord *              inAnswerList,
+               unsigned int                    inIndex,
+               uint8_t **                              outResponsePtr,
+               size_t *                                outResponseLen );
+static OSStatus
+       _MDNSReplierAppendNameToResponse(
+               DataBuffer *            inResponse,
+               const uint8_t *         inName,
+               MRNameOffsetItem **     inNameOffsetListPtr );
+static Boolean
+       _MDNSReplierServiceTypeMatch(
+               const MDNSReplierContext *      inContext,
+               const uint8_t *                         inName,
+               unsigned int *                          outTXTSize,
+               unsigned int *                          outCount );
+static Boolean
+       _MDNSReplierServiceInstanceNameMatch(
+               const MDNSReplierContext *      inContext,
+               const uint8_t *                         inName,
+               unsigned int *                          outIndex,
+               unsigned int *                          outTXTSize,
+               unsigned int *                          outCount );
+static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName );
+static Boolean
+       _MDNSReplierHostnameMatch(
+               const MDNSReplierContext *      inContext,
+               const uint8_t *                         inName,
+               unsigned int *                          outIndex );
+static OSStatus        _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT );
+static OSStatus
+       _MRResourceRecordCreate(
+               uint8_t *                       inName,
+               uint16_t                        inType,
+               uint16_t                        inClass,
+               uint32_t                        inTTL,
+               uint16_t                        inRDLength,
+               uint8_t *                       inRData,
+               MRResourceRecord **     outRecord );
+static void            _MRResourceRecordFree( MRResourceRecord *inRecord );
+static void            _MRResourceRecordFreeList( MRResourceRecord *inList );
+static OSStatus        _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem );
+static void            _MRNameOffsetItemFree( MRNameOffsetItem *inItem );
+static void            _MRNameOffsetItemFreeList( MRNameOffsetItem *inList );
+
+ulog_define_ex( kDNSSDUtilIdentifier, MDNSReplier, kLogLevelInfo, kLogFlags_None, "MDNSReplier", NULL );
+#define mr_ulog( LEVEL, ... )          ulog( &log_category_from_name( MDNSReplier ), (LEVEL), __VA_ARGS__ )
+
+static void    MDNSReplierCmd( void )
+{
+       OSStatus                                        err;
+       MDNSReplierContext *            context;
+       SocketRef                                       sockV4  = kInvalidSocketRef;
+       SocketRef                                       sockV6  = kInvalidSocketRef;
+       const char *                            ifname;
+       size_t                                          len;
+       uint8_t                                         name[ 1 + kDomainLabelLengthMax + 1 ];
+       char                                            ifnameBuf[ IF_NAMESIZE + 1 ];
+       
+       err = CheckIntegerArgument( gMDNSReplier_MaxInstanceCount, "max instance count", 1, UINT16_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSReplier_RecordCountA, "A record count", 0, 255 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSReplier_RecordCountAAAA, "AAAA record count", 0, 255 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckDoubleArgument( gMDNSReplier_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckDoubleArgument( gMDNSReplier_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSReplier_MaxDropCount, "drop count", 0, 255 );
+       require_noerr_quiet( err, exit );
+       
+       if( gMDNSReplier_Foreground )
+       {
+               LogControl( "MDNSReplier:output=file;stdout,MDNSReplier:flags=time;prefix" );
+       }
+       
+       context = (MDNSReplierContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->maxInstanceCount       = (unsigned int) gMDNSReplier_MaxInstanceCount;
+       context->recordCountA           = (unsigned int) gMDNSReplier_RecordCountA;
+       context->recordCountAAAA        = (unsigned int) gMDNSReplier_RecordCountAAAA;
+       context->maxDropCount           = (unsigned int) gMDNSReplier_MaxDropCount;
+       context->ucastDropRate          = gMDNSReplier_UnicastDropRate;
+       context->mcastDropRate          = gMDNSReplier_MulticastDropRate;
+       context->noAdditionals          = gMDNSReplier_NoAdditionals ? true : false;
+       context->useIPv4                        = ( gMDNSReplier_UseIPv4 || !gMDNSReplier_UseIPv6 ) ? true : false;
+       context->useIPv6                        = ( gMDNSReplier_UseIPv6 || !gMDNSReplier_UseIPv4 ) ? true : false;
+       context->bitmapCount            = ( context->maxInstanceCount + 63 ) / 64;
+       
+#if( TARGET_OS_DARWIN )
+       if( gMDNSReplier_FollowPID )
+       {
+               context->followPID = _StringToPID( gMDNSReplier_FollowPID, &err );
+               if( err || ( context->followPID < 0 ) )
+               {
+                       FPrintF( stderr, "error: Invalid follow PID: %s\n", gMDNSReplier_FollowPID );
+                       goto exit;
+               }
+               
+               err = DispatchProcessMonitorCreate( context->followPID, DISPATCH_PROC_EXIT, dispatch_get_main_queue(),
+                       _MDNSReplierFollowedProcessHandler, NULL, context, &context->processMonitor );
+               require_noerr( err, exit );
+               dispatch_resume( context->processMonitor );
+       }
+       else
+       {
+               context->followPID = -1;
+       }
+#endif
+       
+       if( context->maxDropCount > 0 )
+       {
+               context->dropCounters = (uint8_t *) calloc( context->maxInstanceCount, sizeof( *context->dropCounters ) );
+               require_action( context->dropCounters, exit, err = kNoMemoryErr );
+       }
+       
+       context->bitmaps = (uint64_t *) calloc( context->bitmapCount, sizeof( *context->bitmaps ) );
+       require_action( context->bitmaps, exit, err = kNoMemoryErr );
+       
+       // Create the base hostname label.
+       
+       len = strlen( gMDNSReplier_Hostname );
+       if( context->maxInstanceCount > 1 )
+       {
+               unsigned int            maxInstanceCount, digitCount;
+               
+               // When there's more than one instance, extra bytes are needed to append " (<instance index>)" or
+               // "-<instance index>" to the base hostname.
+               
+               maxInstanceCount = context->maxInstanceCount;
+               for( digitCount = 0; maxInstanceCount > 0; ++digitCount ) maxInstanceCount /= 10;
+               len += ( 3 + digitCount );
+       }
+       
+       if( len <= kDomainLabelLengthMax )
+       {
+               uint8_t *               dst = &name[ 1 ];
+               uint8_t *               lim = &name[ countof( name ) ];
+               
+               SNPrintF_Add( (char **) &dst, (char *) lim, "%s", gMDNSReplier_Hostname );
+               name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
+               
+               err = DomainNameDupLower( name, &context->hostname, NULL );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               FPrintF( stderr, "error: Base name \"%s\" is too long for max instance count of %u.\n",
+                       gMDNSReplier_Hostname, context->maxInstanceCount );
+               goto exit;
+       }
+       
+       // Create the service label.
+       
+       len = strlen( gMDNSReplier_ServiceTypeTag ) + 3;        // We need three extra bytes for the service type prefix "_t-".
+       if( len <= kDomainLabelLengthMax )
+       {
+               uint8_t *               dst = &name[ 1 ];
+               uint8_t *               lim = &name[ countof( name ) ];
+               
+               SNPrintF_Add( (char **) &dst, (char *) lim, "_t-%s", gMDNSReplier_ServiceTypeTag );
+               name[ 0 ] = (uint8_t)( dst - &name[ 1 ] );
+               
+               err = DomainNameDupLower( name, &context->serviceLabel, NULL );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               FPrintF( stderr, "error: Service type tag is too long.\n" );
+               goto exit;
+       }
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       ifname = if_indextoname( context->ifIndex, ifnameBuf );
+       require_action( ifname, exit, err = kNameErr );
+       
+       // Set up IPv4 socket.
+       
+       if( context->useIPv4 )
+       {
+               err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV4 );
+               require_noerr( err, exit );
+       }
+       
+       // Set up IPv6 socket.
+       
+       if( context->useIPv6 )
+       {
+               err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, ifname, context->ifIndex, true, NULL, &sockV6 );
+               require_noerr( err, exit );
+       }
+       
+       // Create dispatch read sources for socket(s).
+       
+       if( IsValidSocket( sockV4 ) )
+       {
+               SocketContext *         sockCtx;
+               
+               err = SocketContextCreate( sockV4, context, &sockCtx );
+               require_noerr( err, exit );
+               sockV4 = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
+                       &context->readSourceV4 );
+               if( err ) ForgetSocketContext( &sockCtx );
+               require_noerr( err, exit );
+               
+               dispatch_resume( context->readSourceV4 );
+       }
+       
+       if( IsValidSocket( sockV6 ) )
+       {
+               SocketContext *         sockCtx;
+               
+               err = SocketContextCreate( sockV6, context, &sockCtx );
+               require_noerr( err, exit );
+               sockV6 = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, NULL, _MDNSReplierReadHandler, SocketContextCancelHandler, sockCtx,
+                       &context->readSourceV6 );
+               if( err ) ForgetSocketContext( &sockCtx );
+               require_noerr( err, exit );
+               
+               dispatch_resume( context->readSourceV6 );
+       }
+       
+       dispatch_main();
+       
+exit:
+       ForgetSocket( &sockV4 );
+       ForgetSocket( &sockV6 );
+       exit( 1 );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+//     _MDNSReplierFollowedProcessHandler
+//===========================================================================================================================
+
+static void    _MDNSReplierFollowedProcessHandler( void *inContext )
+{
+       MDNSReplierContext * const              context = (MDNSReplierContext *) inContext;
+       
+       if( dispatch_source_get_data( context->processMonitor ) & DISPATCH_PROC_EXIT )
+       {
+               mr_ulog( kLogLevelNotice, "Exiting: followed process (%lld) exited.\n", (int64_t) context->followPID );
+               exit( 0 );
+       }
+}
+#endif
+
+//===========================================================================================================================
+//     _MDNSReplierReadHandler
+//===========================================================================================================================
+
+#define ShouldDrop( P )                ( ( (P) > 0.0 ) && ( ( (P) >= 1.0 ) || RandomlyTrue( P ) ) )
+
+static void    _MDNSReplierReadHandler( void *inContext )
+{
+       OSStatus                                                err;
+       SocketContext * const                   sockCtx = (SocketContext *) inContext;
+       MDNSReplierContext * const              context = (MDNSReplierContext *) sockCtx->userContext;
+       size_t                                                  msgLen;
+       sockaddr_ip                                             sender;
+       const DNSHeader *                               hdr;
+       unsigned int                                    flags, questionCount, i, j;
+       const uint8_t *                                 ptr;
+       int                                                             drop, isMetaQuery;
+       
+       err = SocketRecvFrom( sockCtx->sock, context->msgBuf, sizeof( context->msgBuf ), &msgLen, &sender, sizeof( sender ),
+               NULL, NULL, NULL, NULL );
+       require_noerr( err, exit );
+       
+       if( msgLen < kDNSHeaderLength )
+       {
+               mr_ulog( kLogLevelInfo, "Message is too small (%zu < %d).\n", msgLen, kDNSHeaderLength );
+               goto exit;
+       }
+       
+       // Perform header field checks.
+       // The message ID and most flag bits are silently ignored (see <https://tools.ietf.org/html/rfc6762#section-18>).
+       
+       hdr = (DNSHeader *) context->msgBuf;
+       flags = DNSHeaderGetFlags( hdr );
+       require_quiet( ( flags & kDNSHeaderFlag_Response ) == 0, exit );                // Reject responses.
+       require_quiet( DNSFlagsGetOpCode( flags ) == kDNSOpCode_Query, exit );  // Reject opcodes other than standard query.
+       require_quiet( DNSFlagsGetRCode( flags )  == kDNSRCode_NoError, exit ); // Reject non-zero rcodes.
+       
+       drop = ( !context->maxDropCount && ShouldDrop( context->mcastDropRate ) ) ? true : false;
+       
+       mr_ulog( kLogLevelInfo, "Received %zu byte message from %##a%?s:\n\n%#1{du:dnsmsg}",
+               msgLen, &sender, drop, " (dropping)", context->msgBuf, msgLen );
+       
+       // Based on the QNAMEs in the query message, determine from which sets of records we may possibly need answers.
+       
+       questionCount = DNSHeaderGetQuestionCount( hdr );
+       require_quiet( questionCount > 0, exit );
+       
+       memset( context->bitmaps, 0, context->bitmapCount * sizeof_element( context->bitmaps ) );
+       
+       isMetaQuery = false;
+       ptr = (const uint8_t *) &hdr[ 1 ];
+       for( i = 0; i < questionCount; ++i )
+       {
+               unsigned int            count, index;
+               uint16_t                        qtype, qclass;
+               uint8_t                         qname[ kDomainNameLengthMax ];
+               
+               err = DNSMessageExtractQuestion( context->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
+               require_noerr_quiet( err, exit );
+               
+               if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
+               
+               if( _MDNSReplierHostnameMatch( context, qname, &index ) ||
+                       _MDNSReplierServiceInstanceNameMatch( context, qname, &index, NULL, NULL ) )
+               {
+                       if( ( index >= 1 ) && ( index <= context->maxInstanceCount ) )
+                       {
+                               context->bitmaps[ ( index - 1 ) / 64 ] |= ( UINT64_C( 1 ) << ( ( index - 1 ) % 64 ) );
+                       }
+               }
+               else if( _MDNSReplierServiceTypeMatch( context, qname, NULL, &count ) )
+               {
+                       if( ( count >= 1 ) && ( count <= context->maxInstanceCount ) )
+                       {
+                               for( j = 0; j < (unsigned int) context->bitmapCount; ++j )
+                               {
+                                       if( count < 64 )
+                                       {
+                                               context->bitmaps[ j ] |= ( ( UINT64_C( 1 ) << count ) - 1 );
+                                               break;
+                                       }
+                                       else
+                                       {
+                                               context->bitmaps[ j ] = ~UINT64_C( 0 );
+                                               count -= 64;
+                                       }
+                               }
+                       }
+               }
+               else if( _MDNSReplierAboutRecordNameMatch( context, qname ) )
+               {
+                       isMetaQuery = true;
+               }
+       }
+       
+       // Attempt to answer the query message using selected record sets.
+       
+       if( isMetaQuery )
+       {
+               err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock, 0 );
+               check_noerr( err );
+       }
+       if( drop ) goto exit;
+       
+       for( i = 0; i < context->bitmapCount; ++i )
+       {
+               for( j = 0; ( context->bitmaps[ i ] != 0 ) && ( j < 64 ); ++j )
+               {
+                       const uint64_t          bitmask = UINT64_C( 1 ) << j;
+                       
+                       if( context->bitmaps[ i ] & bitmask )
+                       {
+                               context->bitmaps[ i ] &= ~bitmask;
+                               
+                               err = _MDNSReplierAnswerQuery( context, context->msgBuf, msgLen, &sender, sockCtx->sock,
+                                       ( i * 64 ) + j + 1 );
+                               check_noerr( err );
+                       }
+               }
+       }
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     _MDNSReplierAnswerQuery
+//===========================================================================================================================
+
+static OSStatus
+       _MDNSReplierAnswerQuery(
+               MDNSReplierContext *    inContext,
+               const uint8_t *                 inQueryPtr,
+               size_t                                  inQueryLen,
+               sockaddr_ip *                   inSender,
+               SocketRef                               inSock,
+               unsigned int                    inIndex )
+{
+       OSStatus                                err;
+       const DNSHeader *               hdr;
+       const uint8_t *                 ptr;
+       unsigned int                    questionCount, answerCount, i;
+       MRResourceRecord *              ucastAnswerList = NULL;
+       MRResourceRecord *              mcastAnswerList = NULL;
+       
+       require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
+       
+       // Get answers for questions.
+       
+       check( inQueryLen >= kDNSHeaderLength );
+       hdr = (const DNSHeader *) inQueryPtr;
+       questionCount = DNSHeaderGetQuestionCount( hdr );
+       
+       ptr = (const uint8_t *) &hdr[ 1 ];
+       for( i = 0; i < questionCount; ++i )
+       {
+               MRResourceRecord **             answerListPtr;
+               uint16_t                                qtype, qclass;
+               uint8_t                                 qname[ kDomainNameLengthMax ];
+               
+               err = DNSMessageExtractQuestion( inQueryPtr, inQueryLen, ptr, qname, &qtype, &qclass, &ptr );
+               require_noerr_quiet( err, exit );
+               
+               if( qclass & kQClassUnicastResponseBit )
+               {
+                       qclass &= ~kQClassUnicastResponseBit;
+                       answerListPtr = &ucastAnswerList;
+               }
+               else
+               {
+                       answerListPtr = &mcastAnswerList;
+               }
+               
+               err = _MDNSReplierAnswerListAdd( inContext, answerListPtr, inIndex, qname, qtype, qclass );
+               require_noerr( err, exit );
+       }
+       require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
+       
+       // Suppress known answers.
+       // Records in the Answer section of the query message are known answers, so remove them from the answer lists.
+       // See <https://tools.ietf.org/html/rfc6762#section-7.1>.
+       
+       answerCount = DNSHeaderGetAnswerCount( hdr );
+       for( i = 0; i < answerCount; ++i )
+       {
+               const uint8_t *         rdataPtr;
+               const uint8_t *         recordPtr;
+               uint16_t                        type, class;
+               uint8_t                         name[ kDomainNameLengthMax ];
+               uint8_t                         instance[ kDomainNameLengthMax ];
+               
+               recordPtr = ptr;
+               err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, ptr, NULL, &type, &class, NULL, NULL, NULL, &ptr );
+               require_noerr_quiet( err, exit );
+               
+               if( ( type != kDNSServiceType_PTR ) || ( class != kDNSServiceClass_IN ) ) continue;
+               
+               err = DNSMessageExtractRecord( inQueryPtr, inQueryLen, recordPtr, name, NULL, NULL, NULL, &rdataPtr, NULL, NULL );
+               require_noerr( err, exit );
+               
+               err = DNSMessageExtractDomainName( inQueryPtr, inQueryLen, rdataPtr, instance, NULL );
+               require_noerr_quiet( err, exit );
+               
+               if( ucastAnswerList ) _MDNSReplierAnswerListRemovePTR( &ucastAnswerList, name, instance );
+               if( mcastAnswerList ) _MDNSReplierAnswerListRemovePTR( &mcastAnswerList, name, instance );
+       }
+       require_action_quiet( mcastAnswerList || ucastAnswerList, exit, err = kNoErr );
+       
+       // Send or drop responses.
+       
+       if( ucastAnswerList )
+       {
+               err = _MDNSReplierSendOrDropResponse( inContext, ucastAnswerList, inSender, inSock, inIndex, true );
+               require_noerr( err, exit );
+       }
+       
+       if( mcastAnswerList )
+       {
+               err = _MDNSReplierSendOrDropResponse( inContext, mcastAnswerList, inSender, inSock, inIndex, false );
+               require_noerr( err, exit );
+       }
+       err = kNoErr;
+       
+exit:
+       _MRResourceRecordFreeList( ucastAnswerList );
+       _MRResourceRecordFreeList( mcastAnswerList );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierAnswerListAdd
+//===========================================================================================================================
+
+static OSStatus
+       _MDNSReplierAnswerListAdd(
+               MDNSReplierContext *    inContext,
+               MRResourceRecord **             inAnswerList,
+               unsigned int                    inIndex,
+               const uint8_t *                 inName,
+               unsigned int                    inType,
+               unsigned int                    inClass )
+{
+       OSStatus                                        err;
+       uint8_t *                                       recordName      = NULL;
+       uint8_t *                                       rdataPtr        = NULL;
+       size_t                                          rdataLen;
+       MRResourceRecord *                      answer;
+       MRResourceRecord **                     answerPtr;
+       const uint8_t * const           hostname        = inContext->hostname;
+       unsigned int                            i;
+       uint32_t                                        index;
+       unsigned int                            count, txtSize;
+       
+       require_action( inIndex <= inContext->maxInstanceCount, exit, err = kRangeErr );
+       require_action_quiet( inClass == kDNSServiceClass_IN, exit, err = kNoErr );
+       
+       for( answerPtr = inAnswerList; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
+       {
+               if( ( answer->type == inType ) && DomainNameEqual( answer->name, inName ) )
+               {
+                       err = kNoErr;
+                       goto exit;
+               }
+       }
+       
+       // Index 0 is reserved for answering queries about the mdnsreplier, while all other index values up to the maximum
+       // instance count are for answering queries about service instances.
+       
+       if( inIndex == 0 )
+       {
+               if( _MDNSReplierAboutRecordNameMatch( inContext, inName ) )
+               {
+                       int             listHasTXT = false;
+                       
+                       if( inType == kDNSServiceType_ANY )
+                       {
+                               for( answer = *inAnswerList; answer; answer = answer->next )
+                               {
+                                       if( ( answer->type == kDNSServiceType_TXT ) && DomainNameEqual( answer->name, inName ) )
+                                       {
+                                               listHasTXT = true;
+                                               break;
+                                       }
+                               }
+                       }
+                       
+                       if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
+                       {
+                               err = DomainNameDupLower( inName, &recordName, NULL );
+                               require_noerr( err, exit );
+                               
+                               err = CreateTXTRecordDataFromString( "ready=yes", ',', &rdataPtr, &rdataLen );
+                               require_noerr( err, exit );
+                               
+                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
+                                       (uint16_t) rdataLen, rdataPtr, &answer );
+                               require_noerr( err, exit );
+                               recordName      = NULL;
+                               rdataPtr        = NULL;
+                               
+                               *answerPtr = answer;
+                       }
+                       else if( inType == kDNSServiceType_NSEC )
+                       {
+                               err = DomainNameDupLower( inName, &recordName, NULL );
+                               require_noerr( err, exit );
+                               
+                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_TXT );
+                               require_noerr( err, exit );
+                               
+                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+                                       (uint16_t) rdataLen, rdataPtr, &answer );
+                               require_noerr( err, exit );
+                               recordName      = NULL;
+                               rdataPtr        = NULL;
+                               
+                               *answerPtr = answer;
+                       }
+               }
+       }
+       else if( _MDNSReplierHostnameMatch( inContext, inName, &index ) && ( index == inIndex ) )
+       {
+               int             listHasA        = false;
+               int             listHasAAAA     = false;
+               
+               if( inType == kDNSServiceType_ANY )
+               {
+                       for( answer = *inAnswerList; answer; answer = answer->next )
+                       {
+                               if( answer->type == kDNSServiceType_A )
+                               {
+                                       if( !listHasA && DomainNameEqual( answer->name, inName ) ) listHasA = true;
+                               }
+                               else if( answer->type == kDNSServiceType_AAAA )
+                               {
+                                       if( !listHasAAAA && DomainNameEqual( answer->name, inName ) ) listHasAAAA = true;
+                               }
+                               if( listHasA && listHasAAAA ) break;
+                       }
+               }
+               
+               if( ( inType == kDNSServiceType_A ) || ( ( inType == kDNSServiceType_ANY ) && !listHasA ) )
+               {
+                       for( i = 1; i <= inContext->recordCountA; ++i )
+                       {
+                               err = DomainNameDupLower( inName, &recordName, NULL );
+                               require_noerr( err, exit );
+                               
+                               rdataLen = 4;
+                               rdataPtr = (uint8_t *) malloc( rdataLen );
+                               require_action( rdataPtr, exit, err = kNoMemoryErr );
+                               
+                               rdataPtr[ 0 ] = 0;
+                               WriteBig16( &rdataPtr[ 1 ], inIndex );
+                               rdataPtr[ 3 ] = (uint8_t) i;
+                               
+                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_A, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+                                       (uint16_t) rdataLen, rdataPtr, &answer );
+                               require_noerr( err, exit );
+                               recordName      = NULL;
+                               rdataPtr        = NULL;
+                               
+                               *answerPtr = answer;
+                                answerPtr = &answer->next;
+                       }
+               }
+               
+               if( ( inType == kDNSServiceType_AAAA ) || ( ( inType == kDNSServiceType_ANY ) && !listHasAAAA ) )
+               {
+                       for( i = 1; i <= inContext->recordCountAAAA; ++i )
+                       {
+                               err = DomainNameDupLower( inName, &recordName, NULL );
+                               require_noerr( err, exit );
+                               
+                               rdataLen = 16;
+                               rdataPtr = (uint8_t *) _memdup( kMDNSReplierBaseAddrV6, rdataLen );
+                               require_action( rdataPtr, exit, err = kNoMemoryErr );
+                               
+                               WriteBig16( &rdataPtr[ 12 ], inIndex );
+                               rdataPtr[ 15 ] = (uint8_t) i;
+                               
+                               err = _MRResourceRecordCreate( recordName, kDNSServiceType_AAAA, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+                                       (uint16_t) rdataLen, rdataPtr, &answer );
+                               require_noerr( err, exit );
+                               recordName      = NULL;
+                               rdataPtr        = NULL;
+                               
+                               *answerPtr = answer;
+                                answerPtr = &answer->next;
+                       }
+               }
+               else if( inType == kDNSServiceType_NSEC )
+               {
+                       err = DomainNameDupLower( inName, &recordName, NULL );
+                       require_noerr( err, exit );
+                       
+                       if( ( inContext->recordCountA > 0 ) && ( inContext->recordCountAAAA > 0 ) )
+                       {
+                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_A, kDNSServiceType_AAAA );
+                               require_noerr( err, exit );
+                       }
+                       else if( inContext->recordCountA > 0 )
+                       {
+                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_A );
+                               require_noerr( err, exit );
+                       }
+                       else if( inContext->recordCountAAAA > 0 )
+                       {
+                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 1, kDNSServiceType_AAAA );
+                               require_noerr( err, exit );
+                       }
+                       else
+                       {
+                               err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 0 );
+                               require_noerr( err, exit );
+                       }
+                       
+                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+                               (uint16_t) rdataLen, rdataPtr, &answer );
+                       require_noerr( err, exit );
+                       recordName      = NULL;
+                       rdataPtr        = NULL;
+                       
+                       *answerPtr = answer;
+               }
+       }
+       else if( _MDNSReplierServiceTypeMatch( inContext, inName, NULL, &count ) && ( count >= inIndex ) )
+       {
+               int             listHasPTR = false;
+               
+               if( inType == kDNSServiceType_ANY )
+               {
+                       for( answer = *inAnswerList; answer; answer = answer->next )
+                       {
+                               if( ( answer->type == kDNSServiceType_PTR ) && DomainNameEqual( answer->name, inName ) )
+                               {
+                                       listHasPTR = true;
+                                       break;
+                               }
+                       }
+               }
+               
+               if( ( inType == kDNSServiceType_PTR ) || ( ( inType == kDNSServiceType_ANY ) && !listHasPTR ) )
+               {
+                       size_t                          recordNameLen;
+                       uint8_t *                       ptr;
+                       uint8_t *                       lim;
+                       
+                       err = DomainNameDupLower( inName, &recordName, &recordNameLen );
+                       require_noerr( err, exit );
+                       
+                       rdataLen = 1 + hostname[ 0 ] + 10 + recordNameLen;
+                       rdataPtr = (uint8_t *) malloc( rdataLen );
+                       require_action( rdataPtr, exit, err = kNoMemoryErr );
+                       
+                       lim = &rdataPtr[ rdataLen ];
+                       
+                       ptr = &rdataPtr[ 1 ];
+                       memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
+                       ptr += hostname[ 0 ];
+                       if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, " (%u)", inIndex );
+                       rdataPtr[ 0 ] = (uint8_t)( ptr - &rdataPtr[ 1 ] );
+                       
+                       check( (size_t)( lim - ptr ) >= recordNameLen );
+                       memcpy( ptr, recordName, recordNameLen );
+                       ptr += recordNameLen;
+                       
+                       rdataLen = (size_t)( ptr - rdataPtr );
+                       
+                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_PTR, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
+                               (uint16_t) rdataLen, rdataPtr, &answer );
+                       require_noerr( err, exit );
+                       recordName      = NULL;
+                       rdataPtr        = NULL;
+                       
+                       *answerPtr = answer;
+               }
+       }
+       else if( _MDNSReplierServiceInstanceNameMatch( inContext, inName, &index, &txtSize, &count ) &&
+               ( index == inIndex ) && ( count >= inIndex ) )
+       {
+               int             listHasSRV = false;
+               int             listHasTXT = false;
+               
+               if( inType == kDNSServiceType_ANY )
+               {
+                       for( answer = *inAnswerList; answer; answer = answer->next )
+                       {
+                               if( answer->type == kDNSServiceType_SRV )
+                               {
+                                       if( !listHasSRV && DomainNameEqual( answer->name, inName ) ) listHasSRV = true;
+                               }
+                               else if( answer->type == kDNSServiceType_TXT )
+                               {
+                                       if( !listHasTXT && DomainNameEqual( answer->name, inName ) ) listHasTXT = true;
+                               }
+                               if( listHasSRV && listHasTXT ) break;
+                       }
+               }
+               
+               if( ( inType == kDNSServiceType_SRV ) || ( ( inType == kDNSServiceType_ANY ) && !listHasSRV ) )
+               {
+                       dns_fixed_fields_srv *          fields;
+                       uint8_t *                                       ptr;
+                       uint8_t *                                       lim;
+                       uint8_t *                                       targetPtr;
+                       
+                       err = DomainNameDupLower( inName, &recordName, NULL );
+                       require_noerr( err, exit );
+                       
+                       rdataLen = sizeof( dns_fixed_fields_srv ) + 1 + hostname[ 0 ] + 10 + kLocalNameLen;
+                       rdataPtr = (uint8_t *) malloc( rdataLen );
+                       require_action( rdataPtr, exit, err = kNoMemoryErr );
+                       
+                       lim = &rdataPtr[ rdataLen ];
+                       
+                       fields = (dns_fixed_fields_srv *) rdataPtr;
+                       dns_fixed_fields_srv_init( fields, 0, 0, (uint16_t)( kMDNSReplierPortBase + txtSize ) );
+                       
+                       targetPtr = (uint8_t *) &fields[ 1 ];
+                       
+                       ptr = &targetPtr[ 1 ];
+                       memcpy( ptr, &hostname[ 1 ], hostname[ 0 ] );
+                       ptr += hostname[ 0 ];
+                       if( inIndex != 1 ) SNPrintF_Add( (char **) &ptr, (char *) lim, "-%u", inIndex );
+                       targetPtr[ 0 ] = (uint8_t)( ptr - &targetPtr[ 1 ] );
+                       
+                       check( (size_t)( lim - ptr ) >= kLocalNameLen );
+                       memcpy( ptr, kLocalName, kLocalNameLen );
+                       ptr += kLocalNameLen;
+                       
+                       rdataLen = (size_t)( ptr - rdataPtr );
+                       
+                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_SRV, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+                               (uint16_t) rdataLen, rdataPtr, &answer );
+                       require_noerr( err, exit );
+                       recordName      = NULL;
+                       rdataPtr        = NULL;
+                       
+                       *answerPtr = answer;
+                        answerPtr = &answer->next;
+               }
+               
+               if( ( inType == kDNSServiceType_TXT ) || ( ( inType == kDNSServiceType_ANY ) && !listHasTXT ) )
+               {
+                       err = DomainNameDupLower( inName, &recordName, NULL );
+                       require_noerr( err, exit );
+                       
+                       rdataLen = txtSize;
+                       err = _MDNSReplierCreateTXTRecord( inName, rdataLen, &rdataPtr );
+                       require_noerr( err, exit );
+                       
+                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_TXT, kDNSServiceClass_IN, kMDNSRecordTTL_Other,
+                               (uint16_t) rdataLen, rdataPtr, &answer );
+                       require_noerr( err, exit );
+                       recordName      = NULL;
+                       rdataPtr        = NULL;
+                       
+                       *answerPtr = answer;
+               }
+               else if( inType == kDNSServiceType_NSEC )
+               {
+                       err = DomainNameDupLower( inName, &recordName, NULL );
+                       require_noerr( err, exit );
+                       
+                       err = CreateNSECRecordData( recordName, &rdataPtr, &rdataLen, 2, kDNSServiceType_TXT, kDNSServiceType_SRV );
+                       require_noerr( err, exit );
+                       
+                       err = _MRResourceRecordCreate( recordName, kDNSServiceType_NSEC, kDNSServiceClass_IN, kMDNSRecordTTL_Host,
+                               (uint16_t) rdataLen, rdataPtr, &answer );
+                       require_noerr( err, exit );
+                       recordName      = NULL;
+                       rdataPtr        = NULL;
+                       
+                       *answerPtr = answer;
+               }
+       }
+       err = kNoErr;
+       
+exit:
+       FreeNullSafe( recordName );
+       FreeNullSafe( rdataPtr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierAnswerListRemovePTR
+//===========================================================================================================================
+
+static void
+       _MDNSReplierAnswerListRemovePTR(
+               MRResourceRecord **     inAnswerListPtr,
+               const uint8_t *         inName,
+               const uint8_t *         inRData )
+{
+       MRResourceRecord *              answer;
+       MRResourceRecord **             answerPtr;
+       
+       for( answerPtr = inAnswerListPtr; ( answer = *answerPtr ) != NULL; answerPtr = &answer->next )
+       {
+               if( ( answer->type == kDNSServiceType_PTR ) && ( answer->class == kDNSServiceClass_IN ) &&
+                       DomainNameEqual( answer->name, inName ) && DomainNameEqual( answer->rdata, inRData ) ) break;
+       }
+       if( answer )
+       {
+               *answerPtr = answer->next;
+               _MRResourceRecordFree( answer );
+       }
+}
+
+//===========================================================================================================================
+//     _MDNSReplierSendOrDropResponse
+//===========================================================================================================================
+
+static OSStatus
+       _MDNSReplierSendOrDropResponse(
+               MDNSReplierContext *    inContext,
+               MRResourceRecord *              inAnswerList,
+               sockaddr_ip *                   inQuerier,
+               SocketRef                               inSock,
+               unsigned int                    inIndex,
+               Boolean                                 inUnicast )
+{
+       OSStatus                                        err;
+       uint8_t *                                       responsePtr     = NULL;
+       size_t                                          responseLen;
+       const struct sockaddr *         destAddr;
+       ssize_t                                         n;
+       const double                            dropRate        = inUnicast ? inContext->ucastDropRate : inContext->mcastDropRate;
+       int                                                     drop;
+       
+       check( inIndex <= inContext->maxInstanceCount );
+       
+       // If maxDropCount > 0, then the drop rates apply only to the first maxDropCount responses. Otherwise, all messages are
+       // subject to their respective drop rate. Also, responses to queries about mDNS replier itself (indicated by index 0),
+       // as opposed to those for service instance records, are never dropped.
+       
+       drop = false;
+       if( inIndex > 0 )
+       {
+               if( inContext->maxDropCount > 0 )
+               {
+                       uint8_t * const         dropCount = &inContext->dropCounters[ inIndex - 1 ];
+                       
+                       if( *dropCount < inContext->maxDropCount )
+                       {
+                               if( ShouldDrop( dropRate ) ) drop = true;
+                               *dropCount += 1;
+                       }
+               }
+               else if( ShouldDrop( dropRate ) )
+               {
+                       drop = true;
+               }
+       }
+       
+       err = _MDNSReplierCreateResponse( inContext, inAnswerList, inIndex, &responsePtr, &responseLen );
+       require_noerr( err, exit );
+       
+       if( inUnicast )
+       {
+               destAddr = &inQuerier->sa;
+       }
+       else
+       {
+               destAddr = ( inQuerier->sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
+       }
+       
+       mr_ulog( kLogLevelInfo, "%s %zu byte response to %##a:\n\n%#1{du:dnsmsg}",
+               drop ? "Dropping" : "Sending", responseLen, destAddr, responsePtr, responseLen );
+       
+       if( !drop )
+       {
+               n = sendto( inSock, (char *) responsePtr, responseLen, 0, destAddr, SockAddrGetSize( destAddr ) );
+               err = map_socket_value_errno( inSock, n == (ssize_t) responseLen, n );
+               require_noerr( err, exit );
+       }
+       
+exit:
+       FreeNullSafe( responsePtr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierCreateResponse
+//===========================================================================================================================
+
+static OSStatus
+       _MDNSReplierCreateResponse(
+               MDNSReplierContext *    inContext,
+               MRResourceRecord *              inAnswerList,
+               unsigned int                    inIndex,
+               uint8_t **                              outResponsePtr,
+               size_t *                                outResponseLen )
+{
+       OSStatus                                err;
+       DataBuffer                              responseDB;
+       DNSHeader                               hdr;
+       MRResourceRecord *              answer;
+       uint8_t *                               responsePtr;
+       size_t                                  responseLen, len;
+       unsigned int                    answerCount, recordCount;
+       MRNameOffsetItem *              nameOffsetList = NULL;
+       
+       DataBuffer_Init( &responseDB, NULL, 0, SIZE_MAX );
+       
+       // The current answers in the answer list will make up the response's Answer Record Section.
+       
+       answerCount = 0;
+       for( answer = inAnswerList; answer; answer = answer->next ) { ++answerCount; }
+       
+       // Unless configured not to, add any additional answers to the answer list for the Additional Record Section.
+       
+       if( !inContext->noAdditionals )
+       {
+               for( answer = inAnswerList; answer; answer = answer->next )
+               {
+                       switch( answer->type )
+                       {
+                               case kDNSServiceType_PTR:
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_SRV,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->rdata, kDNSServiceType_TXT,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       break;
+                               
+                               case kDNSServiceType_SRV:
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_A,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->target, kDNSServiceType_AAAA,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       break;
+                               
+                               case kDNSServiceType_TXT:
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       break;
+                               
+                               case kDNSServiceType_A:
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_AAAA,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       break;
+                               
+                               case kDNSServiceType_AAAA:
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_A,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       
+                                       err = _MDNSReplierAnswerListAdd( inContext, &inAnswerList, inIndex, answer->name, kDNSServiceType_NSEC,
+                                               answer->class );
+                                       require_noerr( err, exit );
+                                       break;
+                               
+                               default:
+                                       break;
+                       }
+               }
+       }
+       
+       // Append a provisional header to the response message.
+       
+       memset( &hdr, 0, sizeof( hdr ) );
+       DNSHeaderSetFlags( &hdr, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
+       
+       err = DataBuffer_Append( &responseDB, &hdr, sizeof( hdr ) );
+       require_noerr( err, exit );
+       
+       // Append answers to response message.
+       
+       responseLen = DataBuffer_GetLen( &responseDB );
+       recordCount = 0;
+       for( answer = inAnswerList; answer; answer = answer->next )
+       {
+               dns_fixed_fields_record         fields;
+               unsigned int                            class;
+               
+               // Append record NAME.
+               
+               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->name, &nameOffsetList );
+               require_noerr( err, exit );
+               
+               // Append record TYPE, CLASS, TTL, and provisional RDLENGTH.
+               
+               class = answer->class;
+               if( ( answer->type == kDNSServiceType_SRV ) || ( answer->type == kDNSServiceType_TXT )  ||
+                       ( answer->type == kDNSServiceType_A )   || ( answer->type == kDNSServiceType_AAAA ) ||
+                       ( answer->type == kDNSServiceType_NSEC ) )
+               {
+                       class |= kRRClassCacheFlushBit;
+               }
+               
+               dns_fixed_fields_record_init( &fields, answer->type, (uint16_t) class, answer->ttl, (uint16_t) answer->rdlength );
+               err = DataBuffer_Append( &responseDB, &fields, sizeof( fields ) );
+               require_noerr( err, exit );
+               
+               // Append record RDATA.
+               // The RDATA of PTR, SRV, and NSEC records contain domain names, which are subject to name compression.
+               
+               if( ( answer->type == kDNSServiceType_PTR ) || ( answer->type == kDNSServiceType_SRV ) ||
+                       ( answer->type == kDNSServiceType_NSEC ) )
+               {
+                       size_t                          rdlength;
+                       uint8_t *                       rdLengthPtr;
+                       const size_t            rdLengthOffset  = DataBuffer_GetLen( &responseDB ) - 2;
+                       const size_t            rdataOffset             = DataBuffer_GetLen( &responseDB );
+                       
+                       if( answer->type == kDNSServiceType_PTR )
+                       {
+                               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
+                               require_noerr( err, exit );
+                       }
+                       else if( answer->type == kDNSServiceType_SRV )
+                       {
+                               require_fatal( answer->target == &answer->rdata[ 6 ], "Bad SRV record target pointer." );
+                               
+                               err = DataBuffer_Append( &responseDB, answer->rdata, (size_t)( answer->target - answer->rdata ) );
+                               require_noerr( err, exit );
+                               
+                               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->target, &nameOffsetList );
+                               require_noerr( err, exit );
+                       }
+                       else
+                       {
+                               const size_t            nameLen = DomainNameLength( answer->rdata );
+                               
+                               err = _MDNSReplierAppendNameToResponse( &responseDB, answer->rdata, &nameOffsetList );
+                               require_noerr( err, exit );
+                               
+                               require_fatal( answer->rdlength > nameLen, "Bad NSEC record data length." );
+                               
+                               err = DataBuffer_Append( &responseDB, &answer->rdata[ nameLen ], answer->rdlength - nameLen );
+                               require_noerr( err, exit );
+                       }
+                       
+                       // Set the actual RDLENGTH, which may be less than the original due to name compression.
+                       
+                       rdlength = DataBuffer_GetLen( &responseDB ) - rdataOffset;
+                       check( rdlength <= UINT16_MAX );
+                       
+                       rdLengthPtr = DataBuffer_GetPtr( &responseDB ) + rdLengthOffset;
+                       WriteBig16( rdLengthPtr, rdlength );
+               }
+               else
+               {
+                       err = DataBuffer_Append( &responseDB, answer->rdata, answer->rdlength );
+                       require_noerr( err, exit );
+               }
+               
+               if( DataBuffer_GetLen( &responseDB ) > kMDNSMessageSizeMax ) break;
+               responseLen = DataBuffer_GetLen( &responseDB );
+               ++recordCount;
+       }
+       
+       // Set the response header's Answer and Additional record counts.
+       // Note: recordCount may be less than answerCount if including all answerCount records would cause the size of the
+       // response message to exceed the maximum mDNS message size.
+       
+       if( recordCount <= answerCount )
+       {
+               DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount );
+       }
+       else
+       {
+               DNSHeaderSetAnswerCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), answerCount );
+               DNSHeaderSetAdditionalCount( (DNSHeader *) DataBuffer_GetPtr( &responseDB ), recordCount - answerCount );
+       }
+       
+       err = DataBuffer_Detach( &responseDB, &responsePtr, &len );
+       require_noerr( err, exit );
+       
+       if( outResponsePtr ) *outResponsePtr = responsePtr;
+       if( outResponseLen ) *outResponseLen = responseLen;
+       
+exit:
+       _MRNameOffsetItemFreeList( nameOffsetList );
+       DataBuffer_Free( &responseDB );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierAppendNameToResponse
+//===========================================================================================================================
+
+static OSStatus
+       _MDNSReplierAppendNameToResponse(
+               DataBuffer *            inResponse,
+               const uint8_t *         inName,
+               MRNameOffsetItem **     inNameOffsetListPtr )
+{
+       OSStatus                                err;
+       const uint8_t *                 subname;
+       const uint8_t *                 limit;
+       size_t                                  nameOffset;
+       MRNameOffsetItem *              item;
+       uint8_t                                 compressionPtr[ 2 ];
+       
+       nameOffset = DataBuffer_GetLen( inResponse );
+       
+       // Find the name's longest subname (more accurately, its longest sub-FQDN) in the name compression list.
+       
+       for( subname = inName; subname[ 0 ] != 0; subname += ( 1 + subname[ 0 ] ) )
+       {
+               for( item = *inNameOffsetListPtr; item; item = item->next )
+               {
+                       if( DomainNameEqual( item->name, subname ) ) break;
+               }
+               
+               // If an item was found for this subname, then append a name compression pointer and we're done. Otherwise, append
+               // the subname's first label.
+               
+               if( item )
+               {
+                       DNSMessageWriteLabelPointer( compressionPtr, item->offset );
+                       
+                       err = DataBuffer_Append( inResponse, compressionPtr, sizeof( compressionPtr ) );
+                       require_noerr( err, exit );
+                       break;
+               }
+               else
+               {
+                       err = DataBuffer_Append( inResponse, subname, 1 + subname[ 0 ] );
+                       require_noerr( err, exit );
+               }
+       }
+               
+       // If we made it to the root label, then no subname was able to be compressed. All of the name's labels up to the root
+       // label were appended to the response message, so a root label is needed to terminate the complete name.
+       
+       if( subname[ 0 ] == 0 )
+       {
+               err = DataBuffer_Append( inResponse, "", 1 );
+               require_noerr( err, exit );
+       }
+       
+       // Add subnames that weren't able to be compressed and their offsets to the name compression list.
+       
+       limit = subname;
+       for( subname = inName; subname < limit; subname += ( 1 + subname[ 0 ] ) )
+       {
+               const size_t            subnameOffset = nameOffset + (size_t)( subname - inName );
+               
+               if( subnameOffset > kDNSCompressionOffsetMax ) break;
+               
+               err = _MRNameOffsetItemCreate( subname, (uint16_t) subnameOffset, &item );
+               require_noerr( err, exit );
+               
+               item->next = *inNameOffsetListPtr;
+               *inNameOffsetListPtr = item;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierServiceTypeMatch
+//===========================================================================================================================
+
+static Boolean
+       _MDNSReplierServiceTypeMatch(
+               const MDNSReplierContext *      inContext,
+               const uint8_t *                         inName,
+               unsigned int *                          outTXTSize,
+               unsigned int *                          outCount )
+{
+       OSStatus                                        err;
+       const char *                            ptr;
+       const char *                            end;
+       uint32_t                                        txtSize, count;
+       const uint8_t * const           serviceLabel    = inContext->serviceLabel;
+       int                                                     nameMatches             = false;
+       
+       require_quiet( inName[ 0 ] >= serviceLabel[ 0 ], exit );
+       if( _memicmp( &inName[ 1 ], &serviceLabel[ 1 ], serviceLabel[ 0 ] ) != 0 ) goto exit;
+       
+       ptr = (const char *) &inName[ 1 + serviceLabel[ 0 ] ];
+       end = (const char *) &inName[ 1 + inName[ 0 ] ];
+       
+       require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+       ++ptr;
+       
+       err = DecimalTextToUInt32( ptr, end, &txtSize, &ptr );
+       require_noerr_quiet( err, exit );
+       require_quiet( txtSize <= UINT16_MAX, exit );
+       
+       require_quiet( ( ptr < end ) && ( *ptr == '-' ), exit );
+       ++ptr;
+       
+       err = DecimalTextToUInt32( ptr, end, &count, &ptr );
+       require_noerr_quiet( err, exit );
+       require_quiet( count <= UINT16_MAX, exit );
+       require_quiet( ptr == end, exit );
+       
+       if( !DomainNameEqual( (const uint8_t *) ptr, (const uint8_t *) "\x04" "_tcp" "\x05" "local" ) ) goto exit;
+       nameMatches = true;
+       
+       if( outTXTSize )        *outTXTSize     = txtSize;
+       if( outCount )          *outCount       = count;
+       
+exit:
+       return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierServiceInstanceNameMatch
+//===========================================================================================================================
+
+static Boolean
+       _MDNSReplierServiceInstanceNameMatch(
+               const MDNSReplierContext *      inContext,
+               const uint8_t *                         inName,
+               unsigned int *                          outIndex,
+               unsigned int *                          outTXTSize,
+               unsigned int *                          outCount )
+{
+       OSStatus                                        err;
+       const uint8_t *                         ptr;
+       const uint8_t *                         end;
+       uint32_t                                        index;
+       unsigned int                            txtSize, count;
+       const uint8_t * const           hostname        = inContext->hostname;
+       int                                                     nameMatches     = false;
+       
+       require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
+       if( _memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
+       
+       ptr = &inName[ 1 + hostname[ 0 ] ];
+       end = &inName[ 1 + inName[ 0 ] ];
+       if( ptr < end )
+       {
+               require_quiet( ( end - ptr ) >= 2, exit );
+               require_quiet( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ), exit );
+               ptr += 2;
+               
+        err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
+               require_noerr_quiet( err, exit );
+               require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
+               
+               require_quiet( ( ( end - ptr ) == 1 ) && ( *ptr == ')' ), exit );
+               ++ptr;
+       }
+       else
+       {
+               index = 1;
+       }
+       
+       if( !_MDNSReplierServiceTypeMatch( inContext, ptr, &txtSize, &count ) ) goto exit;
+       nameMatches = true;
+       
+       if( outIndex )          *outIndex       = index;
+       if( outTXTSize )        *outTXTSize     = txtSize;
+       if( outCount )          *outCount       = count;
+       
+exit:
+       return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierAboutRecordNameMatch
+//===========================================================================================================================
+
+#define _MemIEqual( PTR1, LEN1, PTR2, LEN2 ) \
+       ( ( ( LEN1 ) == ( LEN2 ) ) && ( _memicmp( ( PTR1 ), ( PTR2 ), ( LEN1 ) ) == 0 ) )
+
+static Boolean _MDNSReplierAboutRecordNameMatch( const MDNSReplierContext *inContext, const uint8_t *inName )
+{
+       const uint8_t *                         subname;
+       const uint8_t * const           hostname        = inContext->hostname;
+       int                                                     nameMatches     = false;
+       
+       if( strnicmpx( &inName[ 1 ], inName[ 0 ], "about" ) != 0 ) goto exit;
+       subname = DomainNameGetNextLabel( inName );
+       
+       if( !_MemIEqual( &subname[ 1 ], subname[ 0 ], &hostname[ 1 ], hostname[ 0 ] ) ) goto exit;
+       subname = DomainNameGetNextLabel( subname );
+       
+       if( !DomainNameEqual( subname, kLocalName ) ) goto exit;
+       nameMatches = true;
+       
+exit:
+       return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierHostnameMatch
+//===========================================================================================================================
+
+static Boolean
+       _MDNSReplierHostnameMatch(
+               const MDNSReplierContext *      inContext,
+               const uint8_t *                         inName,
+               unsigned int *                          outIndex )
+{
+       OSStatus                                        err;
+       const uint8_t *                         ptr;
+       const uint8_t *                         end;
+       uint32_t                                        index;
+       const uint8_t * const           hostname        = inContext->hostname;
+       int                                                     nameMatches     = false;
+       
+       require_quiet( inName[ 0 ] >= hostname[ 0 ], exit );
+       if( _memicmp( &inName[ 1 ], &hostname[ 1 ], hostname[ 0 ] ) != 0 ) goto exit;
+       
+       ptr = &inName[ 1 + hostname[ 0 ] ];
+       end = &inName[ 1 + inName[ 0 ] ];
+       if( ptr < end )
+       {
+               require_quiet( *ptr == '-', exit );
+               ++ptr;
+               
+               err = DecimalTextToUInt32( (const char *) ptr, (const char *) end, &index, (const char **) &ptr );
+               require_noerr_quiet( err, exit );
+               require_quiet( ( index >= 2 ) && ( index <= UINT16_MAX ), exit );
+               require_quiet( ptr == end, exit );
+       }
+       else
+       {
+               index = 1;
+       }
+       
+       if( !DomainNameEqual( ptr, kLocalName ) ) goto exit;
+       nameMatches = true;
+       
+       if( outIndex ) *outIndex = index;
+       
+exit:
+       return( nameMatches ? true : false );
+}
+
+//===========================================================================================================================
+//     _MDNSReplierCreateTXTRecord
+//===========================================================================================================================
+
+static OSStatus        _MDNSReplierCreateTXTRecord( const uint8_t *inRecordName, size_t inSize, uint8_t **outTXT )
+{
+       OSStatus                err;
+       uint8_t *               txt;
+       uint8_t *               ptr;
+       size_t                  i, wholeCount, remCount;
+       uint32_t                hash;
+       int                             n;
+       uint8_t                 txtStr[ 16 ];
+       
+       require_action_quiet( inSize > 0, exit, err = kSizeErr );
+       
+       txt = (uint8_t *) malloc( inSize );
+       require_action( txt, exit, err = kNoMemoryErr );
+       
+       hash = _FNV1( inRecordName, DomainNameLength( inRecordName ) );
+       
+       txtStr[ 0 ] = 15;
+       n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
+       check( n == 15 );
+       
+       ptr = txt;
+       wholeCount = inSize / 16;
+       for( i = 0; i < wholeCount; ++i )
+       {
+               memcpy( ptr, txtStr, 16 );
+               ptr += 16;
+       }
+       
+       remCount = inSize % 16;
+       if( remCount > 0 )
+       {
+               txtStr[ 0 ] = (uint8_t)( remCount - 1 );
+               memcpy( ptr, txtStr, remCount );
+               ptr += remCount;
+       }
+       check( ptr == &txt[ inSize ] );
+       
+       *outTXT = txt;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MRResourceRecordCreate
+//===========================================================================================================================
+
+static OSStatus
+       _MRResourceRecordCreate(
+               uint8_t *                       inName,
+               uint16_t                        inType,
+               uint16_t                        inClass,
+               uint32_t                        inTTL,
+               uint16_t                        inRDLength,
+               uint8_t *                       inRData,
+               MRResourceRecord **     outRecord )
+{
+       OSStatus                                err;
+       MRResourceRecord *              obj;
+       
+       obj = (MRResourceRecord *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name               = inName;
+       obj->type               = inType;
+       obj->class              = inClass;
+       obj->ttl                = inTTL;
+       obj->rdlength   = inRDLength;
+       obj->rdata              = inRData;
+       
+       if( inType == kDNSServiceType_SRV )
+       {
+               require_action_quiet( obj->rdlength > sizeof( dns_fixed_fields_srv ), exit, err = kMalformedErr );
+               obj->target = obj->rdata + sizeof( dns_fixed_fields_srv );
+       }
+       
+       *outRecord = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       FreeNullSafe( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MRResourceRecordFree
+//===========================================================================================================================
+
+static void    _MRResourceRecordFree( MRResourceRecord *inRecord )
+{
+       ForgetMem( &inRecord->name );
+       ForgetMem( &inRecord->rdata );
+       free( inRecord );
+}
+
+//===========================================================================================================================
+//     _MRResourceRecordFreeList
+//===========================================================================================================================
+
+static void    _MRResourceRecordFreeList( MRResourceRecord *inList )
+{
+       MRResourceRecord *              record;
+       
+       while( ( record = inList ) != NULL )
+       {
+               inList = record->next;
+               _MRResourceRecordFree( record );
+       }
+}
+
+//===========================================================================================================================
+//     _MRNameOffsetItemCreate
+//===========================================================================================================================
+
+static OSStatus        _MRNameOffsetItemCreate( const uint8_t *inName, uint16_t inOffset, MRNameOffsetItem **outItem )
+{
+       OSStatus                                err;
+       MRNameOffsetItem *              obj;
+       size_t                                  nameLen;
+       
+       require_action_quiet( inOffset <= kDNSCompressionOffsetMax, exit, err = kSizeErr );
+       
+       nameLen = DomainNameLength( inName );
+       obj = (MRNameOffsetItem *) calloc( 1, offsetof( MRNameOffsetItem, name ) + nameLen );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->offset = inOffset;
+       memcpy( obj->name, inName, nameLen );
+       
+       *outItem = obj;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MRNameOffsetItemFree
+//===========================================================================================================================
+
+static void    _MRNameOffsetItemFree( MRNameOffsetItem *inItem )
+{
+       free( inItem );
+}
+
+//===========================================================================================================================
+//     _MRNameOffsetItemFreeList
+//===========================================================================================================================
+
+static void    _MRNameOffsetItemFreeList( MRNameOffsetItem *inList )
+{
+       MRNameOffsetItem *              item;
+       
+       while( ( item = inList ) != NULL )
+       {
+               inList = item->next;
+               _MRNameOffsetItemFree( item );
+       }
+}
+
+//===========================================================================================================================
+//     GAIPerfCmd
+//===========================================================================================================================
+
+#define kGAIPerfStandardTTL            ( 1 * kSecondsPerHour )
+
+typedef struct GAITesterPrivate *              GAITesterRef;
+typedef struct GAITestCase                             GAITestCase;
+
+typedef struct
+{
+       const char *            name;                           // Domain name that was resolved.
+       uint64_t                        connectionTimeUs;       // Time in microseconds that it took to create a DNS-SD connection.
+       uint64_t                        firstTimeUs;            // Time in microseconds that it took to get the first address result.
+       uint64_t                        timeUs;                         // Time in microseconds that it took to get all expected address results.
+       OSStatus                        error;
+       
+}      GAITestItemResult;
+
+typedef void ( *GAITesterStopHandler_f )( void *inContext, OSStatus inError );
+typedef void
+       ( *GAITesterResultsHandler_f )(
+               const char *                            inCaseTitle,
+               NanoTime64                                      inCaseStartTime,
+               NanoTime64                                      inCaseEndTime,
+               const GAITestItemResult *       inResultArray,
+               size_t                                          inResultCount,
+               void *                                          inContext );
+
+typedef unsigned int           GAITestAddrType;
+#define kGAITestAddrType_None          0
+#define kGAITestAddrType_IPv4          ( 1U << 0 )
+#define kGAITestAddrType_IPv6          ( 1U << 1 )
+#define kGAITestAddrType_Both          ( kGAITestAddrType_IPv4 | kGAITestAddrType_IPv6 )
+
+#define GAITestAddrTypeIsValid( X ) \
+       ( ( (X) & kGAITestAddrType_Both ) && ( ( (X) & ~kGAITestAddrType_Both ) == 0 ) )
+
+typedef struct
+{
+       GAITesterRef                    tester;                         // GAI tester object.
+       CFMutableArrayRef               testCaseResults;        // Array of test case results.
+       unsigned int                    iterTimeLimitMs;        // Amount of time to allow each iteration to complete.
+       unsigned int                    callDelayMs;            // Amount of time to wait before calling DNSServiceGetAddrInfo().
+       unsigned int                    serverDelayMs;          // Amount of additional time to have server delay its responses.
+       unsigned int                    defaultIterCount;       // Default test case iteration count.
+       dispatch_source_t               sigIntSource;           // Dispatch source for SIGINT.
+       dispatch_source_t               sigTermSource;          // Dispatch source for SIGTERM.
+       char *                                  outputFilePath;         // File to write test results to. If NULL, then write to stdout.
+       OutputFormatType                outputFormat;           // Format of test results output.
+       Boolean                                 skipPathEval;           // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
+       Boolean                                 badUDPMode;                     // True if the test DNS server is to run in Bad UDP mode.
+       Boolean                                 testFailed;                     // True if at least one test case iteration failed.
+       
+}      GAIPerfContext;
+
+static void            GAIPerfContextFree( GAIPerfContext *inContext );
+static OSStatus        GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext );
+static OSStatus        GAIPerfAddBasicTestCases( GAIPerfContext *inContext );
+static void            GAIPerfTesterStopHandler( void *inContext, OSStatus inError );
+static void
+       GAIPerfResultsHandler(
+               const char *                            inCaseTitle,
+               NanoTime64                                      inCaseStartTime,
+               NanoTime64                                      inCaseEndTime,
+               const GAITestItemResult *       inResultArray,
+               size_t                                          inResultCount,
+               void *                                          inContext );
+static void            GAIPerfSignalHandler( void *inContext );
+
+CFTypeID               GAITesterGetTypeID( void );
+static OSStatus
+       GAITesterCreate(
+               dispatch_queue_t        inQueue,
+               unsigned int            inCallDelayMs,
+               int                                     inServerDelayMs,
+               int                                     inServerDefaultTTL,
+               Boolean                         inSkipPathEvaluation,
+               Boolean                         inBadUDPMode,
+               GAITesterRef *          outTester );
+static void            GAITesterStart( GAITesterRef inTester );
+static void            GAITesterStop( GAITesterRef inTester );
+static OSStatus        GAITesterAddTestCase( GAITesterRef inTester, GAITestCase *inCase );
+static void
+       GAITesterSetStopHandler(
+               GAITesterRef                    inTester,
+               GAITesterStopHandler_f  inEventHandler,
+               void *                                  inEventContext );
+static void
+       GAITesterSetResultsHandler(
+               GAITesterRef                            inTester,
+               GAITesterResultsHandler_f       inResultsHandler,
+               void *                                          inResultsContext );
+
+static OSStatus        GAITestCaseCreate( const char *inTitle, GAITestCase **outCase );
+static void            GAITestCaseFree( GAITestCase *inCase );
+static OSStatus
+       GAITestCaseAddItem(
+               GAITestCase *   inCase,
+               unsigned int    inAliasCount,
+               unsigned int    inAddressCount,
+               int                             inTTL,
+               GAITestAddrType inHasAddrs,
+               GAITestAddrType inWantAddrs,
+               unsigned int    inTimeLimitMs,
+               unsigned int    inItemCount );
+static OSStatus
+       GAITestCaseAddLocalHostItem(
+               GAITestCase *   inCase,
+               GAITestAddrType inWantAddrs,
+               unsigned int    inTimeLimitMs,
+               unsigned int    inItemCount );
+
+static void    GAIPerfCmd( void )
+{
+       OSStatus                                err;
+       GAIPerfContext *                context = NULL;
+       
+       err = CheckRootUser();
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gGAIPerf_CallDelayMs, "call delay (ms)", 0, INT_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gGAIPerf_ServerDelayMs, "server delay (ms)", 0, INT_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gGAIPerf_IterationCount, "iteration count", 1, INT_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gGAIPerf_IterationTimeLimitMs, "iteration time limit (ms)", 0, INT_MAX );
+       require_noerr_quiet( err, exit );
+       
+       context = (GAIPerfContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->testCaseResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( context->testCaseResults, exit, err = kNoMemoryErr );
+       
+       context->iterTimeLimitMs        = (unsigned int) gGAIPerf_IterationTimeLimitMs;
+       context->callDelayMs            = (unsigned int) gGAIPerf_CallDelayMs;
+       context->serverDelayMs          = (unsigned int) gGAIPerf_ServerDelayMs;
+       context->defaultIterCount       = (unsigned int) gGAIPerf_IterationCount;
+       context->skipPathEval           = gGAIPerf_SkipPathEvalulation  ? true : false;
+       context->badUDPMode                     = gGAIPerf_BadUDPMode                   ? true : false;
+       
+       if( gGAIPerf_OutputFilePath )
+       {
+               context->outputFilePath = strdup( gGAIPerf_OutputFilePath );
+               require_action( context->outputFilePath, exit, err = kNoMemoryErr );
+       }
+       
+       err = OutputFormatFromArgString( gGAIPerf_OutputFormat, &context->outputFormat );
+       require_noerr_quiet( err, exit );
+       
+       err = GAITesterCreate( dispatch_get_main_queue(), context->callDelayMs, (int) context->serverDelayMs,
+               kGAIPerfStandardTTL, context->skipPathEval, context->badUDPMode, &context->tester );
+       require_noerr( err, exit );
+       
+       check( gGAIPerf_TestSuite );
+       if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Basic ) == 0 )
+       {
+               err = GAIPerfAddBasicTestCases( context );
+               require_noerr( err, exit );
+       }
+       else if( strcasecmp( gGAIPerf_TestSuite, kGAIPerfTestSuiteName_Advanced ) == 0 )
+       {
+               err = GAIPerfAddAdvancedTestCases( context );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               FPrintF( stderr, "error: Invalid test suite name: %s.\n", gGAIPerf_TestSuite );
+               goto exit;
+       }
+       
+       GAITesterSetStopHandler( context->tester, GAIPerfTesterStopHandler, context );
+       GAITesterSetResultsHandler( context->tester, GAIPerfResultsHandler, context );
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, GAIPerfSignalHandler, context, &context->sigIntSource );
+       require_noerr( err, exit );
+       dispatch_resume( context->sigIntSource );
+       
+       signal( SIGTERM, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGTERM, GAIPerfSignalHandler, context, &context->sigTermSource );
+       require_noerr( err, exit );
+       dispatch_resume( context->sigTermSource );
+       
+       GAITesterStart( context->tester );
+       dispatch_main();
+       
+exit:
+       if( context ) GAIPerfContextFree( context );
+       exit( 1 );
+}
+
+//===========================================================================================================================
+//     GAIPerfContextFree
+//===========================================================================================================================
+
+static void    GAIPerfContextFree( GAIPerfContext *inContext )
+{
+       ForgetCF( &inContext->tester );
+       ForgetCF( &inContext->testCaseResults );
+       ForgetMem( &inContext->outputFilePath );
+       dispatch_source_forget( &inContext->sigIntSource );
+       dispatch_source_forget( &inContext->sigTermSource );
+       free( inContext );
+}
+
+//===========================================================================================================================
+//     GAIPerfAddAdvancedTestCases
+//===========================================================================================================================
+
+#define kTestCaseTitleBufferSize               128
+
+static void
+       _GAIPerfWriteTestCaseTitle(
+               char                    inBuffer[ kTestCaseTitleBufferSize ],
+               unsigned int    inCNAMERecordCount,
+               unsigned int    inARecordCount,
+               unsigned int    inAAAARecordCount,
+               GAITestAddrType inRequested,
+               unsigned int    inIterationCount,
+               Boolean                 inIterationsAreUnique );
+static void
+       _GAIPerfWriteLocalHostTestCaseTitle(
+               char                    inBuffer[ kTestCaseTitleBufferSize ],
+               GAITestAddrType inRequested,
+               unsigned int    inIterationCount );
+
+#define kGAIPerfAdvancedTestSuite_MaxAliasCount                4
+#define kGAIPerfAdvancedTestSuite_MaxAddrCount         8
+
+static OSStatus        GAIPerfAddAdvancedTestCases( GAIPerfContext *inContext )
+{
+       OSStatus                        err;
+       unsigned int            aliasCount, addressCount, i;
+       GAITestCase *           testCase = NULL;
+       char                            title[ kTestCaseTitleBufferSize ];
+       
+       aliasCount = 0;
+       while( aliasCount <= kGAIPerfAdvancedTestSuite_MaxAliasCount )
+       {
+               for( addressCount = 1; addressCount <= kGAIPerfAdvancedTestSuite_MaxAddrCount; addressCount *= 2 )
+               {
+                       // Add a test case to resolve a domain name with
+                       //
+                       //     <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
+                       //
+                       // to its IPv4 and IPv6 addresses. Each iteration resolves a unique instance of such a domain name, which
+                       // requires server queries.
+                       
+                       _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
+                               inContext->defaultIterCount, true );
+                       
+                       err = GAITestCaseCreate( title, &testCase );
+                       require_noerr( err, exit );
+                       
+                       for( i = 0; i < inContext->defaultIterCount; ++i )
+                       {
+                               err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
+                                       kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs, 1 );
+                               require_noerr( err, exit );
+                       }
+                       
+                       err = GAITesterAddTestCase( inContext->tester, testCase );
+                       require_noerr( err, exit );
+                       testCase = NULL;
+                       
+                       // Add a test case to resolve a domain name with
+                       //
+                       //     <aliasCount> CNAME records, <addressCount> A records, and <addressCount> AAAA records
+                       //
+                       // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique domain name, which requires a server
+                       // query. The subsequent iterations resolve the same domain name as the preliminary iteration, which should
+                       // ideally require no server queries, i.e., the results should come from the cache.
+                       
+                       _GAIPerfWriteTestCaseTitle( title, aliasCount, addressCount, addressCount, kGAITestAddrType_Both,
+                               inContext->defaultIterCount, false );
+                       
+                       err = GAITestCaseCreate( title, &testCase );
+                       require_noerr( err, exit );
+                       
+                       err = GAITestCaseAddItem( testCase, aliasCount, addressCount, kGAIPerfStandardTTL,
+                               kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs, inContext->defaultIterCount + 1 );
+                       require_noerr( err, exit );
+                       
+                       err = GAITesterAddTestCase( inContext->tester, testCase );
+                       require_noerr( err, exit );
+                       testCase = NULL;
+               }
+               
+               aliasCount = ( aliasCount == 0 ) ? 1 : ( 2 * aliasCount );
+       }
+       
+       // Finally, add a test case to resolve localhost to its IPv4 and IPv6 addresses.
+       
+       _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
+       
+       err = GAITestCaseCreate( title, &testCase );
+       require_noerr( err, exit );
+       
+       err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, inContext->iterTimeLimitMs,
+               inContext->defaultIterCount );
+       require_noerr( err, exit );
+       
+       err = GAITesterAddTestCase( inContext->tester, testCase );
+       require_noerr( err, exit );
+       testCase = NULL;
+       
+exit:
+       if( testCase ) GAITestCaseFree( testCase );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _GAIPerfWriteTestCaseTitle
+//===========================================================================================================================
+
+#define GAITestAddrTypeToRequestKeyValue( X ) (                                \
+       ( (X) == kGAITestAddrType_Both ) ? "ipv4\\,ipv6"        :       \
+       ( (X) == kGAITestAddrType_IPv4 ) ? "ipv4"                       :       \
+       ( (X) == kGAITestAddrType_IPv6 ) ? "ipv6"                       :       \
+                                                                          "" )
+
+static void
+       _GAIPerfWriteTestCaseTitle(
+               char                    inBuffer[ kTestCaseTitleBufferSize ],
+               unsigned int    inCNAMERecordCount,
+               unsigned int    inARecordCount,
+               unsigned int    inAAAARecordCount,
+               GAITestAddrType inRequested,
+               unsigned int    inIterationCount,
+               Boolean                 inIterationsAreUnique )
+{
+       SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=dynamic,cname=%u,a=%u,aaaa=%u,req=%s,iterations=%u%?s",
+               inCNAMERecordCount, inARecordCount, inAAAARecordCount, GAITestAddrTypeToRequestKeyValue( inRequested ),
+               inIterationCount, inIterationsAreUnique, ",unique" );
+}
+
+//===========================================================================================================================
+//     _GAIPerfWriteLocalHostTestCaseTitle
+//===========================================================================================================================
+
+static void
+       _GAIPerfWriteLocalHostTestCaseTitle(
+               char                    inBuffer[ kTestCaseTitleBufferSize ],
+               GAITestAddrType inRequested,
+               unsigned int    inIterationCount )
+{
+       SNPrintF( inBuffer, kTestCaseTitleBufferSize, "name=localhost,req=%s,iterations=%u",
+               GAITestAddrTypeToRequestKeyValue( inRequested ), inIterationCount );
+}
+
+//===========================================================================================================================
+//     GAIPerfAddBasicTestCases
+//===========================================================================================================================
+
+#define kGAIPerfBasicTestSuite_AliasCount              2
+#define kGAIPerfBasicTestSuite_AddrCount               4
+
+static OSStatus        GAIPerfAddBasicTestCases( GAIPerfContext *inContext )
+{
+       OSStatus                        err;
+       GAITestCase *           testCase = NULL;
+       char                            title[ kTestCaseTitleBufferSize ];
+       unsigned int            i;
+       
+       // Test Case #1:
+       // Resolve a domain name with
+       //
+       //     2 CNAME records, 4 A records, and 4 AAAA records
+       //
+       // to its IPv4 and IPv6 addresses. Each of the iterations resolves a unique domain name, which requires server
+       // queries.
+       
+       _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
+               kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
+               inContext->defaultIterCount, true );
+       
+       err = GAITestCaseCreate( title, &testCase );
+       require_noerr( err, exit );
+       
+       for( i = 0; i < inContext->defaultIterCount; ++i )
+       {
+               err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
+                       kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs, 1 );
+               require_noerr( err, exit );
+       }
+       
+       err = GAITesterAddTestCase( inContext->tester, testCase );
+       require_noerr( err, exit );
+       testCase = NULL;
+       
+       // Test Case #2:
+       // Resolve a domain name with
+       //
+       //     2 CNAME records, 4 A records, and 4 AAAA records
+       //
+       // to its IPv4 and IPv6 addresses. A preliminary iteration resolves a unique instance of such a domain name, which
+       // requires server queries. Each of the subsequent iterations resolves the same domain name as the preliminary
+       // iteration, which should ideally require no additional server queries, i.e., the results should come from the cache.
+       
+       _GAIPerfWriteTestCaseTitle( title, kGAIPerfBasicTestSuite_AliasCount,
+               kGAIPerfBasicTestSuite_AddrCount, kGAIPerfBasicTestSuite_AddrCount, kGAITestAddrType_Both,
+               inContext->defaultIterCount, false );
+       
+       err = GAITestCaseCreate( title, &testCase );
+       require_noerr( err, exit );
+       
+       err = GAITestCaseAddItem( testCase, kGAIPerfBasicTestSuite_AliasCount, kGAIPerfBasicTestSuite_AddrCount,
+               kGAIPerfStandardTTL, kGAITestAddrType_Both, kGAITestAddrType_Both, inContext->iterTimeLimitMs,
+               inContext->defaultIterCount + 1 );
+       require_noerr( err, exit );
+       
+       err = GAITesterAddTestCase( inContext->tester, testCase );
+       require_noerr( err, exit );
+       testCase = NULL;
+       
+       // Test Case #3:
+       // Each iteration resolves localhost to its IPv4 and IPv6 addresses.
+       
+       _GAIPerfWriteLocalHostTestCaseTitle( title, kGAITestAddrType_Both, inContext->defaultIterCount );
+       
+       err = GAITestCaseCreate( title, &testCase );
+       require_noerr( err, exit );
+       
+       err = GAITestCaseAddLocalHostItem( testCase, kGAITestAddrType_Both, inContext->iterTimeLimitMs,
+               inContext->defaultIterCount );
+       require_noerr( err, exit );
+       
+       err = GAITesterAddTestCase( inContext->tester, testCase );
+       require_noerr( err, exit );
+       testCase = NULL;
+       
+exit:
+       if( testCase ) GAITestCaseFree( testCase );
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAIPerfTesterStopHandler
+//===========================================================================================================================
+
+#define kGAIPerfResultsKey_Info                                CFSTR( "info" )
+#define kGAIPerfResultsKey_TestCases           CFSTR( "testCases" )
+#define kGAIPerfResultsKey_Success                     CFSTR( "success" )
+
+#define kGAIPerfInfoKey_CallDelay                      CFSTR( "callDelayMs" )
+#define kGAIPerfInfoKey_ServerDelay                    CFSTR( "serverDelayMs" )
+#define kGAIPerfInfoKey_SkippedPathEval                CFSTR( "skippedPathEval" )
+#define kGAIPerfInfoKey_UsedBadUDPMode         CFSTR( "usedBadUPDMode" )
+
+static void    GAIPerfTesterStopHandler( void *inContext, OSStatus inError )
+{
+       OSStatus                                        err;
+       GAIPerfContext * const          context = (GAIPerfContext *) inContext;
+       CFPropertyListRef                       plist;
+       int                                                     exitCode;
+       
+       err = inError;
+       require_noerr_quiet( err, exit );
+       
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+               "{"
+                       "%kO="                  // info
+                       "{"
+                               "%kO=%lli"      // callDelayMs
+                               "%kO=%lli"      // serverDelayMs
+                               "%kO=%b"        // skippedPathEval
+                               "%kO=%b"        // usedBadUPDMode
+                       "}"
+                       "%kO=%O"                // testCases
+                       "%kO=%b"                // success
+               "}",
+               kGAIPerfResultsKey_Info,
+               kGAIPerfInfoKey_CallDelay,                      (int64_t) context->callDelayMs,
+               kGAIPerfInfoKey_ServerDelay,            (int64_t) context->serverDelayMs,
+               kGAIPerfInfoKey_SkippedPathEval,        context->skipPathEval,
+               kGAIPerfInfoKey_UsedBadUDPMode,         context->badUDPMode,
+               kGAIPerfResultsKey_TestCases,           context->testCaseResults,
+               kGAIPerfResultsKey_Success,                     !context->testFailed );
+       require_noerr( err, exit );
+       
+       err = OutputPropertyList( plist, context->outputFormat, context->outputFilePath );
+       CFRelease( plist );
+       require_noerr( err, exit );
+       
+exit:
+       exitCode = err ? 1 : ( context->testFailed ? 2 : 0 );
+       GAIPerfContextFree( context );
+       exit( exitCode );
+}
+
+//===========================================================================================================================
+//     GAIPerfResultsHandler
+//===========================================================================================================================
+
+// Keys for test case dictionary
+
+#define kGAIPerfTestCaseKey_Title                              CFSTR( "title" )
+#define kGAIPerfTestCaseKey_StartTime                  CFSTR( "startTime" )
+#define kGAIPerfTestCaseKey_EndTime                            CFSTR( "endTime" )
+#define kGAIPerfTestCaseKey_Results                            CFSTR( "results" )
+#define kGAIPerfTestCaseKey_FirstStats                 CFSTR( "firstStats" )
+#define kGAIPerfTestCaseKey_ConnectionStats            CFSTR( "connectionStats" )
+#define kGAIPerfTestCaseKey_Stats                              CFSTR( "stats" )
+
+// Keys for test case results array entry dictionaries
+
+#define kGAIPerfTestCaseResultKey_Name                                 CFSTR( "name" )
+#define kGAIPerfTestCaseResultKey_ConnectionTime               CFSTR( "connectionTimeUs" )
+#define kGAIPerfTestCaseResultKey_FirstTime                            CFSTR( "firstTimeUs" )
+#define kGAIPerfTestCaseResultKey_Time                                 CFSTR( "timeUs" )
+
+// Keys for test case stats dictionaries
+
+#define kGAIPerfTestCaseStatsKey_Count         CFSTR( "count" )
+#define kGAIPerfTestCaseStatsKey_Min           CFSTR( "min" )
+#define kGAIPerfTestCaseStatsKey_Max           CFSTR( "max" )
+#define kGAIPerfTestCaseStatsKey_Mean          CFSTR( "mean" )
+#define kGAIPerfTestCaseStatsKey_StdDev                CFSTR( "sd" )
+
+typedef struct
+{
+       double          min;
+       double          max;
+       double          mean;
+       double          stdDev;
+       
+}      GAIPerfStats;
+
+#define GAIPerfStatsInit( X ) \
+       do { (X)->min = DBL_MAX; (X)->max = DBL_MIN; (X)->mean = 0.0; (X)->stdDev = 0.0; } while( 0 )
+
+static void
+       GAIPerfResultsHandler(
+               const char *                            inCaseTitle,
+               NanoTime64                                      inCaseStartTime,
+               NanoTime64                                      inCaseEndTime,
+               const GAITestItemResult *       inResultArray,
+               size_t                                          inResultCount,
+               void *                                          inContext )
+{
+       OSStatus                                                err;
+       GAIPerfContext * const                  context = (GAIPerfContext *) inContext;
+       int                                                             namesAreDynamic, namesAreUnique;
+       const char *                                    ptr;
+       size_t                                                  count, startIndex;
+       CFMutableArrayRef                               results = NULL;
+       GAIPerfStats                                    stats, firstStats, connStats;
+       double                                                  sum, firstSum, connSum;
+       size_t                                                  keyValueLen, i;
+       char                                                    keyValue[ 16 ]; // Size must be at least strlen( "name=dynamic" ) + 1 bytes.
+       char                                                    startTime[ 32 ];
+       char                                                    endTime[ 32 ];
+       const GAITestItemResult *               result;
+       
+       // If this test case resolves the same "d.test." name in each iteration (title contains the "name=dynamic" key-value
+       // pair, but not the "unique" key), then don't count the first iteration, whose purpose is to populate the cache with
+       // the domain name's CNAME, A, and AAAA records.
+       
+       namesAreDynamic = false;
+       namesAreUnique  = false;
+       ptr = inCaseTitle;
+       while( _ParseQuotedEscapedString( ptr, NULL, ",", keyValue, sizeof( keyValue ), &keyValueLen, NULL, &ptr ) )
+       {
+               if( strnicmpx( keyValue, keyValueLen, "name=dynamic" ) == 0 )
+               {
+                       namesAreDynamic = true;
+               }
+               else if( strnicmpx( keyValue, keyValueLen, "unique" ) == 0 )
+               {
+                       namesAreUnique = true;
+               }
+               if( namesAreDynamic && namesAreUnique ) break;
+       }
+       
+       startIndex = ( ( inResultCount > 0 ) && namesAreDynamic && !namesAreUnique ) ? 1 : 0;
+       results = CFArrayCreateMutable( NULL, (CFIndex)( inResultCount - startIndex ), &kCFTypeArrayCallBacks );
+       require_action( results, exit, err = kNoMemoryErr );
+       
+       GAIPerfStatsInit( &stats );
+       GAIPerfStatsInit( &firstStats );
+       GAIPerfStatsInit( &connStats );
+       
+       sum                     = 0.0;
+       firstSum        = 0.0;
+       connSum         = 0.0;
+       count           = 0;
+       for( i = startIndex; i < inResultCount; ++i )
+       {
+               double          value;
+               
+               result = &inResultArray[ i ];
+               
+               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, results,
+                       "{"
+                               "%kO=%s"        // name
+                               "%kO=%lli"      // connectionTimeUs
+                               "%kO=%lli"      // firstTimeUs
+                               "%kO=%lli"      // timeUs
+                               "%kO=%lli"      // error
+                       "}",
+                       kGAIPerfTestCaseResultKey_Name,                         result->name,
+                       kGAIPerfTestCaseResultKey_ConnectionTime,       (int64_t) result->connectionTimeUs,
+                       kGAIPerfTestCaseResultKey_FirstTime,            (int64_t) result->firstTimeUs,
+                       kGAIPerfTestCaseResultKey_Time,                         (int64_t) result->timeUs,
+                       CFSTR( "error" ),                                                       (int64_t) result->error );
+               require_noerr( err, exit );
+               
+               if( !result->error )
+               {
+                       value = (double) result->timeUs;
+                       if( value < stats.min ) stats.min = value;
+                       if( value > stats.max ) stats.max = value;
+                       sum += value;
+                       
+                       value = (double) result->firstTimeUs;
+                       if( value < firstStats.min ) firstStats.min = value;
+                       if( value > firstStats.max ) firstStats.max = value;
+                       firstSum += value;
+                       
+                       value = (double) result->connectionTimeUs;
+                       if( value < connStats.min ) connStats.min = value;
+                       if( value > connStats.max ) connStats.max = value;
+                       connSum += value;
+                       
+                       ++count;
+               }
+               else
+               {
+                       context->testFailed = true;
+               }
+       }
+       
+       if( count > 0 )
+       {
+               stats.mean              = sum      / count;
+               firstStats.mean = firstSum / count;
+               connStats.mean  = connSum  / count;
+               
+               sum                     = 0.0;
+               firstSum        = 0.0;
+               connSum         = 0.0;
+               for( i = startIndex; i < inResultCount; ++i )
+               {
+                       double          diff;
+                       
+                       result = &inResultArray[ i ];
+                       if( result->error ) continue;
+                       
+                       diff             = stats.mean - (double) result->timeUs;
+                       sum                     += ( diff * diff );
+                       
+                       diff             = firstStats.mean - (double) result->firstTimeUs;
+                       firstSum        += ( diff * diff );
+                       
+                       diff             = connStats.mean - (double) result->connectionTimeUs;
+                       connSum         += ( diff * diff );
+               }
+               stats.stdDev            = sqrt( sum      / count );
+               firstStats.stdDev       = sqrt( firstSum / count );
+               connStats.stdDev        = sqrt( connSum  / count );
+       }
+       
+       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->testCaseResults,
+               "{"
+                       "%kO=%s"
+                       "%kO=%s"
+                       "%kO=%s"
+                       "%kO=%O"
+                       "%kO="
+                       "{"
+                               "%kO=%lli"
+                               "%kO=%f"
+                               "%kO=%f"
+                               "%kO=%f"
+                               "%kO=%f"
+                       "}"
+                       "%kO="
+                       "{"
+                               "%kO=%lli"
+                               "%kO=%f"
+                               "%kO=%f"
+                               "%kO=%f"
+                               "%kO=%f"
+                       "}"
+                       "%kO="
+                       "{"
+                               "%kO=%lli"
+                               "%kO=%f"
+                               "%kO=%f"
+                               "%kO=%f"
+                               "%kO=%f"
+                       "}"
+               "}",
+               kGAIPerfTestCaseKey_Title,                      inCaseTitle,
+               kGAIPerfTestCaseKey_StartTime,          _NanoTime64ToTimestamp( inCaseStartTime, startTime, sizeof( startTime ) ),
+               kGAIPerfTestCaseKey_EndTime,            _NanoTime64ToTimestamp( inCaseEndTime, endTime, sizeof( endTime ) ),
+               kGAIPerfTestCaseKey_Results,            results,
+               kGAIPerfTestCaseKey_Stats,
+               kGAIPerfTestCaseStatsKey_Count,         (int64_t) count,
+               kGAIPerfTestCaseStatsKey_Min,           stats.min,
+               kGAIPerfTestCaseStatsKey_Max,           stats.max,
+               kGAIPerfTestCaseStatsKey_Mean,          stats.mean,
+               kGAIPerfTestCaseStatsKey_StdDev,        stats.stdDev,
+               kGAIPerfTestCaseKey_FirstStats,
+               kGAIPerfTestCaseStatsKey_Count,         (int64_t) count,
+               kGAIPerfTestCaseStatsKey_Min,           firstStats.min,
+               kGAIPerfTestCaseStatsKey_Max,           firstStats.max,
+               kGAIPerfTestCaseStatsKey_Mean,          firstStats.mean,
+               kGAIPerfTestCaseStatsKey_StdDev,        firstStats.stdDev,
+               kGAIPerfTestCaseKey_ConnectionStats,
+               kGAIPerfTestCaseStatsKey_Count,         (int64_t) count,
+               kGAIPerfTestCaseStatsKey_Min,           connStats.min,
+               kGAIPerfTestCaseStatsKey_Max,           connStats.max,
+               kGAIPerfTestCaseStatsKey_Mean,          connStats.mean,
+               kGAIPerfTestCaseStatsKey_StdDev,        connStats.stdDev );
+       require_noerr( err, exit );
+       
+exit:
+       CFReleaseNullSafe( results );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     GAIPerfSignalHandler
+//===========================================================================================================================
+
+static void    GAIPerfSignalHandler( void *inContext )
+{
+       GAIPerfContext * const          context = (GAIPerfContext *) inContext;
+       
+       if( !context->tester ) exit( 1 );
+       GAITesterStop( context->tester );
+       context->tester = NULL;
+}
+
+//===========================================================================================================================
+//     GAITesterCreate
+//===========================================================================================================================
+
+// A character set of lower-case alphabet characters and digits and a string length of six allows for 36^6 = 2,176,782,336
+// possible strings to use in the Tag label.
+
+#define kGAITesterTagStringLen         6
+
+typedef struct GAITestItem             GAITestItem;
+struct GAITestItem
+{
+       GAITestItem *           next;                           // Next test item in list.
+       char *                          name;                           // Domain name to resolve.
+       uint64_t                        connectionTimeUs;       // Time in microseconds that it took to create a DNS-SD connection.
+       uint64_t                        firstTimeUs;            // Time in microseconds that it took to get the first address result.
+       uint64_t                        timeUs;                         // Time in microseconds that it took to get all expected address results.
+       unsigned int            addressCount;           // Address count of the domain name, i.e., the Count label argument.
+       OSStatus                        error;                          // Current status/error.
+       unsigned int            timeLimitMs;            // Time limit in milliseconds for the test item's completion.
+       Boolean                         hasV4;                          // True if the domain name has one or more IPv4 addresses.
+       Boolean                         hasV6;                          // True if the domain name has one or more IPv6 addresses.
+       Boolean                         wantV4;                         // True if DNSServiceGetAddrInfo() should be called to get IPv4 addresses.
+       Boolean                         wantV6;                         // True if DNSServiceGetAddrInfo() should be called to get IPv6 addresses.
+};
+
+struct GAITestCase
+{
+       GAITestCase *           next;           // Next test case in list.
+       GAITestItem *           itemList;       // List of test items.
+       char *                          title;          // Title of the test case.
+};
+
+struct GAITesterPrivate
+{
+       CFRuntimeBase                                   base;                           // CF object base.
+       dispatch_queue_t                                queue;                          // Serial work queue.
+       DNSServiceRef                                   connection;                     // Reference to the shared DNS-SD connection.
+       DNSServiceRef                                   getAddrInfo;            // Reference to the current DNSServiceGetAddrInfo operation.
+       GAITestCase *                                   caseList;                       // List of test cases.
+       GAITestCase *                                   currentCase;            // Pointer to the current test case.
+       GAITestItem *                                   currentItem;            // Pointer to the current test item.
+       NanoTime64                                              caseStartTime;          // Start time of current test case in Unix time as nanoseconds.
+       NanoTime64                                              caseEndTime;            // End time of current test case in Unix time as nanoseconds.
+       unsigned int                                    callDelayMs;            // Amount of time to wait before calling DNSServiceGetAddrInfo().
+       Boolean                                                 skipPathEval;           // True if DNSServiceGetAddrInfo() path evaluation is to be skipped.
+       Boolean                                                 stopped;                        // True if the tester has been stopped.
+       Boolean                                                 badUDPMode;                     // True if the test DNS server is to run in Bad UDP mode.
+       dispatch_source_t                               timer;                          // Timer for enforcing a test item's time limit.
+       pcap_t *                                                pcap;                           // Captures traffic between mDNSResponder and test DNS server.
+       pid_t                                                   serverPID;                      // PID of the test DNS server.
+       int                                                             serverDelayMs;          // Additional time to have the server delay its responses by.
+       int                                                             serverDefaultTTL;       // Default TTL for the server's records.
+       GAITesterStopHandler_f                  stopHandler;            // User's stop handler.
+       void *                                                  stopContext;            // User's event handler context.
+       GAITesterResultsHandler_f               resultsHandler;         // User's results handler.
+       void *                                                  resultsContext;         // User's results handler context.
+       
+       // Variables for current test item.
+       
+       uint64_t                                                bitmapV4;               // Bitmap of IPv4 results that have yet to be received.
+       uint64_t                                                bitmapV6;               // Bitmap of IPv6 results that have yet to be received.
+       uint64_t                                                startTicks;             // Start ticks of DNSServiceGetAddrInfo().
+       uint64_t                                                connTicks;              // Ticks when the connection was created.
+       uint64_t                                                firstTicks;             // Ticks when the first DNSServiceGetAddrInfo result was received.
+       uint64_t                                                endTicks;               // Ticks when the last DNSServiceGetAddrInfo result was received.
+       Boolean                                                 gotFirstResult; // True if the first result has been received.
+};
+
+CF_CLASS_DEFINE( GAITester );
+
+static void            _GAITesterStartNextTest( GAITesterRef inTester );
+static OSStatus        _GAITesterCreatePacketCapture( pcap_t **outPCap );
+static void            _GAITesterFirstGAITimeout( void *inContext );
+static void            _GAITesterTimeout( void *inContext );
+static void DNSSD_API
+       _GAITesterFirstGAICallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static void DNSSD_API
+       _GAITesterGetAddrInfoCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static void            _GAITesterCompleteCurrentTest( GAITesterRef inTester, OSStatus inError );
+
+#define ForgetPacketCapture( X )               ForgetCustom( X, pcap_close )
+
+static OSStatus
+       GAITestItemCreate(
+               const char *    inName,
+               unsigned int    inAddressCount,
+               GAITestAddrType inHasAddrs,
+               GAITestAddrType inWantAddrs,
+               unsigned int    inTimeLimitMs,
+               GAITestItem **  outItem );
+static OSStatus        GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem );
+static void            GAITestItemFree( GAITestItem *inItem );
+
+static OSStatus
+       GAITesterCreate(
+               dispatch_queue_t        inQueue,
+               unsigned int            inCallDelayMs,
+               int                                     inServerDelayMs,
+               int                                     inServerDefaultTTL,
+               Boolean                         inSkipPathEvaluation,
+               Boolean                         inBadUDPMode,
+               GAITesterRef *          outTester )
+{
+       OSStatus                        err;
+       GAITesterRef            obj = NULL;
+       
+       CF_OBJECT_CREATE( GAITester, obj, err, exit );
+       
+       ReplaceDispatchQueue( &obj->queue, inQueue );
+       obj->callDelayMs                = inCallDelayMs;
+       obj->serverPID                  = -1;
+       obj->serverDelayMs              = inServerDelayMs;
+       obj->serverDefaultTTL   = inServerDefaultTTL;
+       obj->skipPathEval               = inSkipPathEvaluation;
+       obj->badUDPMode                 = inBadUDPMode;
+       
+       *outTester = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       CFReleaseNullSafe( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _GAITesterFinalize
+//===========================================================================================================================
+
+static void    _GAITesterFinalize( CFTypeRef inObj )
+{
+       GAITesterRef const              me = (GAITesterRef) inObj;
+       GAITestCase *                   testCase;
+       
+       check( !me->getAddrInfo );
+       check( !me->connection );
+       check( !me->timer );
+       dispatch_forget( &me->queue );
+       while( ( testCase = me->caseList ) != NULL )
+       {
+               me->caseList = testCase->next;
+               GAITestCaseFree( testCase );
+       }
+}
+
+//===========================================================================================================================
+//     GAITesterStart
+//===========================================================================================================================
+
+static void    _GAITesterStart( void *inContext );
+static void    _GAITesterStop( GAITesterRef me, OSStatus inError );
+
+static void    GAITesterStart( GAITesterRef me )
+{
+       CFRetain( me );
+       dispatch_async_f( me->queue, me, _GAITesterStart );
+}
+
+#define kGAITesterFirstGAITimeoutSecs          4
+
+static void    _GAITesterStart( void *inContext )
+{
+       OSStatus                                err;
+       GAITesterRef const              me = (GAITesterRef) inContext;
+       DNSServiceFlags                 flags;
+       char                                    name[ 64 ];
+       char                                    tag[ kGAITesterTagStringLen + 1 ];
+       
+       err = SpawnCommand( &me->serverPID, "dnssdutil server --loopback --follow %lld%?s%?d%?s%?d%?s",
+               (int64_t) getpid(),
+               me->serverDefaultTTL >= 0,      " --defaultTTL ",
+               me->serverDefaultTTL >= 0,      me->serverDefaultTTL,
+               me->serverDelayMs    >= 0,      " --responseDelay ",
+               me->serverDelayMs    >= 0,      me->serverDelayMs,
+               me->badUDPMode,                         " --badUDPMode" );
+       require_noerr_quiet( err, exit );
+       
+       SNPrintF( name, sizeof( name ), "tag-gaitester-probe-%s.ipv4.d.test",
+               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+       
+       flags = 0;
+       if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
+       
+       err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, kDNSServiceProtocol_IPv4, name,
+               _GAITesterFirstGAICallback, me );
+       require_noerr( err, exit );
+       
+       err = DNSServiceSetDispatchQueue( me->getAddrInfo, me->queue );
+       require_noerr( err, exit );
+       
+       err = DispatchTimerOneShotCreate( dispatch_time_seconds( kGAITesterFirstGAITimeoutSecs ),
+               UINT64_C_safe( kGAITesterFirstGAITimeoutSecs ) * kNanosecondsPerSecond / 10, me->queue,
+               _GAITesterFirstGAITimeout, me, &me->timer );
+       require_noerr( err, exit );
+       dispatch_resume( me->timer );
+       
+exit:
+       if( err ) _GAITesterStop( me, err );
+}
+
+//===========================================================================================================================
+//     GAITesterStop
+//===========================================================================================================================
+
+static void    _GAITesterUserStop( void *inContext );
+
+static void    GAITesterStop( GAITesterRef me )
+{
+       CFRetain( me );
+       dispatch_async_f( me->queue, me, _GAITesterUserStop );
+}
+
+static void    _GAITesterUserStop( void *inContext )
+{
+       GAITesterRef const              me = (GAITesterRef) inContext;
+       
+       _GAITesterStop( me, kCanceledErr );
+       CFRelease( me );
+}
+
+static void    _GAITesterStop( GAITesterRef me, OSStatus inError )
+{
+       OSStatus                err;
+       
+       ForgetPacketCapture( &me->pcap );
+       dispatch_source_forget( &me->timer );
+       DNSServiceForget( &me->getAddrInfo );
+       DNSServiceForget( &me->connection );
+       if( me->serverPID != -1 )
+       {
+               err = kill( me->serverPID, SIGTERM );
+               err = map_global_noerr_errno( err );
+               check_noerr( err );
+               me->serverPID = -1;
+       }
+       
+       if( !me->stopped )
+       {
+               me->stopped = true;
+               if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
+               CFRelease( me );
+       }
+}
+
+//===========================================================================================================================
+//     GAITesterAddTestCase
+//===========================================================================================================================
+
+static OSStatus        GAITesterAddTestCase( GAITesterRef me, GAITestCase *inCase )
+{
+       OSStatus                        err;
+       GAITestCase **          ptr;
+       
+       require_action_quiet( inCase->itemList, exit, err = kCountErr );
+       
+       for( ptr = &me->caseList; *ptr; ptr = &( *ptr )->next ) {}
+       *ptr = inCase;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAITesterSetStopHandler
+//===========================================================================================================================
+
+static void    GAITesterSetStopHandler( GAITesterRef me, GAITesterStopHandler_f inStopHandler, void *inStopContext )
+{
+       me->stopHandler = inStopHandler;
+       me->stopContext = inStopContext;
+}
+
+//===========================================================================================================================
+//     GAITesterSetResultsHandler
+//===========================================================================================================================
+
+static void    GAITesterSetResultsHandler( GAITesterRef me, GAITesterResultsHandler_f inResultsHandler, void *inResultsContext )
+{
+       me->resultsHandler = inResultsHandler;
+       me->resultsContext = inResultsContext;
+}
+
+//===========================================================================================================================
+//     _GAITesterStartNextTest
+//===========================================================================================================================
+
+static void    _GAITesterStartNextTest( GAITesterRef me )
+{
+       OSStatus                                err;
+       GAITestItem *                   item;
+       DNSServiceFlags                 flags;
+       DNSServiceProtocol              protocols;
+       int                                             done = false;
+       
+       if( me->currentItem ) me->currentItem = me->currentItem->next;
+       
+       if( !me->currentItem )
+       {
+               if( me->currentCase )
+               {
+                       // No more test items means that the current test case has completed.
+                       
+                       me->caseEndTime = NanoTimeGetCurrent();
+                       
+                       if( me->resultsHandler )
+                       {
+                               size_t                                  resultCount, i;
+                               GAITestItemResult *             resultArray;
+                               
+                               resultCount     = 0;
+                               for( item = me->currentCase->itemList; item; item = item->next ) ++resultCount;
+                               check( resultCount > 0 );
+                               
+                               resultArray = (GAITestItemResult *) calloc( resultCount, sizeof( *resultArray ) );
+                               require_action( resultArray, exit, err = kNoMemoryErr );
+                               
+                               item = me->currentCase->itemList;
+                               for( i = 0; i < resultCount; ++i )
+                               {
+                                       resultArray[ i ].name                           = item->name;
+                                       resultArray[ i ].connectionTimeUs       = item->connectionTimeUs;
+                                       resultArray[ i ].firstTimeUs            = item->firstTimeUs;
+                                       resultArray[ i ].timeUs                         = item->timeUs;
+                                       resultArray[ i ].error                          = item->error;
+                                       item = item->next;
+                               }
+                               me->resultsHandler( me->currentCase->title, me->caseStartTime, me->caseEndTime, resultArray, resultCount,
+                                       me->resultsContext );
+                               ForgetMem( &resultArray );
+                       }
+                       
+                       me->currentCase = me->currentCase->next;
+                       if( !me->currentCase )
+                       {
+                               done = true;
+                               err = kNoErr;
+                               goto exit;
+                       }
+               }
+               else
+               {
+                       me->currentCase = me->caseList;
+               }
+               require_action_quiet( me->currentCase->itemList, exit, err = kInternalErr );
+               me->currentItem = me->currentCase->itemList;
+       }
+       
+       item = me->currentItem;
+       check( ( item->addressCount >= 1 ) && ( item->addressCount <= 64 ) );
+       
+       if(      !item->wantV4 )                        me->bitmapV4 = 0;
+       else if( !item->hasV4 )                         me->bitmapV4 = 1;
+       else if(  item->addressCount < 64 )     me->bitmapV4 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
+       else                                                            me->bitmapV4 =  ~UINT64_C( 0 );
+       
+       if(      !item->wantV6 )                        me->bitmapV6 = 0;
+       else if( !item->hasV6 )                         me->bitmapV6 = 1;
+       else if(  item->addressCount < 64 )     me->bitmapV6 = ( UINT64_C( 1 ) << item->addressCount ) - 1;
+       else                                                            me->bitmapV6 =  ~UINT64_C( 0 );
+       check( ( me->bitmapV4 != 0 ) || ( me->bitmapV6 != 0 ) );
+       me->gotFirstResult = false;
+       
+       // Perform preliminary tasks if this is the start of a new test case.
+       
+       if( item == me->currentCase->itemList )
+       {
+               // Flush mDNSResponder's cache.
+               
+               err = systemf( NULL, "killall -HUP mDNSResponder" );
+               require_noerr( err, exit );
+               sleep( 1 );
+               
+               me->caseStartTime       = NanoTimeGetCurrent();
+               me->caseEndTime         = kNanoTime_Invalid;
+       }
+       
+       // Start a packet capture.
+       
+       check( !me->pcap );
+       err = _GAITesterCreatePacketCapture( &me->pcap );
+       require_noerr( err, exit );
+       
+       // Start timer for test item's time limit.
+       
+       check( !me->timer );
+       if( item->timeLimitMs > 0 )
+       {
+               unsigned int            timeLimitMs;
+               
+               timeLimitMs = item->timeLimitMs;
+               if( me->callDelayMs   > 0 ) timeLimitMs += (unsigned int) me->callDelayMs;
+               if( me->serverDelayMs > 0 ) timeLimitMs += (unsigned int) me->serverDelayMs;
+               
+               err = DispatchTimerCreate( dispatch_time_milliseconds( timeLimitMs ), DISPATCH_TIME_FOREVER,
+                       ( (uint64_t) timeLimitMs ) * kNanosecondsPerMillisecond / 10,
+                       me->queue, _GAITesterTimeout, NULL, me, &me->timer );
+               require_noerr( err, exit );
+               dispatch_resume( me->timer );
+       }
+       
+       // Call DNSServiceGetAddrInfo().
+       
+       if( me->callDelayMs > 0 ) usleep( ( (useconds_t) me->callDelayMs ) * kMicrosecondsPerMillisecond );
+       
+       flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
+       if( me->skipPathEval ) flags |= kDNSServiceFlagsPathEvaluationDone;
+       
+       protocols = 0;
+       if( item->wantV4 ) protocols |= kDNSServiceProtocol_IPv4;
+       if( item->wantV6 ) protocols |= kDNSServiceProtocol_IPv6;
+       
+       me->startTicks = UpTicks();
+       
+       check( !me->connection );
+       err = DNSServiceCreateConnection( &me->connection );
+       require_noerr( err, exit );
+       
+       err = DNSServiceSetDispatchQueue( me->connection, me->queue );
+       require_noerr( err, exit );
+       
+       me->connTicks = UpTicks();
+       
+       check( !me->getAddrInfo );
+       me->getAddrInfo = me->connection;
+       err = DNSServiceGetAddrInfo( &me->getAddrInfo, flags, kDNSServiceInterfaceIndexAny, protocols, item->name,
+               _GAITesterGetAddrInfoCallback, me );
+       require_noerr( err, exit );
+       
+exit:
+       if( err || done ) _GAITesterStop( me, err );
+}
+
+//===========================================================================================================================
+//     _GAITesterCreatePacketCapture
+//===========================================================================================================================
+
+static OSStatus        _GAITesterCreatePacketCapture( pcap_t **outPCap )
+{
+       OSStatus                                err;
+       pcap_t *                                pcap;
+       struct bpf_program              program;
+       char                                    errBuf[ PCAP_ERRBUF_SIZE ];
+       
+       pcap = pcap_create( "lo0", errBuf );
+       require_action_string( pcap, exit, err = kUnknownErr, errBuf );
+       
+       err = pcap_set_buffer_size( pcap, 512 * kBytesPerKiloByte );
+       require_noerr_action( err, exit, err = kUnknownErr );
+       
+       err = pcap_set_snaplen( pcap, 512 );
+       require_noerr_action( err, exit, err = kUnknownErr );
+       
+       err = pcap_set_immediate_mode( pcap, 0 );
+       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+       
+       err = pcap_activate( pcap );
+       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+       
+       err = pcap_setdirection( pcap, PCAP_D_INOUT );
+       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+       
+       err = pcap_setnonblock( pcap, 1, errBuf );
+       require_noerr_action_string( err, exit, err = kUnknownErr, errBuf );
+       
+       err = pcap_compile( pcap, &program, "udp port 53", 1, PCAP_NETMASK_UNKNOWN );
+       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+       
+       err = pcap_setfilter( pcap, &program );
+       pcap_freecode( &program );
+       require_noerr_action_string( err, exit, err = kUnknownErr, pcap_geterr( pcap ) );
+       
+       *outPCap = pcap;
+       pcap = NULL;
+       
+exit:
+       if( pcap ) pcap_close( pcap );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _GAITesterFirstGAITimeout
+//===========================================================================================================================
+
+static void    _GAITesterFirstGAITimeout( void *inContext )
+{
+       GAITesterRef const              me = (GAITesterRef) inContext;
+       
+       _GAITesterStop( me, kNoResourcesErr );
+}
+
+//===========================================================================================================================
+//     _GAITesterTimeout
+//===========================================================================================================================
+
+static void    _GAITesterTimeout( void *inContext )
+{
+       GAITesterRef const              me = (GAITesterRef) inContext;
+       
+       _GAITesterCompleteCurrentTest( me, kTimeoutErr );
+}
+
+//===========================================================================================================================
+//     _GAITesterFirstGAICallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _GAITesterFirstGAICallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       GAITesterRef const              me = (GAITesterRef) inContext;
+       
+       Unused( inSDRef );
+       Unused( inInterfaceIndex );
+       Unused( inHostname );
+       Unused( inSockAddr );
+       Unused( inTTL );
+       
+       if( ( inFlags & kDNSServiceFlagsAdd ) && !inError )
+       {
+               dispatch_source_forget( &me->timer );
+               DNSServiceForget( &me->getAddrInfo );
+               
+               _GAITesterStartNextTest( me );
+       }
+}
+
+//===========================================================================================================================
+//     _GAITesterGetAddrInfoCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _GAITesterGetAddrInfoCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                                                err;
+       GAITesterRef const                              me              = (GAITesterRef) inContext;
+       GAITestItem * const                             item    = me->currentItem;
+       const sockaddr_ip * const               sip             = (const sockaddr_ip *) inSockAddr;
+       uint64_t                                                nowTicks;
+       uint64_t *                                              bitmapPtr;
+       uint64_t                                                bitmask;
+       int                                                             hasAddr;
+       
+       Unused( inSDRef );
+       Unused( inInterfaceIndex );
+       Unused( inHostname );
+       Unused( inTTL );
+       
+       nowTicks = UpTicks();
+       
+       require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
+       
+       // Check if we were expecting an IP address result of this type.
+       
+       if( sip->sa.sa_family == AF_INET )
+       {
+               bitmapPtr       = &me->bitmapV4;
+               hasAddr         = item->hasV4;
+       }
+       else if( sip->sa.sa_family == AF_INET6 )
+       {
+               bitmapPtr       = &me->bitmapV6;
+               hasAddr         = item->hasV6;
+       }
+       else
+       {
+               err = kTypeErr;
+               goto exit;
+       }
+       
+       bitmask = 0;
+       if( hasAddr )
+       {
+               uint32_t                addrOffset;
+               
+               require_noerr_action_quiet( inError, exit, err = inError );
+               
+               if( sip->sa.sa_family == AF_INET )
+               {
+                       const uint32_t          addrV4 = ntohl( sip->v4.sin_addr.s_addr );
+                       
+                       if( strcasecmp( item->name, "localhost." ) == 0 )
+                       {
+                               if( addrV4 == INADDR_LOOPBACK ) bitmask = 1;
+                       }
+                       else
+                       {
+                               addrOffset = addrV4 - kDNSServerBaseAddrV4;
+                               if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
+                               {
+                                       bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
+                               }
+                       }
+               }
+               else
+               {
+                       const uint8_t * const           addrV6 = sip->v6.sin6_addr.s6_addr;
+                       
+                       if( strcasecmp( item->name, "localhost." ) == 0 )
+                       {
+                               if( memcmp( addrV6, in6addr_loopback.s6_addr, 16 ) == 0 ) bitmask = 1;
+                       }
+                       else if( memcmp( addrV6, kDNSServerBaseAddrV6, 15 ) == 0 )
+                       {
+                               addrOffset = addrV6[ 15 ];
+                               if( ( addrOffset >= 1 ) && ( addrOffset <= item->addressCount ) )
+                               {
+                                       bitmask = UINT64_C( 1 ) << ( addrOffset - 1 );
+                               }
+                       }
+               }
+       }
+       else
+       {
+               require_action_quiet( inError == kDNSServiceErr_NoSuchRecord, exit, err = inError ? inError : kUnexpectedErr );
+               bitmask = 1;
+       }
+       require_action_quiet( bitmask != 0, exit, err = kValueErr );
+       require_action_quiet( *bitmapPtr & bitmask, exit, err = kDuplicateErr );
+       
+       *bitmapPtr &= ~bitmask;
+       if( !me->gotFirstResult )
+       {
+               me->firstTicks          = nowTicks;
+               me->gotFirstResult      = true;
+       }
+       err = kNoErr;
+       
+exit:
+       if( err || ( ( me->bitmapV4 == 0 ) && ( me->bitmapV6 == 0 ) ) )
+       {
+               me->endTicks = nowTicks;
+               _GAITesterCompleteCurrentTest( me, err );
+       }
+}
+
+//===========================================================================================================================
+//     _GAITesterCompleteCurrentTest
+//===========================================================================================================================
+
+static OSStatus
+       _GAITesterGetDNSMessageFromPacket(
+               const uint8_t *         inPacketPtr,
+               size_t                          inPacketLen,
+               const uint8_t **        outMsgPtr,
+               size_t *                        outMsgLen );
+
+static void    _GAITesterCompleteCurrentTest( GAITesterRef me, OSStatus inError )
+{
+       OSStatus                                err;
+       GAITestItem * const             item    = me->currentItem;
+       struct timeval                  timeStamps[ 4 ];
+       struct timeval *                tsPtr;
+       struct timeval *                tsQA    = NULL;
+       struct timeval *                tsQAAAA = NULL;
+       struct timeval *                tsRA    = NULL;
+       struct timeval *                tsRAAAA = NULL;
+       struct timeval *                t1;
+       struct timeval *                t2;
+       int64_t                                 idleTimeUs;
+       uint8_t                                 name[ kDomainNameLengthMax ];
+       
+       dispatch_source_forget( &me->timer );
+       DNSServiceForget( &me->getAddrInfo );
+       DNSServiceForget( &me->connection );
+       
+       item->error = inError;
+       if( item->error )
+       {
+               err = kNoErr;
+               goto exit;
+       }
+       
+       err = DomainNameFromString( name, item->name, NULL );
+       require_noerr( err, exit );
+       
+       tsPtr = &timeStamps[ 0 ];
+       for( ;; )
+       {
+               int                                                     status;
+               struct pcap_pkthdr *            pktHdr;
+               const uint8_t *                         packet;
+               const uint8_t *                         msgPtr;
+               size_t                                          msgLen;
+               const DNSHeader *                       hdr;
+               unsigned int                            flags;
+               const uint8_t *                         ptr;
+               uint16_t                                        qtype, qclass;
+               uint8_t                                         qname[ kDomainNameLengthMax ];
+               
+               status = pcap_next_ex( me->pcap, &pktHdr, &packet );
+               if( status != 1 ) break;
+               if( _GAITesterGetDNSMessageFromPacket( packet, pktHdr->caplen, &msgPtr, &msgLen ) != kNoErr ) continue;
+               if( msgLen < kDNSHeaderLength ) continue;
+               
+               hdr = (const DNSHeader *) msgPtr;
+               flags = DNSHeaderGetFlags( hdr );
+               if( DNSFlagsGetOpCode( flags ) != kDNSOpCode_Query ) continue;
+               if( DNSHeaderGetQuestionCount( hdr ) < 1 ) continue;
+               
+               ptr = (const uint8_t *) &hdr[ 1 ];
+               if( DNSMessageExtractQuestion( msgPtr, msgLen, ptr, qname, &qtype, &qclass, NULL ) != kNoErr ) continue;
+               if( qclass != kDNSServiceClass_IN ) continue;
+               if( !DomainNameEqual( qname, name ) ) continue;
+               
+               if( item->wantV4 && ( qtype == kDNSServiceType_A ) )
+               {
+                       if( flags & kDNSHeaderFlag_Response )
+                       {
+                               if( tsQA && !tsRA )
+                               {
+                                       tsRA  = tsPtr++;
+                                       *tsRA = pktHdr->ts;
+                               }
+                       }
+                       else if( !tsQA )
+                       {
+                               tsQA  = tsPtr++;
+                               *tsQA = pktHdr->ts;
+                       }
+               }
+               else if( item->wantV6 && ( qtype == kDNSServiceType_AAAA ) )
+               {
+                       if( flags & kDNSHeaderFlag_Response )
+                       {
+                               if( tsQAAAA && !tsRAAAA )
+                               {
+                                       tsRAAAA  = tsPtr++;
+                                       *tsRAAAA = pktHdr->ts;
+                               }
+                       }
+                       else if( !tsQAAAA )
+                       {
+                               tsQAAAA  = tsPtr++;
+                               *tsQAAAA = pktHdr->ts;
+                       }
+               }
+       }
+       
+       // t1 is the time when the last query was sent.
+       
+       if( tsQA && tsQAAAA )   t1 = TIMEVAL_GT( *tsQA, *tsQAAAA ) ? tsQA : tsQAAAA;
+       else                                    t1 = tsQA ? tsQA : tsQAAAA;
+       
+       // t2 is when the first response was received.
+       
+       if( tsRA && tsRAAAA )   t2 = TIMEVAL_LT( *tsRA, *tsRAAAA ) ? tsRA : tsRAAAA;
+       else                                    t2 = tsRA ? tsRA : tsRAAAA;
+       
+       if( t1 && t2 )
+       {
+               idleTimeUs = TIMEVAL_USEC64_DIFF( *t2, *t1 );
+               if( idleTimeUs < 0 ) idleTimeUs = 0;
+       }
+       else
+       {
+               idleTimeUs = 0;
+       }
+       
+       item->connectionTimeUs  = UpTicksToMicroseconds( me->connTicks  - me->startTicks );
+       item->firstTimeUs               = UpTicksToMicroseconds( me->firstTicks - me->connTicks  ) - (uint64_t) idleTimeUs;
+       item->timeUs                    = UpTicksToMicroseconds( me->endTicks   - me->connTicks  ) - (uint64_t) idleTimeUs;
+       
+exit:
+       ForgetPacketCapture( &me->pcap );
+       if( err )       _GAITesterStop( me, err );
+       else            _GAITesterStartNextTest( me );
+}
+
+//===========================================================================================================================
+//     _GAITesterGetDNSMessageFromPacket
+//===========================================================================================================================
+
+#define kHeaderSizeNullLink             4
+#define kHeaderSizeIPv4Min             20
+#define kHeaderSizeIPv6                        40
+#define kHeaderSizeUDP                  8
+
+#define kIPProtocolUDP         0x11
+
+static OSStatus
+       _GAITesterGetDNSMessageFromPacket(
+               const uint8_t *         inPacketPtr,
+               size_t                          inPacketLen,
+               const uint8_t **        outMsgPtr,
+               size_t *                        outMsgLen )
+{
+       OSStatus                                        err;
+       const uint8_t *                         nullLink;
+       uint32_t                                        addressFamily;
+       const uint8_t *                         ip;
+       int                                                     ipHeaderLen;
+       int                                                     protocol;
+       const uint8_t *                         msg;
+       const uint8_t * const           end = &inPacketPtr[ inPacketLen ];
+       
+       nullLink = &inPacketPtr[ 0 ];
+       require_action_quiet( ( end - nullLink ) >= kHeaderSizeNullLink, exit, err = kUnderrunErr );
+       addressFamily = ReadHost32( &nullLink[ 0 ] );
+       
+       ip = &nullLink[ kHeaderSizeNullLink ];
+       if( addressFamily == AF_INET )
+       {
+               require_action_quiet( ( end - ip ) >= kHeaderSizeIPv4Min, exit, err = kUnderrunErr );
+               ipHeaderLen     = ( ip[ 0 ] & 0x0F ) * 4;
+               protocol        =   ip[ 9 ];
+       }
+       else if( addressFamily == AF_INET6 )
+       {
+               require_action_quiet( ( end - ip ) >= kHeaderSizeIPv6, exit, err = kUnderrunErr );
+               ipHeaderLen     = kHeaderSizeIPv6;
+               protocol        = ip[ 6 ];
+       }
+       else
+       {
+               err = kTypeErr;
+               goto exit;
+       }
+       require_action_quiet( protocol == kIPProtocolUDP, exit, err = kTypeErr );
+       require_action_quiet( ( end - ip ) >= ( ipHeaderLen + kHeaderSizeUDP ), exit, err = kUnderrunErr );
+       
+       msg = &ip[ ipHeaderLen + kHeaderSizeUDP ];
+       
+       *outMsgPtr = msg;
+       *outMsgLen = (size_t)( end - msg );
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAITestCaseCreate
+//===========================================================================================================================
+
+static OSStatus        GAITestCaseCreate( const char *inTitle, GAITestCase **outCase )
+{
+       OSStatus                        err;
+       GAITestCase *           obj;
+       
+       obj = (GAITestCase *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->title = strdup( inTitle );
+       require_action( obj->title, exit, err = kNoMemoryErr );
+       
+       *outCase = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) GAITestCaseFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAITestCaseFree
+//===========================================================================================================================
+
+static void    GAITestCaseFree( GAITestCase *inCase )
+{
+       GAITestItem *           item;
+       
+       while( ( item = inCase->itemList ) != NULL )
+       {
+               inCase->itemList = item->next;
+               GAITestItemFree( item );
+       }
+       ForgetMem( &inCase->title );
+       free( inCase );
+}
+
+//===========================================================================================================================
+//     GAITestCaseAddItem
+//===========================================================================================================================
+
+static OSStatus
+       GAITestCaseAddItem(
+               GAITestCase *   inCase,
+               unsigned int    inAliasCount,
+               unsigned int    inAddressCount,
+               int                             inTTL,
+               GAITestAddrType inHasAddrs,
+               GAITestAddrType inWantAddrs,
+               unsigned int    inTimeLimitMs,
+               unsigned int    inItemCount )
+{
+       OSStatus                        err;
+       GAITestItem *           item;
+       GAITestItem *           item2;
+       GAITestItem *           newItemList = NULL;
+       GAITestItem **          itemPtr;
+       char *                          ptr;
+       char *                          end;
+       unsigned int            i;
+       char                            name[ 64 ];
+       char                            tag[ kGAITesterTagStringLen + 1 ];
+       
+       require_action_quiet( inItemCount > 0, exit, err = kNoErr );
+       
+       // Limit address count to 64 because we use 64-bit bitmaps for keeping track of addresses.
+       
+       require_action_quiet( ( inAddressCount >= 1 ) && ( inAddressCount <= 64 ), exit, err = kCountErr );
+       require_action_quiet( ( inAliasCount >= 0 ) && ( inAliasCount <= INT32_MAX ), exit, err = kCountErr );
+       require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
+       
+       ptr = &name[ 0 ];
+       end = &name[ countof( name ) ];
+       
+       // Add Alias label.
+       
+       if(      inAliasCount == 1 ) SNPrintF_Add( &ptr, end, "alias." );
+       else if( inAliasCount >= 2 ) SNPrintF_Add( &ptr, end, "alias-%u.", inAliasCount );
+       
+       // Add Count label.
+       
+       SNPrintF_Add( &ptr, end, "count-%u.", inAddressCount );
+       
+       // Add TTL label.
+       
+       if( inTTL >= 0 ) SNPrintF_Add( &ptr, end, "ttl-%d.", inTTL );
+       
+       // Add Tag label.
+       
+       SNPrintF_Add( &ptr, end, "tag-%s.",
+               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+       
+       // Add IPv4 or IPv6 label if necessary.
+       
+       if(      inHasAddrs == kGAITestAddrType_IPv4 ) SNPrintF_Add( &ptr, end, "ipv4." );
+       else if( inHasAddrs == kGAITestAddrType_IPv6 ) SNPrintF_Add( &ptr, end, "ipv6." );
+       
+       // Finally, add the d.test. labels.
+       
+       SNPrintF_Add( &ptr, end, "d.test." );
+       
+       // Create item.
+       
+       err = GAITestItemCreate( name, inAddressCount, inHasAddrs, inWantAddrs, inTimeLimitMs, &item );
+       require_noerr( err, exit );
+       
+       newItemList     = item;
+       itemPtr         = &item->next;
+       
+       // Create repeat items.
+       
+       for( i = 1; i < inItemCount; ++i )
+       {
+               err = GAITestItemDup( item, &item2 );
+               require_noerr( err, exit );
+               
+               *itemPtr        = item2;
+               itemPtr         = &item2->next;
+       }
+       
+       // Append to test case's item list.
+       
+       for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
+       *itemPtr        = newItemList;
+       newItemList     = NULL;
+       
+exit:
+       while( ( item = newItemList ) != NULL )
+       {
+               newItemList = item->next;
+               GAITestItemFree( item );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAITestCaseAddLocalHostItem
+//===========================================================================================================================
+
+static OSStatus
+       GAITestCaseAddLocalHostItem(
+               GAITestCase *   inCase,
+               GAITestAddrType inWantAddrs,
+               unsigned int    inTimeLimitMs,
+               unsigned int    inItemCount )
+{
+       OSStatus                        err;
+       GAITestItem *           item;
+       GAITestItem *           item2;
+       GAITestItem *           newItemList = NULL;
+       GAITestItem **          itemPtr;
+       unsigned int            i;
+       
+       require_action_quiet( inItemCount > 1, exit, err = kNoErr );
+       
+       err = GAITestItemCreate( "localhost.", 1, kGAITestAddrType_Both, inWantAddrs, inTimeLimitMs, &item );
+       require_noerr( err, exit );
+       
+       newItemList     = item;
+       itemPtr         = &item->next;
+       
+       // Create repeat items.
+       
+       for( i = 1; i < inItemCount; ++i )
+       {
+               err = GAITestItemDup( item, &item2 );
+               require_noerr( err, exit );
+               
+               *itemPtr        = item2;
+               itemPtr         = &item2->next;
+       }
+       
+       for( itemPtr = &inCase->itemList; *itemPtr; itemPtr = &( *itemPtr )->next ) {}
+       *itemPtr        = newItemList;
+       newItemList     = NULL;
+       
+exit:
+       while( ( item = newItemList ) != NULL )
+       {
+               newItemList = item->next;
+               GAITestItemFree( item );
+       }
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAITestItemCreate
+//===========================================================================================================================
+
+static OSStatus
+       GAITestItemCreate(
+               const char *    inName,
+               unsigned int    inAddressCount,
+               GAITestAddrType inHasAddrs,
+               GAITestAddrType inWantAddrs,
+               unsigned int    inTimeLimitMs,
+               GAITestItem **  outItem )
+{
+       OSStatus                        err;
+       GAITestItem *           obj = NULL;
+       
+       require_action_quiet( inAddressCount >= 1, exit, err = kCountErr );
+       require_action_quiet( GAITestAddrTypeIsValid( inHasAddrs ), exit, err = kValueErr );
+       require_action_quiet( GAITestAddrTypeIsValid( inWantAddrs ), exit, err = kValueErr );
+       
+       obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name = strdup( inName );
+       require_action( obj->name, exit, err = kNoMemoryErr );
+       
+       obj->addressCount       = inAddressCount;
+       obj->hasV4                      = ( inHasAddrs  & kGAITestAddrType_IPv4 ) ? true : false;
+       obj->hasV6                      = ( inHasAddrs  & kGAITestAddrType_IPv6 ) ? true : false;
+       obj->wantV4                     = ( inWantAddrs & kGAITestAddrType_IPv4 ) ? true : false;
+       obj->wantV6                     = ( inWantAddrs & kGAITestAddrType_IPv6 ) ? true : false;
+       obj->error                      = kInProgressErr;
+       obj->timeLimitMs        = inTimeLimitMs;
+       
+       *outItem = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) GAITestItemFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAITestItemDup
+//===========================================================================================================================
+
+static OSStatus        GAITestItemDup( const GAITestItem *inItem, GAITestItem **outItem )
+{
+       OSStatus                        err;
+       GAITestItem *           obj;
+       
+       obj = (GAITestItem *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       *obj = *inItem;
+       obj->next = NULL;
+       if( inItem->name )
+       {
+               obj->name = strdup( inItem->name );
+               require_action( obj->name, exit, err = kNoMemoryErr );
+       }
+       
+       *outItem = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) GAITestItemFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     GAITestItemFree
+//===========================================================================================================================
+
+static void    GAITestItemFree( GAITestItem *inItem )
+{
+       ForgetMem( &inItem->name );
+       free( inItem );
+}
+
+//===========================================================================================================================
+//     MDNSDiscoveryTestCmd
+//===========================================================================================================================
+
+#define kMDNSDiscoveryTestFirstQueryTimeoutSecs                4
+
+typedef struct
+{
+       DNSServiceRef                   query;                                  // Reference to DNSServiceQueryRecord for replier's "about" TXT record.
+       dispatch_source_t               queryTimer;                             // Used to time out the "about" TXT record query.
+       NanoTime64                              startTime;                              // When the test started.
+       NanoTime64                              endTime;                                // When the test ended.
+       pid_t                                   replierPID;                             // PID of mDNS replier.
+       uint32_t                                ifIndex;                                // Index of interface to run the replier on.
+       unsigned int                    instanceCount;                  // Desired number of service instances.
+       unsigned int                    txtSize;                                // Desired size of each service instance's TXT record data.
+       unsigned int                    recordCountA;                   // Desired number of A records per replier hostname.
+       unsigned int                    recordCountAAAA;                // Desired number of AAAA records per replier hostname.
+       unsigned int                    maxDropCount;                   // Replier's --maxDropCount option argument.
+       double                                  ucastDropRate;                  // Replier's probability of dropping a unicast response.
+       double                                  mcastDropRate;                  // Replier's probability of dropping a multicast query or response.
+       Boolean                                 noAdditionals;                  // True if the replier is to not include additional records in responses.
+       Boolean                                 useIPv4;                                // True if the replier is to use IPv4.
+       Boolean                                 useIPv6;                                // True if the replier is to use IPv6.
+       Boolean                                 flushedCache;                   // True if mDNSResponder's record cache was flushed before testing.
+       char *                                  replierCommand;                 // Command used to run the replier.
+       char *                                  serviceType;                    // Type of services to browse for.
+       ServiceBrowserRef               browser;                                // Service browser.
+       unsigned int                    browseTimeSecs;                 // Amount of time to spend browsing in seconds.
+       const char *                    outputFilePath;                 // File to write test results to. If NULL, then write to stdout.
+       OutputFormatType                outputFormat;                   // Format of test results output.
+       Boolean                                 outputAppendNewline;    // True if a newline character should be appended to JSON output.
+       char                                    hostname[ 32 + 1 ];             // Base hostname that the replier is to use for instance and host names.
+       char                                    tag[ 4 + 1 ];                   // Tag that the replier is to use in its service types.
+       
+}      MDNSDiscoveryTestContext;
+
+static void            _MDNSDiscoveryTestFirstQueryTimeout( void *inContext );
+static void DNSSD_API
+       _MDNSDiscoveryTestAboutQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static void
+       _MDNSDiscoveryTestServiceBrowserCallback(
+               ServiceBrowserResults * inResults,
+               OSStatus                                inError,
+               void *                                  inContext );
+static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen );
+
+static void    MDNSDiscoveryTestCmd( void )
+{
+       OSStatus                                                err;
+       MDNSDiscoveryTestContext *              context;
+       char                                                    queryName[ sizeof_field( MDNSDiscoveryTestContext, hostname ) + 15 ];
+       
+       context = (MDNSDiscoveryTestContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       err = CheckIntegerArgument( gMDNSDiscoveryTest_InstanceCount, "instance count", 1, UINT16_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSDiscoveryTest_TXTSize, "TXT size", 1, UINT16_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSDiscoveryTest_BrowseTimeSecs, "browse time (seconds)", 1, INT_MAX );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountA, "A record count", 0, 64 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSDiscoveryTest_RecordCountAAAA, "AAAA record count", 0, 64 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckDoubleArgument( gMDNSDiscoveryTest_UnicastDropRate, "unicast drop rate", 0.0, 1.0 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckDoubleArgument( gMDNSDiscoveryTest_MulticastDropRate, "multicast drop rate", 0.0, 1.0 );
+       require_noerr_quiet( err, exit );
+       
+       err = CheckIntegerArgument( gMDNSDiscoveryTest_MaxDropCount, "drop count", 0, 255 );
+       require_noerr_quiet( err, exit );
+       
+       context->replierPID                             = -1;
+       context->instanceCount                  = (unsigned int) gMDNSDiscoveryTest_InstanceCount;
+       context->txtSize                                = (unsigned int) gMDNSDiscoveryTest_TXTSize;
+       context->browseTimeSecs                 = (unsigned int) gMDNSDiscoveryTest_BrowseTimeSecs;
+       context->recordCountA                   = (unsigned int) gMDNSDiscoveryTest_RecordCountA;
+       context->recordCountAAAA                = (unsigned int) gMDNSDiscoveryTest_RecordCountAAAA;
+       context->ucastDropRate                  = gMDNSDiscoveryTest_UnicastDropRate;
+       context->mcastDropRate                  = gMDNSDiscoveryTest_MulticastDropRate;
+       context->maxDropCount                   = (unsigned int) gMDNSDiscoveryTest_MaxDropCount;
+       context->outputFilePath                 = gMDNSDiscoveryTest_OutputFilePath;
+       context->outputAppendNewline    = gMDNSDiscoveryTest_OutputAppendNewline ? true : false;
+       context->noAdditionals                  = gMDNSDiscoveryTest_NoAdditionals       ? true : false;
+       context->useIPv4                                = ( gMDNSDiscoveryTest_UseIPv4 || !gMDNSDiscoveryTest_UseIPv6 ) ? true : false;
+       context->useIPv6                                = ( gMDNSDiscoveryTest_UseIPv6 || !gMDNSDiscoveryTest_UseIPv4 ) ? true : false;
+       
+       if( gMDNSDiscoveryTest_Interface )
+       {
+               err = InterfaceIndexFromArgString( gMDNSDiscoveryTest_Interface, &context->ifIndex );
+               require_noerr_quiet( err, exit );
+       }
+       else
+       {
+               err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_All, NULL, &context->ifIndex );
+               require_noerr_quiet( err, exit );
+       }
+       
+       err = OutputFormatFromArgString( gMDNSDiscoveryTest_OutputFormat, &context->outputFormat );
+       require_noerr_quiet( err, exit );
+       
+       if( gMDNSDiscoveryTest_FlushCache )
+       {
+               err = CheckRootUser();
+               require_noerr_quiet( err, exit );
+               
+               err = systemf( NULL, "killall -HUP mDNSResponder" );
+               require_noerr( err, exit );
+               sleep( 1 );
+               context->flushedCache = true;
+       }
+       
+       _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->hostname ) - 1,
+               context->hostname );
+       _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( context->tag ) - 1, context->tag );
+       
+       ASPrintF( &context->serviceType, "_t-%s-%u-%u._tcp", context->tag, context->txtSize, context->instanceCount );
+       require_action( context->serviceType, exit, err = kUnknownErr );
+       
+       ASPrintF( &context->replierCommand,
+               "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount %u "
+               "--countA %u --countAAAA %u --udrop %.1f --mdrop %.1f --maxDropCount %u %?s%?s%?s",
+               (int64_t) getpid(),
+               context->ifIndex,
+               context->hostname,
+               context->tag,
+               context->instanceCount,
+               context->recordCountA,
+               context->recordCountAAAA,
+               context->ucastDropRate,
+               context->mcastDropRate,
+               context->maxDropCount,
+               context->noAdditionals, " --noAdditionals",
+               context->useIPv4,               " --ipv4",
+               context->useIPv6,               " --ipv6" );
+       require_action_quiet( context->replierCommand, exit, err = kUnknownErr );
+       
+       err = SpawnCommand( &context->replierPID, "%s", context->replierCommand );
+       require_noerr_quiet( err, exit );
+       
+       // Query for the replier's about TXT record. A response means it's fully up and running.
+       
+       SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->hostname );
+       err = DNSServiceQueryRecord( &context->query, kDNSServiceFlagsForceMulticast, context->ifIndex, queryName,
+               kDNSServiceType_TXT, kDNSServiceClass_IN, _MDNSDiscoveryTestAboutQueryCallback, context );
+       require_noerr( err, exit );
+       
+       err = DNSServiceSetDispatchQueue( context->query, dispatch_get_main_queue() );
+       require_noerr( err, exit );
+       
+       err = DispatchTimerCreate( dispatch_time_seconds( kMDNSDiscoveryTestFirstQueryTimeoutSecs ),
+               DISPATCH_TIME_FOREVER, UINT64_C_safe( kMDNSDiscoveryTestFirstQueryTimeoutSecs ) * kNanosecondsPerSecond / 10, NULL,
+               _MDNSDiscoveryTestFirstQueryTimeout, NULL, context, &context->queryTimer );
+       require_noerr( err, exit );
+       dispatch_resume( context->queryTimer );
+       
+       context->startTime = NanoTimeGetCurrent();
+       dispatch_main();
+       
+exit:
+       exit( 1 );
+}
+
+//===========================================================================================================================
+//     _MDNSDiscoveryTestFirstQueryTimeout
+//===========================================================================================================================
+
+static void    _MDNSDiscoveryTestFirstQueryTimeout( void *inContext )
+{
+       MDNSDiscoveryTestContext * const                context = (MDNSDiscoveryTestContext *) inContext;
+       
+       dispatch_source_forget( &context->queryTimer );
+       
+       FPrintF( stderr, "error: Query for mdnsreplier's \"about\" TXT record timed out.\n" );
+       exit( 1 );
+}
+
+//===========================================================================================================================
+//     _MDNSDiscoveryTestAboutQueryCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _MDNSDiscoveryTestAboutQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                                                                err;
+       MDNSDiscoveryTestContext * const                context = (MDNSDiscoveryTestContext *) inContext;
+       
+       Unused( inSDRef );
+       Unused( inInterfaceIndex );
+       Unused( inFullName );
+       Unused( inType );
+       Unused( inClass );
+       Unused( inRDataLen );
+       Unused( inRDataPtr );
+       Unused( inTTL );
+       
+       err = inError;
+       require_noerr( err, exit );
+       require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
+       
+       DNSServiceForget( &context->query );
+       dispatch_source_forget( &context->queryTimer );
+       
+       err = ServiceBrowserCreate( dispatch_get_main_queue(), 0, "local.", context->browseTimeSecs, false, &context->browser );
+       require_noerr( err, exit );
+       
+       err = ServiceBrowserAddServiceType( context->browser, context->serviceType );
+       require_noerr( err, exit );
+       
+       ServiceBrowserSetCallback( context->browser, _MDNSDiscoveryTestServiceBrowserCallback, context );
+       ServiceBrowserStart( context->browser );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     _MDNSDiscoveryTestServiceBrowserCallback
+//===========================================================================================================================
+
+#define kMDNSDiscoveryTestResultsKey_ReplierInfo                                       CFSTR( "replierInfo" )
+#define kMDNSDiscoveryTestResultsKey_StartTime                                         CFSTR( "startTime" )
+#define kMDNSDiscoveryTestResultsKey_EndTime                                           CFSTR( "endTime" )
+#define kMDNSDiscoveryTestResultsKey_BrowseTimeSecs                                    CFSTR( "browseTimeSecs" )
+#define kMDNSDiscoveryTestResultsKey_ServiceType                                       CFSTR( "serviceType" )
+#define kMDNSDiscoveryTestResultsKey_FlushedCache                                      CFSTR( "flushedCache" )
+#define kMDNSDiscoveryTestResultsKey_UnexpectedInstances                       CFSTR( "unexpectedInstances" )
+#define kMDNSDiscoveryTestResultsKey_MissingInstances                          CFSTR( "missingInstances" )
+#define kMDNSDiscoveryTestResultsKey_IncorrectInstances                                CFSTR( "incorrectInstances" )
+#define kMDNSDiscoveryTestResultsKey_Success                                           CFSTR( "success" )
+#define kMDNSDiscoveryTestResultsKey_TotalResolveTime                          CFSTR( "totalResolveTimeUs" )
+
+#define kMDNSDiscoveryTestReplierInfoKey_Command                                       CFSTR( "command" )
+#define kMDNSDiscoveryTestReplierInfoKey_InstanceCount                         CFSTR( "instanceCount" )
+#define kMDNSDiscoveryTestReplierInfoKey_TXTSize                                       CFSTR( "txtSize" )
+#define kMDNSDiscoveryTestReplierInfoKey_RecordCountA                          CFSTR( "recordCountA" )
+#define kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA                       CFSTR( "recordCountAAAA" )
+#define kMDNSDiscoveryTestReplierInfoKey_Hostname                                      CFSTR( "hostname" )
+#define kMDNSDiscoveryTestReplierInfoKey_NoAdditionals                         CFSTR( "noAdditionals" )
+#define kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate                       CFSTR( "ucastDropRate" )
+#define kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate                     CFSTR( "mcastDropRate" )
+#define kMDNSDiscoveryTestReplierInfoKey_MaxDropCount                          CFSTR( "maxDropCount" )
+
+#define kMDNSDiscoveryTestUnexpectedInstanceKey_Name                           CFSTR( "name" )
+#define kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex         CFSTR( "interfaceIndex" )
+
+#define kMDNSDiscoveryTestIncorrectInstanceKey_Name                                    CFSTR( "name" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve                      CFSTR( "didResolve" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname                     CFSTR( "badHostname" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_BadPort                         CFSTR( "badPort" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT                          CFSTR( "badTXT" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs         CFSTR( "unexpectedAddrs" )
+#define kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs                    CFSTR( "missingAddrs" )
+
+static void    _MDNSDiscoveryTestServiceBrowserCallback( ServiceBrowserResults *inResults, OSStatus inError, void *inContext )
+{
+       OSStatus                                                                err;
+       MDNSDiscoveryTestContext * const                context                 = (MDNSDiscoveryTestContext *) inContext;
+       const SBRDomain *                                               domain;
+       const SBRServiceType *                                  type;
+       const SBRServiceInstance *                              instance;
+       const SBRServiceInstance **                             instanceArray   = NULL;
+       const SBRIPAddress *                                    ipaddr;
+       size_t                                                                  hostnameLen;
+       const char *                                                    ptr;
+       const char *                                                    end;
+       unsigned int                                                    i;
+       uint32_t                                                                u32;
+       CFMutableArrayRef                                               unexpectedInstances;
+       CFMutableArrayRef                                               missingInstances;
+       CFMutableArrayRef                                               incorrectInstances;
+       CFMutableDictionaryRef                                  plist                   = NULL;
+       CFMutableDictionaryRef                                  badDict                 = NULL;
+       CFMutableArrayRef                                               unexpectedAddrs = NULL;
+       CFMutableArrayRef                                               missingAddrs    = NULL;
+       uint64_t                                                                maxResolveTimeUs;
+       int                                                                             success                 = false;
+       char                                                                    startTime[ 32 ];
+       char                                                                    endTime[ 32 ];
+       
+       context->endTime = NanoTimeGetCurrent();
+       
+       err = inError;
+       require_noerr( err, exit );
+       
+       _NanoTime64ToTimestamp( context->startTime, startTime, sizeof( startTime ) );
+       _NanoTime64ToTimestamp( context->endTime, endTime, sizeof( endTime ) );
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+               "{"
+                       "%kO="
+                       "{"
+                               "%kO=%s"        // replierCommand
+                               "%kO=%lli"      // txtSize
+                               "%kO=%lli"      // instanceCount
+                               "%kO=%lli"      // recordCountA
+                               "%kO=%lli"      // recordCountAAAA
+                               "%kO=%s"        // hostname
+                               "%kO=%b"        // noAdditionals
+                               "%kO=%f"        // ucastDropRate
+                               "%kO=%f"        // mcastDropRate
+                               "%kO=%i"        // maxDropCount
+                       "}"
+                       "%kO=%s"        // startTime
+                       "%kO=%s"        // endTime
+                       "%kO=%lli"      // browseTimeSecs
+                       "%kO=%s"        // serviceType
+                       "%kO=%b"        // flushedCache
+                       "%kO=[%@]"      // unexpectedInstances
+                       "%kO=[%@]"      // missingInstances
+                       "%kO=[%@]"      // incorrectInstances
+               "}",
+               kMDNSDiscoveryTestResultsKey_ReplierInfo,
+               kMDNSDiscoveryTestReplierInfoKey_Command,                       context->replierCommand,
+               kMDNSDiscoveryTestReplierInfoKey_InstanceCount,         (int64_t) context->instanceCount,
+               kMDNSDiscoveryTestReplierInfoKey_TXTSize,                       (int64_t) context->txtSize,
+               kMDNSDiscoveryTestReplierInfoKey_RecordCountA,          (int64_t) context->recordCountA,
+               kMDNSDiscoveryTestReplierInfoKey_RecordCountAAAA,       (int64_t) context->recordCountAAAA,
+               kMDNSDiscoveryTestReplierInfoKey_Hostname,                      context->hostname,
+               kMDNSDiscoveryTestReplierInfoKey_NoAdditionals,         context->noAdditionals,
+               kMDNSDiscoveryTestReplierInfoKey_UnicastDropRate,       context->ucastDropRate,
+               kMDNSDiscoveryTestReplierInfoKey_MulticastDropRate,     context->mcastDropRate,
+               kMDNSDiscoveryTestReplierInfoKey_MaxDropCount,          context->maxDropCount,
+               kMDNSDiscoveryTestResultsKey_StartTime,                         startTime,
+               kMDNSDiscoveryTestResultsKey_EndTime,                           endTime,
+               kMDNSDiscoveryTestResultsKey_BrowseTimeSecs,            (int64_t) context->browseTimeSecs,
+               kMDNSDiscoveryTestResultsKey_ServiceType,                       context->serviceType,
+               kMDNSDiscoveryTestResultsKey_FlushedCache,                      context->flushedCache,
+               kMDNSDiscoveryTestResultsKey_UnexpectedInstances,       &unexpectedInstances,
+               kMDNSDiscoveryTestResultsKey_MissingInstances,          &missingInstances,
+               kMDNSDiscoveryTestResultsKey_IncorrectInstances,        &incorrectInstances );
+       require_noerr( err, exit );
+       
+       for( domain = inResults->domainList; domain && ( strcasecmp( domain->name, "local." ) != 0 ); domain = domain->next ) {}
+       require_action( domain, exit, err = kInternalErr );
+       
+       for( type = domain->typeList; type && ( strcasecmp( type->name, context->serviceType ) != 0 ); type = type->next ) {}
+       require_action( type, exit, err = kInternalErr );
+       
+       instanceArray = (const SBRServiceInstance **) calloc( context->instanceCount, sizeof( *instanceArray ) );
+       require_action( instanceArray, exit, err = kNoMemoryErr );
+       
+       hostnameLen = strlen( context->hostname );
+       for( instance = type->instanceList; instance; instance = instance->next )
+       {
+               unsigned int            instanceNumber = 0;
+               
+               if( strcmp_prefix( instance->name, context->hostname ) == 0 )
+               {
+                       ptr = &instance->name[ hostnameLen ];
+                       if( ( ptr[ 0 ] == ' ' ) && ( ptr[ 1 ] == '(' ) )
+                       {
+                               ptr += 2;
+                               for( end = ptr; isdigit_safe( *end ); ++end ) {}
+                               if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
+                               {
+                                       if( ( u32 >= 2 ) && ( u32 <= context->instanceCount ) && ( ptr[ 0 ] == ')' ) && ( ptr[ 1 ] == '\0' ) )
+                                       {
+                                               instanceNumber = u32;
+                                       }
+                               }
+                       }
+                       else if( *ptr == '\0' )
+                       {
+                               instanceNumber = 1;
+                       }
+               }
+               if( ( instanceNumber != 0 ) && ( instance->ifIndex == context->ifIndex ) )
+               {
+                       check( !instanceArray[ instanceNumber - 1 ] );
+                       instanceArray[ instanceNumber - 1 ] = instance;
+               }
+               else
+               {
+                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedInstances,
+                               "{"
+                                       "%kO=%s"
+                                       "%kO=%lli"
+                               "}",
+                               kMDNSDiscoveryTestUnexpectedInstanceKey_Name,                   instance->name,
+                               kMDNSDiscoveryTestUnexpectedInstanceKey_InterfaceIndex, (int64_t) instance->ifIndex );
+                       require_noerr( err, exit );
+               }
+       }
+       
+       maxResolveTimeUs = 0;
+       for( i = 1; i <= context->instanceCount; ++i )
+       {
+               int             isHostnameValid;
+               int             isTXTValid;
+               
+               instance = instanceArray[ i - 1 ];
+               if( !instance )
+               {
+                       if( i == 1 )
+                       {
+                               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", context->hostname );
+                               require_noerr( err, exit );
+                       }
+                       else
+                       {
+                               char *          instanceName = NULL;
+                               
+                               ASPrintF( &instanceName, "%s (%u)", context->hostname, i );
+                               require_action( instanceName, exit, err = kUnknownErr );
+                               
+                               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingInstances, "%s", instanceName );
+                               free( instanceName );
+                               require_noerr( err, exit );
+                       }
+                       continue;
+               }
+               
+               if( !instance->hostname )
+               {
+                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, incorrectInstances,
+                               "{"
+                                       "%kO=%s"
+                                       "%kO=%b"
+                               "}",
+                               kMDNSDiscoveryTestIncorrectInstanceKey_Name,            instance->name,
+                               kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve,      false );
+                       require_noerr( err, exit );
+                       continue;
+               }
+               
+               badDict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
+               require_action( badDict, exit, err = kNoMemoryErr );
+               
+               isHostnameValid = false;
+               if( strcmp_prefix( instance->hostname, context->hostname ) == 0 )
+               {
+                       ptr = &instance->hostname[ hostnameLen ];
+                       if( i == 1 )
+                       {
+                               if( strcmp( ptr, ".local." ) == 0 ) isHostnameValid = true;
+                       }
+                       else if( *ptr == '-' )
+                       {
+                               ++ptr;
+                               for( end = ptr; isdigit_safe( *end ); ++end ) {}
+                               if( DecimalTextToUInt32( ptr, end, &u32, &ptr ) == kNoErr )
+                               {
+                                       if( ( u32 == i ) && ( strcmp( ptr, ".local." ) == 0 ) ) isHostnameValid = true;
+                               }
+                       }
+               }
+               if( !isHostnameValid )
+               {
+                       err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadHostname, instance->hostname,
+                               kSizeCString );
+                       require_noerr( err, exit );
+               }
+               
+               if( instance->port != (uint16_t)( kMDNSReplierPortBase + context->txtSize ) )
+               {
+                       err = CFDictionarySetInt64( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadPort, instance->port );
+                       require_noerr( err, exit );
+               }
+               
+               isTXTValid = false;
+               if( instance->txtLen == context->txtSize )
+               {
+                       uint8_t         name[ kDomainNameLengthMax ];
+                       
+                       err = DomainNameFromString( name, instance->name, NULL );
+                       require_noerr( err, exit );
+                       
+                       err = DomainNameAppendString( name, type->name, NULL );
+                       require_noerr( err, exit );
+                       
+                       err = DomainNameAppendString( name, "local", NULL );
+                       require_noerr( err, exit );
+                       
+                       if( _MDNSDiscoveryTestTXTRecordIsValid( name, instance->txtPtr, instance->txtLen ) ) isTXTValid = true;
+               }
+               if( !isTXTValid )
+               {
+                       char *          hexStr = NULL;
+                       
+                       ASPrintF( &hexStr, "%.4H", instance->txtPtr, (int) instance->txtLen, (int) instance->txtLen );
+                       require_action( hexStr, exit, err = kUnknownErr );
+                       
+                       err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_BadTXT, hexStr, kSizeCString );
+                       free( hexStr );
+                       require_noerr( err, exit );
+               }
+               
+               if( isHostnameValid )
+               {
+                       uint64_t                        addrV4Bitmap, addrV6Bitmap, bitmask, resolveTimeUs;
+                       unsigned int            j;
+                       uint8_t                         addrV4[ 4 ];
+                       uint8_t                         addrV6[ 16 ];
+                       
+                       if( context->recordCountA < 64 )        addrV4Bitmap = ( UINT64_C( 1 ) << context->recordCountA ) - 1;
+                       else                                                            addrV4Bitmap =  ~UINT64_C( 0 );
+                       
+                       if( context->recordCountAAAA < 64 ) addrV6Bitmap = ( UINT64_C( 1 ) << context->recordCountAAAA ) - 1;
+                       else                                                            addrV6Bitmap =  ~UINT64_C( 0 );
+                       
+                       addrV4[ 0 ] = 0;
+                       WriteBig16( &addrV4[ 1 ], i );
+                       addrV4[ 3 ] = 0;
+                       
+                       memcpy( addrV6, kMDNSReplierBaseAddrV6, 16 );
+                       WriteBig16( &addrV6[ 12 ], i );
+                       
+                       unexpectedAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+                       require_action( unexpectedAddrs, exit, err = kNoMemoryErr );
+                       
+                       resolveTimeUs = 0;
+                       for( ipaddr = instance->ipaddrList; ipaddr; ipaddr = ipaddr->next )
+                       {
+                               const uint8_t *         addrPtr;
+                               unsigned int            lsb;
+                               int                                     isAddrValid = false;
+                               
+                               if( ipaddr->sip.sa.sa_family == AF_INET )
+                               {
+                                       addrPtr = (const uint8_t *) &ipaddr->sip.v4.sin_addr.s_addr;
+                                       lsb             = addrPtr[ 3 ];
+                                       if( ( memcmp( addrPtr, addrV4, 3 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountA ) )
+                                       {
+                                               bitmask = UINT64_C( 1 ) << ( lsb - 1 );
+                                               addrV4Bitmap &= ~bitmask;
+                                               isAddrValid = true;
+                                       }
+                               }
+                               else if( ipaddr->sip.sa.sa_family == AF_INET6 )
+                               {
+                                       addrPtr = ipaddr->sip.v6.sin6_addr.s6_addr;
+                                       lsb             = addrPtr[ 15 ];
+                                       if( ( memcmp( addrPtr, addrV6, 15 ) == 0 ) && ( lsb >= 1 ) && ( lsb <= context->recordCountAAAA ) )
+                                       {
+                                               bitmask = UINT64_C( 1 ) << ( lsb - 1 );
+                                               addrV6Bitmap &= ~bitmask;
+                                               isAddrValid = true;
+                                       }
+                               }
+                               if( isAddrValid )
+                               {
+                                       if( ipaddr->resolveTimeUs > resolveTimeUs ) resolveTimeUs = ipaddr->resolveTimeUs;
+                               }
+                               else
+                               {
+                                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, unexpectedAddrs, "%##a", &ipaddr->sip );
+                                       require_noerr( err, exit );
+                               }
+                       }
+                       
+                       resolveTimeUs += ( instance->discoverTimeUs + instance->resolveTimeUs );
+                       if( resolveTimeUs > maxResolveTimeUs ) maxResolveTimeUs = resolveTimeUs;
+                       
+                       if( CFArrayGetCount( unexpectedAddrs ) > 0 )
+                       {
+                               CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_UnexpectedAddrs, unexpectedAddrs );
+                       }
+                       ForgetCF( &unexpectedAddrs );
+                       
+                       missingAddrs = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+                       require_action( missingAddrs, exit, err = kNoMemoryErr );
+                       
+                       for( j = 1; addrV4Bitmap != 0; ++j )
+                       {
+                               bitmask = UINT64_C( 1 ) << ( j - 1 );
+                               if( addrV4Bitmap & bitmask )
+                               {
+                                       addrV4Bitmap &= ~bitmask;
+                                       addrV4[ 3 ] = (uint8_t) j;
+                                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.4a", addrV4 );
+                                       require_noerr( err, exit );
+                               }
+                       }
+                       for( j = 1; addrV6Bitmap != 0; ++j )
+                       {
+                               bitmask = UINT64_C( 1 ) << ( j - 1 );
+                               if( addrV6Bitmap & bitmask )
+                               {
+                                       addrV6Bitmap &= ~bitmask;
+                                       addrV6[ 15 ] = (uint8_t) j;
+                                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, missingAddrs, "%.16a", addrV6 );
+                                       require_noerr( err, exit );
+                               }
+                       }
+                       
+                       if( CFArrayGetCount( missingAddrs ) > 0 )
+                       {
+                               CFDictionarySetValue( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_MissingAddrs, missingAddrs );
+                       }
+                       ForgetCF( &missingAddrs );
+               }
+               
+               if( CFDictionaryGetCount( badDict ) > 0 )
+               {
+                       err = CFDictionarySetCString( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_Name, instance->name,
+                               kSizeCString );
+                       require_noerr( err, exit );
+                       
+                       CFDictionarySetBoolean( badDict, kMDNSDiscoveryTestIncorrectInstanceKey_DidResolve, true );
+                       CFArrayAppendValue( incorrectInstances, badDict );
+               }
+               ForgetCF( &badDict );
+       }
+       
+       if( ( CFArrayGetCount( unexpectedInstances ) == 0 ) &&
+               ( CFArrayGetCount( missingInstances )    == 0 ) &&
+               ( CFArrayGetCount( incorrectInstances )  == 0 ) )
+       {
+               err = CFDictionarySetInt64( plist, kMDNSDiscoveryTestResultsKey_TotalResolveTime, (int64_t) maxResolveTimeUs );
+               require_noerr( err, exit );
+               success = true;
+       }
+       else
+       {
+               success = false;
+       }
+       CFDictionarySetBoolean( plist, kMDNSDiscoveryTestResultsKey_Success, success );
+       
+       err = OutputPropertyList( plist, context->outputFormat, context->outputFilePath );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       ForgetCF( &context->browser );
+       if( context->replierPID != -1 )
+       {
+               kill( context->replierPID, SIGTERM );
+               context->replierPID = -1;
+       }
+       FreeNullSafe( instanceArray );
+       CFReleaseNullSafe( plist );
+       CFReleaseNullSafe( badDict );
+       CFReleaseNullSafe( unexpectedAddrs );
+       CFReleaseNullSafe( missingAddrs );
+       exit( err ? 1 : ( success ? 0 : 2 ) );
+}
+
+//===========================================================================================================================
+//     _MDNSDiscoveryTestTXTRecordIsValid
+//===========================================================================================================================
+
+static Boolean _MDNSDiscoveryTestTXTRecordIsValid( const uint8_t *inRecordName, const uint8_t *inTXTPtr, size_t inTXTLen )
+{
+       uint32_t                        hash;
+       int                                     n;
+       const uint8_t *         ptr;
+       size_t                          i, wholeCount, remCount;
+       uint8_t                         txtStr[ 16 ];
+       
+       if( inTXTLen == 0 ) return( false );
+       
+       hash = _FNV1( inRecordName, DomainNameLength( inRecordName ) );
+       
+       txtStr[ 0 ] = 15;
+       n = MemPrintF( &txtStr[ 1 ], 15, "hash=0x%08X", hash );
+       check( n == 15 );
+       
+       ptr = inTXTPtr;
+       wholeCount = inTXTLen / 16;
+       for( i = 0; i < wholeCount; ++i )
+       {
+               if( memcmp( ptr, txtStr, 16 ) != 0 ) return( false );
+               ptr += 16;
+       }
+       
+       remCount = inTXTLen % 16;
+       if( remCount > 0 )
+       {
+               txtStr[ 0 ] = (uint8_t)( remCount - 1 );
+               if( memcmp( ptr, txtStr, remCount ) != 0 ) return( false );
+               ptr += remCount;
+       }
+       check( ptr == &inTXTPtr[ inTXTLen ] );
+       return( true );
+}
+
+//===========================================================================================================================
+//     DotLocalTestCmd
+//===========================================================================================================================
+
+#define kDotLocalTestPreparationTimeLimitSecs          5
+#define kDotLocalTestSubtestDurationSecs                       5
+
+// Constants for SRV record query subtest.
+
+#define kDotLocalTestSRV_Priority              1
+#define kDotLocalTestSRV_Weight                        0
+#define kDotLocalTestSRV_Port                  80
+#define kDotLocalTestSRV_TargetName            ( (const uint8_t *) "\x03" "www" "\x07" "example" "\x03" "com" )
+#define kDotLocalTestSRV_TargetStr             "www.example.com."
+#define kDotLocalTestSRV_ResultStr             "1 0 80 " kDotLocalTestSRV_TargetStr
+
+typedef enum
+{
+       kDotLocalTestState_Unset                                = 0,
+       kDotLocalTestState_Preparing                    = 1,
+       kDotLocalTestState_GAIMDNSOnly                  = 2,
+       kDotLocalTestState_GAIDNSOnly                   = 3,
+       kDotLocalTestState_GAIBoth                              = 4,
+       kDotLocalTestState_GAINeither                   = 5,
+       kDotLocalTestState_GAINoSuchRecord              = 6,
+       kDotLocalTestState_QuerySRV                             = 7,
+       kDotLocalTestState_Done                                 = 8
+       
+}      DotLocalTestState;
+
+typedef struct
+{
+       const char *                    testDesc;                       // Description of the current subtest.
+       char *                                  queryName;                      // Query name for GetAddrInfo or QueryRecord operation.
+       dispatch_source_t               timer;                          // Timer used for limiting the time for each subtest.
+       NanoTime64                              startTime;                      // Timestamp of when the subtest started.
+       NanoTime64                              endTime;                        // Timestamp of when the subtest ended.
+       CFMutableArrayRef               correctResults;         // Operation results that were expected.
+       CFMutableArrayRef               duplicateResults;       // Operation results that were expected, but were already received.
+       CFMutableArrayRef               unexpectedResults;      // Operation results that were unexpected.
+       OSStatus                                error;                          // Subtest's error code.
+       uint32_t                                addrDNSv4;                      // If hasDNSv4 is true, the expected DNS IPv4 address for queryName.
+       uint32_t                                addrMDNSv4;                     // If hasMDNSv4 is true, the expected MDNS IPv4 address for queryName.
+       uint8_t                                 addrDNSv6[ 16 ];        // If hasDNSv6 is true, the expected DNS IPv6 address for queryName.
+       uint8_t                                 addrMDNSv6[ 16 ];       // If hasMDNSv6 is true, the expected MDNS IPv6 address for queryName.
+       Boolean                                 hasDNSv4;                       // True if queryName has a DNS IPv4 address.
+       Boolean                                 hasDNSv6;                       // True if queryName has a DNS IPv6 address.
+       Boolean                                 hasMDNSv4;                      // True if queryName has an MDNS IPv4 address.
+       Boolean                                 hasMDNSv6;                      // True if queryName has an MDNS IPv6 address.
+       Boolean                                 needDNSv4;                      // True if operation is expecting, but hasn't received a DNS IPv4 result.
+       Boolean                                 needDNSv6;                      // True if operation is expecting, but hasn't received a DNS IPv6 result.
+       Boolean                                 needMDNSv4;                     // True if operation is expecting, but hasn't received an MDNS IPv4 result.
+       Boolean                                 needMDNSv6;                     // True if operation is expecting, but hasn't received an MDNS IPv6 result.
+       Boolean                                 needSRV;                        // True if operation is expecting, but hasn't received an SRV result.
+       
+}      DotLocalSubtest;
+
+typedef struct
+{
+       dispatch_source_t               timer;                          // Timer used for limiting the time for each state/subtest.
+       DotLocalSubtest *               subtest;                        // Current subtest's state.
+       DNSServiceRef                   connection;                     // Shared connection for DNS-SD operations.
+       DNSServiceRef                   op;                                     // Reference for the current DNS-SD operation.
+       DNSServiceRef                   op2;                            // Reference for mdnsreplier probe query used during preparing state.
+       DNSRecordRef                    localSOARef;            // Reference returned by DNSServiceRegisterRecord() for local. SOA record.
+       char *                                  replierCmd;                     // Command used to invoke the mdnsreplier.
+       char *                                  serverCmd;                      // Command used to invoke the test DNS server.
+       CFMutableArrayRef               reportsGAI;                     // Reports for subtests that use DNSServiceGetAddrInfo.
+       CFMutableArrayRef               reportsQuerySRV;        // Reports for subtests that use DNSServiceQueryRecord for SRV records.
+       NanoTime64                              startTime;                      // Timestamp for when the test started.
+       NanoTime64                              endTime;                        // Timestamp for when the test ended.
+       DotLocalTestState               state;                          // The test's current state.
+       pid_t                                   replierPID;                     // PID of spawned mdnsreplier.
+       pid_t                                   serverPID;                      // PID of spawned test DNS server.
+       uint32_t                                ifIndex;                        // Interface index used for mdnsreplier.
+       char *                                  outputFilePath;         // File to write test results to. If NULL, then write to stdout.
+       OutputFormatType                outputFormat;           // Format of test results output.
+       Boolean                                 registeredSOA;          // True if the dummy local. SOA record was successfully registered.
+       Boolean                                 serverIsReady;          // True if response was received for test DNS server probe query.
+       Boolean                                 replierIsReady;         // True if response was received for mdnsreplier probe query.
+       Boolean                                 testFailed;                     // True if at least one subtest failed.
+       char                                    labelStr[ 20 + 1 ];     // Unique label string used for for making the query names used by subtests.
+                                                                                               // The format of this string is "dotlocal-test-<six random chars>".
+}      DotLocalTestContext;
+
+static void    _DotLocalTestStateMachine( DotLocalTestContext *inContext );
+static void DNSSD_API
+       _DotLocalTestProbeQueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static void DNSSD_API
+       _DotLocalTestRegisterRecordCallback(
+               DNSServiceRef           inSDRef,
+               DNSRecordRef            inRecordRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               void *                          inContext );
+static void    _DotLocalTestTimerHandler( void *inContext );
+static void DNSSD_API
+       _DotLocalTestGAICallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static void DNSSD_API
+       _DotLocalTestQueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+
+static void    DotLocalTestCmd( void )
+{
+       OSStatus                                        err;
+       DotLocalTestContext *           context;
+       uint8_t *                                       rdataPtr;
+       size_t                                          rdataLen;
+       DNSServiceFlags                         flags;
+       char                                            queryName[ 64 ];
+       char                                            randBuf[ 6 + 1 ];       // Large enough for four and six character random strings below.
+       
+       context = (DotLocalTestContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->startTime      = NanoTimeGetCurrent();
+       context->endTime        = kNanoTime_Invalid;
+       
+       context->state = kDotLocalTestState_Preparing;
+       
+       if( gDotLocalTest_Interface )
+       {
+               err = InterfaceIndexFromArgString( gDotLocalTest_Interface, &context->ifIndex );
+               require_noerr_quiet( err, exit );
+       }
+       else
+       {
+               err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_All, NULL, &context->ifIndex );
+               require_noerr_quiet( err, exit );
+       }
+       
+       if( gDotLocalTest_OutputFilePath )
+       {
+               context->outputFilePath = strdup( gDotLocalTest_OutputFilePath );
+               require_action( context->outputFilePath, exit, err = kNoMemoryErr );
+       }
+       
+       err = OutputFormatFromArgString( gDotLocalTest_OutputFormat, &context->outputFormat );
+       require_noerr_quiet( err, exit );
+       
+       context->reportsGAI = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( context->reportsGAI, exit, err = kNoMemoryErr );
+       
+       context->reportsQuerySRV = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( context->reportsQuerySRV, exit, err = kNoMemoryErr );
+       
+       SNPrintF( context->labelStr, sizeof( context->labelStr ), "dotlocal-test-%s",
+               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 6, randBuf ) );
+       
+       // Spawn an mdnsreplier.
+       
+       ASPrintF( &context->replierCmd,
+               "dnssdutil mdnsreplier --follow %lld --interface %u --hostname %s --tag %s --maxInstanceCount 2 --countA 1"
+               " --countAAAA 1",
+               (int64_t) getpid(), context->ifIndex, context->labelStr,
+               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, 4, randBuf ) );
+       require_action_quiet( context->replierCmd, exit, err = kUnknownErr );
+       
+       err = SpawnCommand( &context->replierPID, "%s", context->replierCmd );
+       require_noerr( err, exit );
+       
+       // Spawn a test DNS server
+       
+       ASPrintF( &context->serverCmd,
+               "dnssdutil server --loopback --follow %lld --port 0 --defaultTTL 300 --domain %s.local.",
+               (int64_t) getpid(), context->labelStr );
+       require_action_quiet( context->serverCmd, exit, err = kUnknownErr );
+       
+       err = SpawnCommand( &context->serverPID, "%s", context->serverCmd );
+       require_noerr( err, exit );
+       
+       // Create a shared DNS-SD connection.
+       
+       err = DNSServiceCreateConnection( &context->connection );
+       require_noerr( err, exit );
+       
+       err = DNSServiceSetDispatchQueue( context->connection, dispatch_get_main_queue() );
+       require_noerr( err, exit );
+       
+       // Create probe query for DNS server, i.e., query for any name that has an A record.
+       
+       SNPrintF( queryName, sizeof( queryName ), "tag-dotlocal-test-probe.ipv4.%s.local.", context->labelStr );
+       
+       flags = kDNSServiceFlagsShareConnection;
+#if( TARGET_OS_WATCH )
+       flags |= kDNSServiceFlagsPathEvaluationDone;
+#endif
+       
+       context->op = context->connection;
+       err = DNSServiceQueryRecord( &context->op, flags, kDNSServiceInterfaceIndexAny, queryName, kDNSServiceType_A,
+               kDNSServiceClass_IN, _DotLocalTestProbeQueryRecordCallback, context );
+       require_noerr( err, exit );
+       
+       // Create probe query for mdnsreplier's "about" TXT record.
+       
+       SNPrintF( queryName, sizeof( queryName ), "about.%s.local.", context->labelStr );
+       
+       flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsForceMulticast;
+#if( TARGET_OS_WATCH )
+       flags |= kDNSServiceFlagsPathEvaluationDone;
+#endif
+       
+       context->op2 = context->connection;
+       err = DNSServiceQueryRecord( &context->op2, flags, context->ifIndex, queryName, kDNSServiceType_TXT, kDNSServiceClass_IN,
+               _DotLocalTestProbeQueryRecordCallback, context );
+       require_noerr( err, exit );
+       
+       // Register a dummy local. SOA record.
+       
+       err = CreateSOARecordData( kRootLabel, kRootLabel, 1976040101, 1 * kSecondsPerDay, 2 * kSecondsPerHour,
+               1000 * kSecondsPerHour, 2 * kSecondsPerDay, &rdataPtr, &rdataLen );
+       require_noerr( err, exit );
+       
+       err = DNSServiceRegisterRecord( context->connection, &context->localSOARef, kDNSServiceFlagsUnique,
+               kDNSServiceInterfaceIndexLocalOnly, "local.", kDNSServiceType_SOA, kDNSServiceClass_IN, 1,
+               rdataPtr, 1 * kSecondsPerHour, _DotLocalTestRegisterRecordCallback, context );
+       require_noerr( err, exit );
+       
+       // Start timer for probe responses and SOA record registration.
+       
+       err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestPreparationTimeLimitSecs ),
+               INT64_C_safe( kDotLocalTestPreparationTimeLimitSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
+               _DotLocalTestTimerHandler, context, &context->timer );
+       require_noerr( err, exit );
+       dispatch_resume( context->timer );
+       
+       dispatch_main();
+       
+exit:
+       if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//     _DotLocalTestStateMachine
+//===========================================================================================================================
+
+static OSStatus        _DotLocalSubtestCreate( DotLocalSubtest **outSubtest );
+static void            _DotLocalSubtestFree( DotLocalSubtest *inSubtest );
+static OSStatus        _DotLocalTestStartSubtest( DotLocalTestContext *inContext );
+static OSStatus        _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext );
+static void            _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext ) ATTRIBUTE_NORETURN;
+
+static void    _DotLocalTestStateMachine( DotLocalTestContext *inContext )
+{
+       OSStatus                                err;
+       DotLocalTestState               nextState;
+       
+       DNSServiceForget( &inContext->op );
+       DNSServiceForget( &inContext->op2 );
+       dispatch_source_forget( &inContext->timer );
+       
+       switch( inContext->state )
+       {
+               case kDotLocalTestState_Preparing:                      nextState = kDotLocalTestState_GAIMDNSOnly;             break;
+               case kDotLocalTestState_GAIMDNSOnly:            nextState = kDotLocalTestState_GAIDNSOnly;              break;
+               case kDotLocalTestState_GAIDNSOnly:                     nextState = kDotLocalTestState_GAIBoth;                 break;
+               case kDotLocalTestState_GAIBoth:                        nextState = kDotLocalTestState_GAINeither;              break;
+               case kDotLocalTestState_GAINeither:                     nextState = kDotLocalTestState_GAINoSuchRecord; break;
+               case kDotLocalTestState_GAINoSuchRecord:        nextState = kDotLocalTestState_QuerySRV;                break;
+               case kDotLocalTestState_QuerySRV:                       nextState = kDotLocalTestState_Done;                    break;
+               default:                                                                        err = kStateErr;                                                                goto exit;
+       }
+       
+       if( inContext->state == kDotLocalTestState_Preparing )
+       {
+               if( !inContext->registeredSOA || !inContext->serverIsReady || !inContext->replierIsReady )
+               {
+                       FPrintF( stderr, "Preparation timed out: Registered SOA? %s. Server ready? %s. mdnsreplier ready? %s.\n",
+                               YesNoStr( inContext->registeredSOA ),
+                               YesNoStr( inContext->serverIsReady ),
+                               YesNoStr( inContext->replierIsReady ) );
+                       err = kNotPreparedErr;
+                       goto exit;
+               }
+       }
+       else
+       {
+               err = _DotLocalTestFinalizeSubtest( inContext );
+               require_noerr( err, exit );
+       }
+       
+       inContext->state = nextState;
+       if( inContext->state == kDotLocalTestState_Done ) _DotLocalTestFinalizeAndExit( inContext );
+       err = _DotLocalTestStartSubtest( inContext );
+       
+exit:
+       if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//     _DotLocalSubtestCreate
+//===========================================================================================================================
+
+static OSStatus        _DotLocalSubtestCreate( DotLocalSubtest **outSubtest )
+{
+       OSStatus                                err;
+       DotLocalSubtest *               obj;
+       
+       obj = (DotLocalSubtest *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->correctResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( obj->correctResults, exit, err = kNoMemoryErr );
+       
+       obj->duplicateResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( obj->duplicateResults, exit, err = kNoMemoryErr );
+       
+       obj->unexpectedResults = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( obj->unexpectedResults, exit, err = kNoMemoryErr );
+       
+       *outSubtest = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _DotLocalSubtestFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _DotLocalSubtestFree
+//===========================================================================================================================
+
+static void    _DotLocalSubtestFree( DotLocalSubtest *inSubtest )
+{
+       ForgetMem( &inSubtest->queryName );
+       ForgetCF( &inSubtest->correctResults );
+       ForgetCF( &inSubtest->duplicateResults );
+       ForgetCF( &inSubtest->unexpectedResults );
+       free( inSubtest );
+}
+
+//===========================================================================================================================
+//     _DotLocalTestStartSubtest
+//===========================================================================================================================
+
+static OSStatus        _DotLocalTestStartSubtest( DotLocalTestContext *inContext )
+{
+       OSStatus                                err;
+       DotLocalSubtest *               subtest = NULL;
+       DNSServiceRef                   op              = NULL;
+       DNSServiceFlags                 flags;
+       
+       err = _DotLocalSubtestCreate( &subtest );
+       require_noerr( err, exit );
+       
+       if( inContext->state == kDotLocalTestState_GAIMDNSOnly )
+       {
+               ASPrintF( &subtest->queryName, "%s-2.local.", inContext->labelStr );
+               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+               
+               subtest->hasMDNSv4 = subtest->needMDNSv4 = true;
+               subtest->hasMDNSv6 = subtest->needMDNSv6 = true;
+               
+               subtest->addrMDNSv4 = htonl( 0x00000201 );                                      // 0.0.2.1
+               memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 );      // 2001:db8:2::2:1
+               subtest->addrMDNSv6[ 13 ] = 2;
+               subtest->addrMDNSv6[ 15 ] = 1;
+               
+               subtest->testDesc = kDotLocalTestSubtestDesc_GAIMDNSOnly;
+       }
+       
+       else if( inContext->state == kDotLocalTestState_GAIDNSOnly )
+       {
+               ASPrintF( &subtest->queryName, "tag-dns-only.%s.local.", inContext->labelStr );
+               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+               
+               subtest->hasDNSv4 = subtest->needDNSv4 = true;
+               subtest->hasDNSv6 = subtest->needDNSv6 = true;
+               
+               subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 );         // 203.0.113.1
+               memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 );         // 2001:db8:1::1
+               subtest->addrDNSv6[ 15 ] = 1;
+               
+               subtest->testDesc = kDotLocalTestSubtestDesc_GAIDNSOnly;
+       }
+       
+       else if( inContext->state == kDotLocalTestState_GAIBoth )
+       {
+               ASPrintF( &subtest->queryName, "%s.local.", inContext->labelStr );
+               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+               
+               subtest->hasDNSv4       = subtest->needDNSv4    = true;
+               subtest->hasDNSv6       = subtest->needDNSv6    = true;
+               subtest->hasMDNSv4      = subtest->needMDNSv4   = true;
+               subtest->hasMDNSv6      = subtest->needMDNSv6   = true;
+               
+               subtest->addrDNSv4 = htonl( kDNSServerBaseAddrV4 + 1 );         // 203.0.113.1
+               memcpy( subtest->addrDNSv6, kDNSServerBaseAddrV6, 16 );         // 2001:db8:1::1
+               subtest->addrDNSv6[ 15 ] = 1;
+               
+               subtest->addrMDNSv4 = htonl( 0x00000101 );                                      // 0.0.1.1
+               memcpy( subtest->addrMDNSv6, kMDNSReplierBaseAddrV6, 16 );      // 2001:db8:2::1:1
+               subtest->addrMDNSv6[ 13 ] = 1;
+               subtest->addrMDNSv6[ 15 ] = 1;
+               
+               subtest->testDesc = kDotLocalTestSubtestDesc_GAIBoth;
+       }
+       
+       else if( inContext->state == kDotLocalTestState_GAINeither )
+       {
+               ASPrintF( &subtest->queryName, "doesnotexit-%s.local.", inContext->labelStr );
+               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+               
+               subtest->testDesc = kDotLocalTestSubtestDesc_GAINeither;
+       }
+       
+       else if( inContext->state == kDotLocalTestState_GAINoSuchRecord )
+       {
+               ASPrintF( &subtest->queryName, "doesnotexit-dns.%s.local.", inContext->labelStr );
+               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+               
+               subtest->hasDNSv4 = subtest->needDNSv4 = true;
+               subtest->hasDNSv6 = subtest->needDNSv6 = true;
+               subtest->testDesc = kDotLocalTestSubtestDesc_GAINoSuchRecord;
+       }
+       
+       else if( inContext->state == kDotLocalTestState_QuerySRV )
+       {
+               ASPrintF( &subtest->queryName, "_http._tcp.srv-%u-%u-%u.%s%s.local.",
+                       kDotLocalTestSRV_Priority, kDotLocalTestSRV_Weight, kDotLocalTestSRV_Port, kDotLocalTestSRV_TargetStr,
+                       inContext->labelStr );
+               require_action_quiet( subtest->queryName, exit, err = kNoMemoryErr );
+               
+               subtest->needSRV        = true;
+               subtest->testDesc       = kDotLocalTestSubtestDesc_QuerySRV;
+       }
+       
+       else
+       {
+               err = kStateErr;
+               goto exit;
+       }
+       
+       // Start new operation.
+       
+       flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsReturnIntermediates;
+#if( TARGET_OS_WATCH )
+       flags |= kDNSServiceFlagsPathEvaluationDone;
+#endif
+       
+       subtest->startTime      = NanoTimeGetCurrent();
+       subtest->endTime        = kNanoTime_Invalid;
+       
+       if( inContext->state == kDotLocalTestState_QuerySRV )
+       {
+               op = inContext->connection;
+               err = DNSServiceQueryRecord( &op, flags, kDNSServiceInterfaceIndexAny, subtest->queryName,
+                       kDNSServiceType_SRV, kDNSServiceClass_IN, _DotLocalTestQueryRecordCallback, inContext );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               op = inContext->connection;
+               err = DNSServiceGetAddrInfo( &op, flags, kDNSServiceInterfaceIndexAny,
+                       kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, subtest->queryName, _DotLocalTestGAICallback, inContext );
+               require_noerr( err, exit );
+       }
+       
+       // Start timer.
+       
+       check( !inContext->timer );
+       err = DispatchTimerOneShotCreate( dispatch_time_seconds( kDotLocalTestSubtestDurationSecs ),
+               INT64_C_safe( kDotLocalTestSubtestDurationSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
+               _DotLocalTestTimerHandler, inContext, &inContext->timer );
+       require_noerr( err, exit );
+       dispatch_resume( inContext->timer );
+       
+       check( !inContext->op );
+       inContext->op = op;
+       op = NULL;
+       
+       check( !inContext->subtest );
+       inContext->subtest = subtest;
+       subtest = NULL;
+       
+exit:
+       if( subtest )   _DotLocalSubtestFree( subtest );
+       if( op )                DNSServiceRefDeallocate( op );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _DotLocalTestFinalizeSubtest
+//===========================================================================================================================
+
+#define kDotLocalTestReportKey_StartTime                               CFSTR( "startTime" )            // String.
+#define kDotLocalTestReportKey_EndTime                                 CFSTR( "endTime" )                      // String.
+#define kDotLocalTestReportKey_Success                                 CFSTR( "success" )                      // Boolean.
+#define kDotLocalTestReportKey_MDNSReplierCmd                  CFSTR( "replierCmd" )           // String.
+#define kDotLocalTestReportKey_DNSServerCmd                            CFSTR( "serverCmd" )            // String.
+#define kDotLocalTestReportKey_GetAddrInfoTests                        CFSTR( "testsGAI" )                     // Array of Dictionaries.
+#define kDotLocalTestReportKey_QuerySRVTests                   CFSTR( "testsQuerySRV" )        // Array of Dictionaries.
+#define kDotLocalTestReportKey_Description                             CFSTR( "description" )          // String.
+#define kDotLocalTestReportKey_QueryName                               CFSTR( "queryName" )            // String.
+#define kDotLocalTestReportKey_Error                                   CFSTR( "error" )                        // Integer.
+#define kDotLocalTestReportKey_Results                                 CFSTR( "results" )                      // Dictionary of Arrays.
+#define kDotLocalTestReportKey_CorrectResults                  CFSTR( "correct" )                      // Array of Strings
+#define kDotLocalTestReportKey_DuplicateResults                        CFSTR( "duplicates" )           // Array of Strings.
+#define kDotLocalTestReportKey_UnexpectedResults               CFSTR( "unexpected" )           // Array of Strings.
+#define kDotLocalTestReportKey_MissingResults                  CFSTR( "missing" )                      // Array of Strings.
+
+static OSStatus        _DotLocalTestFinalizeSubtest( DotLocalTestContext *inContext )
+{
+       OSStatus                                        err;
+       DotLocalSubtest *                       subtest;
+       CFMutableDictionaryRef          reportDict;
+       CFMutableDictionaryRef          resultsDict;
+       CFMutableArrayRef                       missingResults, reportArray;
+       char                                            startTime[ 32 ];
+       char                                            endTime[ 32 ];
+       
+       subtest = inContext->subtest;
+       inContext->subtest = NULL;
+       
+       subtest->endTime = NanoTimeGetCurrent();
+       _NanoTime64ToTimestamp( subtest->startTime, startTime, sizeof( startTime ) );
+       _NanoTime64ToTimestamp( subtest->endTime, endTime, sizeof( endTime ) );
+       
+       reportDict = NULL;
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &reportDict,
+               "{"
+                       "%kO=%s"        // startTime
+                       "%kO=%s"        // endTime
+                       "%kO=%s"        // queryName
+                       "%kO=%s"        // description
+                       "%kO={%@}"      // results
+               "}",
+               kDotLocalTestReportKey_StartTime,       startTime,
+               kDotLocalTestReportKey_EndTime,         endTime,
+               kDotLocalTestReportKey_QueryName,       subtest->queryName,
+               kDotLocalTestReportKey_Description,     subtest->testDesc,
+               kDotLocalTestReportKey_Results,         &resultsDict );
+       require_noerr( err, exit );
+       
+       missingResults = NULL;
+       switch( inContext->state )
+       {
+               case kDotLocalTestState_GAIMDNSOnly:
+               case kDotLocalTestState_GAIDNSOnly:
+               case kDotLocalTestState_GAIBoth:
+               case kDotLocalTestState_GAINeither:
+                       if( subtest->needDNSv4 || subtest->needDNSv6 || subtest->needMDNSv4 || subtest->needMDNSv6 )
+                       {
+                               err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
+                                       "["
+                                               "%.4a"  // Expected DNS IPv4 address
+                                               "%.16a" // Expected DNS IPv6 address
+                                               "%.4a"  // Expected MDNS IPv4 address
+                                               "%.16a" // Expected MDNS IPv6 address
+                                       "]",
+                                       subtest->needDNSv4  ? &subtest->addrDNSv4  : NULL,
+                                       subtest->needDNSv6  ?  subtest->addrDNSv6  : NULL,
+                                       subtest->needMDNSv4 ? &subtest->addrMDNSv4 : NULL,
+                                       subtest->needMDNSv6 ?  subtest->addrMDNSv6 : NULL );
+                               require_noerr( err, exit );
+                       }
+                       break;
+               
+               case kDotLocalTestState_QuerySRV:
+                       if( subtest->needSRV )
+                       {
+                               err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
+                                       "["
+                                               "%s"    // Expected SRV record data as a string.
+                                       "]",
+                                       kDotLocalTestSRV_ResultStr );
+                               require_noerr( err, exit );
+                       }
+                       break;
+               
+               case kDotLocalTestState_GAINoSuchRecord:
+                       if( subtest->needDNSv4 || subtest->needDNSv6 )
+                       {
+                               err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &missingResults,
+                                       "["
+                                               "%s" // No Such Record (A)
+                                               "%s" // No Such Record (AAAA)
+                                       "]",
+                                       subtest->needDNSv4 ? kNoSuchRecordAStr    : NULL,
+                                       subtest->needDNSv6 ? kNoSuchRecordAAAAStr : NULL );
+                               require_noerr( err, exit );
+                       }
+                       break;
+               
+               default:
+                       err = kStateErr;
+                       goto exit;
+       }
+       
+       CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_CorrectResults, subtest->correctResults );
+       
+       if( missingResults )
+       {
+               CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_MissingResults, missingResults );
+               ForgetCF( &missingResults );
+               if( !subtest->error ) subtest->error = kNotFoundErr;
+       }
+       
+       if( CFArrayGetCount( subtest->unexpectedResults ) > 0 )
+       {
+               CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_UnexpectedResults, subtest->unexpectedResults );
+               if( !subtest->error ) subtest->error = kUnexpectedErr;
+       }
+       
+       if( CFArrayGetCount( subtest->duplicateResults ) > 0 )
+       {
+               CFDictionarySetValue( resultsDict, kDotLocalTestReportKey_DuplicateResults, subtest->duplicateResults );
+               if( !subtest->error ) subtest->error = kDuplicateErr;
+       }
+       
+       if( subtest->error ) inContext->testFailed = true;
+       err = CFDictionarySetInt64( reportDict, kDotLocalTestReportKey_Error, subtest->error );
+       require_noerr( err, exit );
+       
+       reportArray = ( inContext->state == kDotLocalTestState_QuerySRV ) ? inContext->reportsQuerySRV : inContext->reportsGAI;
+       CFArrayAppendValue( reportArray, reportDict );
+       
+exit:
+       _DotLocalSubtestFree( subtest );
+       CFReleaseNullSafe( reportDict );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _DotLocalTestFinalizeAndExit
+//===========================================================================================================================
+
+static void    _DotLocalTestFinalizeAndExit( DotLocalTestContext *inContext )
+{
+       OSStatus                                err;
+       CFPropertyListRef               plist;
+       char                                    timestampStart[ 32 ];
+       char                                    timestampEnd[ 32 ];
+       
+       check( !inContext->subtest );
+       inContext->endTime = NanoTimeGetCurrent();
+       
+       if( inContext->replierPID != -1 )
+       {
+               kill( inContext->replierPID, SIGTERM );
+               inContext->replierPID = -1;
+       }
+       if( inContext->serverPID != -1 )
+       {
+               kill( inContext->serverPID, SIGTERM );
+               inContext->serverPID = -1;
+       }
+       err = DNSServiceRemoveRecord( inContext->connection, inContext->localSOARef, 0 );
+       require_noerr( err, exit );
+       
+       _NanoTime64ToTimestamp( inContext->startTime, timestampStart, sizeof( timestampStart ) );
+       _NanoTime64ToTimestamp( inContext->endTime, timestampEnd, sizeof( timestampEnd ) );
+       
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+               "{"
+                       "%kO=%s"        // startTime
+                       "%kO=%s"        // endTime
+                       "%kO=%O"        // testsGAI
+                       "%kO=%O"        // testsQuerySRV
+                       "%kO=%b"        // success
+                       "%kO=%s"        // replierCmd
+                       "%kO=%s"        // serverCmd
+               "}",
+               kDotLocalTestReportKey_StartTime,                       timestampStart,
+               kDotLocalTestReportKey_EndTime,                         timestampEnd,
+               kDotLocalTestReportKey_GetAddrInfoTests,        inContext->reportsGAI,
+               kDotLocalTestReportKey_QuerySRVTests,           inContext->reportsQuerySRV,
+               kDotLocalTestReportKey_Success,                         inContext->testFailed ? false : true,
+               kDotLocalTestReportKey_MDNSReplierCmd,          inContext->replierCmd,
+               kDotLocalTestReportKey_DNSServerCmd,            inContext->serverCmd );
+       require_noerr( err, exit );
+       
+       ForgetCF( &inContext->reportsGAI );
+       ForgetCF( &inContext->reportsQuerySRV );
+       
+       err = OutputPropertyList( plist, inContext->outputFormat, inContext->outputFilePath );
+       CFRelease( plist );
+       require_noerr( err, exit );
+       
+       exit( inContext->testFailed ? 2 : 0 );
+       
+exit:
+       ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//     _DotLocalTestProbeQueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _DotLocalTestProbeQueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       DotLocalTestContext * const             context = (DotLocalTestContext *) inContext;
+       
+       Unused( inInterfaceIndex );
+       Unused( inFullName );
+       Unused( inType );
+       Unused( inClass );
+       Unused( inRDataLen );
+       Unused( inRDataPtr );
+       Unused( inTTL );
+       
+       check( context->state == kDotLocalTestState_Preparing );
+       
+       require_quiet( ( inFlags & kDNSServiceFlagsAdd ) && !inError, exit );
+       
+       if( inSDRef == context->op )
+       {
+               DNSServiceForget( &context->op );
+               context->serverIsReady = true;
+       }
+       else if( inSDRef == context->op2 )
+       {
+               DNSServiceForget( &context->op2 );
+               context->replierIsReady = true;
+       }
+       
+       if( context->registeredSOA && context->serverIsReady && context->replierIsReady )
+       {
+               _DotLocalTestStateMachine( context );
+       }
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     _DotLocalTestRegisterRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _DotLocalTestRegisterRecordCallback(
+               DNSServiceRef           inSDRef,
+               DNSRecordRef            inRecordRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               void *                          inContext )
+{
+       DotLocalTestContext * const             context = (DotLocalTestContext *) inContext;
+       
+       Unused( inSDRef );
+       Unused( inRecordRef );
+       Unused( inFlags );
+       
+       if( inError ) ErrQuit( 1, "error: local. SOA record registration failed: %#m\n", inError );
+       
+       if( !context->registeredSOA )
+       {
+               context->registeredSOA = true;
+               if( context->serverIsReady && context->replierIsReady ) _DotLocalTestStateMachine( context );
+       }
+}
+
+//===========================================================================================================================
+//     _DotLocalTestTimerHandler
+//===========================================================================================================================
+
+static void    _DotLocalTestTimerHandler( void *inContext )
+{
+       _DotLocalTestStateMachine( (DotLocalTestContext *) inContext );
+}
+
+//===========================================================================================================================
+//     _DotLocalTestGAICallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _DotLocalTestGAICallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                                                err;
+       DotLocalTestContext * const             context = (DotLocalTestContext *) inContext;
+       DotLocalSubtest * const                 subtest = context->subtest;
+       const sockaddr_ip * const               sip             = (const sockaddr_ip *) inSockAddr;
+       
+       Unused( inSDRef );
+       Unused( inInterfaceIndex );
+       Unused( inHostname );
+       Unused( inTTL );
+       
+       require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
+       require_action_quiet( ( sip->sa.sa_family == AF_INET ) || ( sip->sa.sa_family == AF_INET6 ), exit, err = kTypeErr );
+       
+       if( context->state == kDotLocalTestState_GAINoSuchRecord )
+       {
+               if( inError == kDNSServiceErr_NoSuchRecord )
+               {
+                       CFMutableArrayRef               array = NULL;   
+                       const char *                    noSuchRecordStr;
+                       
+                       if( sip->sa.sa_family == AF_INET )
+                       {
+                               array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
+                               subtest->needDNSv4 = false;
+                               
+                               noSuchRecordStr = kNoSuchRecordAStr;
+                       }
+                       else
+                       {
+                               array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
+                               subtest->needDNSv6 = false;
+                               
+                               noSuchRecordStr = kNoSuchRecordAAAAStr;
+                       }
+                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", noSuchRecordStr );
+                       require_noerr( err, fatal );
+               }
+               else if( !inError )
+               {
+                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%##a", sip );
+                       require_noerr( err, fatal );
+               }
+               else
+               {
+                       err = inError;
+                       goto exit;
+               }
+       }
+       else
+       {
+               if( !inError )
+               {
+                       CFMutableArrayRef               array = NULL;   
+                       
+                       if( sip->sa.sa_family == AF_INET )
+                       {
+                               const uint32_t          addrV4 = sip->v4.sin_addr.s_addr;
+                               
+                               if( subtest->hasDNSv4 && ( addrV4 == subtest->addrDNSv4 ) )
+                               {
+                                       array = subtest->needDNSv4 ? subtest->correctResults : subtest->duplicateResults;
+                                       subtest->needDNSv4 = false;
+                               }
+                               else if( subtest->hasMDNSv4 && ( addrV4 == subtest->addrMDNSv4 ) )
+                               {
+                                       array = subtest->needMDNSv4 ? subtest->correctResults : subtest->duplicateResults;
+                                       subtest->needMDNSv4 = false;
+                               }
+                       }
+                       else
+                       {
+                               const uint8_t * const           addrV6 = sip->v6.sin6_addr.s6_addr;
+                               
+                               if( subtest->hasDNSv6 && ( memcmp( addrV6, subtest->addrDNSv6, 16 ) == 0 ) )
+                               {
+                                       array = subtest->needDNSv6 ? subtest->correctResults : subtest->duplicateResults;
+                                       subtest->needDNSv6 = false;
+                               }
+                               else if( subtest->hasMDNSv6 && ( memcmp( addrV6, subtest->addrMDNSv6, 16 ) == 0 ) )
+                               {
+                                       array = subtest->needMDNSv6 ? subtest->correctResults : subtest->duplicateResults;
+                                       subtest->needMDNSv6 = false;
+                               }
+                       }
+                       if( !array ) array = subtest->unexpectedResults;
+                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%##a", sip );
+                       require_noerr( err, fatal );
+               }
+               else if( inError == kDNSServiceErr_NoSuchRecord )
+               {
+                       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpectedResults, "%s",
+                               ( sip->sa.sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr );
+                       require_noerr( err, fatal );
+               }
+               else
+               {
+                       err = inError;
+                       goto exit;
+               }
+       }
+       
+exit:
+       if( err )
+       {
+               subtest->error = err;
+               _DotLocalTestStateMachine( context );
+       }
+       return;
+       
+fatal:
+       ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//     _DotLocalTestQueryRecordCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _DotLocalTestQueryRecordCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                                                        err;
+       DotLocalTestContext * const                     context = (DotLocalTestContext *) inContext;
+       DotLocalSubtest * const                         subtest = context->subtest;
+       const dns_fixed_fields_srv *            fields;
+       const uint8_t *                                         target;
+       const uint8_t *                                         ptr;
+       const uint8_t *                                         end;
+       char *                                                          rdataStr;
+       unsigned int                                            priority, weight, port;
+       CFMutableArrayRef                                       array;
+       
+       Unused( inSDRef );
+       Unused( inInterfaceIndex );
+       Unused( inFullName );
+       Unused( inTTL );
+       
+       check( context->state == kDotLocalTestState_QuerySRV );
+       
+       err = inError;
+       require_noerr_quiet( err, exit );
+       require_action_quiet( inFlags & kDNSServiceFlagsAdd, exit, err = kFlagErr );
+       require_action_quiet( ( inType == kDNSServiceType_SRV ) && ( inClass == kDNSServiceClass_IN ), exit, err = kTypeErr );
+       require_action_quiet( inRDataLen > sizeof( dns_fixed_fields_srv ), exit, err = kSizeErr );
+       
+       fields          = (const dns_fixed_fields_srv *) inRDataPtr;
+       priority        = dns_fixed_fields_srv_get_priority( fields );
+       weight          = dns_fixed_fields_srv_get_weight( fields );
+       port            = dns_fixed_fields_srv_get_port( fields );
+       target          = (const uint8_t *) &fields[ 1 ];
+       end                     = ( (const uint8_t *) inRDataPtr ) + inRDataLen;
+       for( ptr = target; ( ptr < end ) && ( *ptr != 0 ); ptr += ( 1 + *ptr ) ) {}
+       
+       if( ( priority == kDotLocalTestSRV_Priority ) &&
+               ( weight   == kDotLocalTestSRV_Weight )   &&
+               ( port     == kDotLocalTestSRV_Port )     &&
+               ( ptr < end ) && DomainNameEqual( target, kDotLocalTestSRV_TargetName ) )
+       {
+               array = subtest->needSRV ? subtest->correctResults : subtest->duplicateResults;
+               subtest->needSRV = false;
+       }
+       else
+       {
+               array = subtest->unexpectedResults;
+       }
+       
+       rdataStr = NULL;
+       DNSRecordDataToString( inRDataPtr, inRDataLen, kDNSServiceType_SRV, NULL, 0, &rdataStr );
+       if( !rdataStr )
+       {
+               ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, inRDataLen );
+               require_action( rdataStr, fatal, err = kNoMemoryErr );
+       }
+       
+       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, array, "%s", rdataStr );
+       free( rdataStr );
+       require_noerr( err, fatal );
+       
+exit:
+       if( err )
+       {
+               subtest->error = err;
+               _DotLocalTestStateMachine( context );
+       }
+       return;
+       
+fatal:
+       ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//     ProbeConflictTestCmd
+//===========================================================================================================================
+
+#define kProbeConflictTestService_DefaultName          "pctest-name"
+#define kProbeConflictTestService_Port                         60000
+
+#define kProbeConflictTestTXTPtr               "\x13" "PROBE-CONFLICT-TEST"
+#define kProbeConflictTestTXTLen               sizeof_string( kProbeConflictTestTXTPtr )
+
+typedef struct
+{
+       const char *            description;
+       const char *            program;
+       Boolean                         expectsRename;
+       
+}      ProbeConflictTestCase;
+
+#define kPCTProgPreWait                        "wait 1000;"    // Wait 1 second before sending gratuitous response.
+#define kPCTProgPostWait               "wait 8000;"    // Wait 8 seconds after sending gratuitous response.
+                                                                                               // This allows ~2.75 seconds for probing and ~5 seconds for a rename.
+
+static const ProbeConflictTestCase             kProbeConflictTestCases[] =
+{
+       // No conflicts
+       
+       { "No probe conflicts.",                       kPCTProgPreWait "probes n-n-n;"       "send;" kPCTProgPostWait, false },
+       
+       // One multicast probe conflict
+       
+       { "One multicast probe conflict (1).",         kPCTProgPreWait "probes m;"           "send;" kPCTProgPostWait, false },
+       { "One multicast probe conflict (2).",         kPCTProgPreWait "probes n-m;"         "send;" kPCTProgPostWait, false },
+       { "One multicast probe conflict (3).",         kPCTProgPreWait "probes n-n-m;"       "send;" kPCTProgPostWait, false },
+       
+       // One unicast probe conflict
+       
+       { "One unicast probe conflict (1).",           kPCTProgPreWait "probes u;"           "send;" kPCTProgPostWait, true },
+       { "One unicast probe conflict (2).",           kPCTProgPreWait "probes n-u;"         "send;" kPCTProgPostWait, true },
+       { "One unicast probe conflict (3).",           kPCTProgPreWait "probes n-n-u;"       "send;" kPCTProgPostWait, true },
+       
+       // One multicast and one unicast probe conflict
+       
+       { "Multicast and unicast probe conflict (1).", kPCTProgPreWait "probes m-u;"         "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (2).", kPCTProgPreWait "probes m-n-u;"       "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (3).", kPCTProgPreWait "probes m-n-n-u;"     "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (4).", kPCTProgPreWait "probes n-m-u;"       "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (5).", kPCTProgPreWait "probes n-m-n-u;"     "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (6).", kPCTProgPreWait "probes n-m-n-n-u;"   "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (7).", kPCTProgPreWait "probes n-n-m-u;"     "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (8).", kPCTProgPreWait "probes n-n-m-n-u;"   "send;" kPCTProgPostWait, true },
+       { "Multicast and unicast probe conflict (9).", kPCTProgPreWait "probes n-n-m-n-n-u;" "send;" kPCTProgPostWait, true },
+       
+       // Two multicast probe conflicts
+       
+       { "Two multicast probe conflicts (1).",        kPCTProgPreWait "probes m-m;"         "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (2).",        kPCTProgPreWait "probes m-n-m;"       "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (3).",        kPCTProgPreWait "probes m-n-n-m;"     "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (4).",        kPCTProgPreWait "probes n-m-m;"       "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (5).",        kPCTProgPreWait "probes n-m-n-m-n;"   "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (6).",        kPCTProgPreWait "probes n-m-n-n-m;"   "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (7).",        kPCTProgPreWait "probes n-n-m-m;"     "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (8).",        kPCTProgPreWait "probes n-n-m-n-m;"   "send;" kPCTProgPostWait, true },
+       { "Two multicast probe conflicts (9).",        kPCTProgPreWait "probes n-n-m-n-n-m;" "send;" kPCTProgPostWait, true },
+};
+
+#define kProbeConflictTestCaseCount            countof( kProbeConflictTestCases )
+
+typedef struct
+{
+       DNSServiceRef                   registration;   // Test service registration.
+       NanoTime64                              testStartTime;  // Test's start time.
+       NanoTime64                              startTime;              // Current test case's start time.
+       MDNSColliderRef                 collider;               // mDNS collider object.
+       CFMutableArrayRef               results;                // Array of test case results.
+       char *                                  serviceName;    // Test service's instance name as a string. (malloced)
+       char *                                  serviceType;    // Test service's service type as a string. (malloced)
+       uint8_t *                               recordName;             // FQDN of collider's record (same as test service's SRV+TXT records). (malloced)
+       unsigned int                    testCaseIndex;  // Index of the current test case.
+       uint32_t                                ifIndex;                // Index of the interface that the collider is to operate on.
+       char *                                  outputFilePath; // File to write test results to. If NULL, then write to stdout. (malloced)
+       OutputFormatType                outputFormat;   // Format of test report output.
+       Boolean                                 registered;             // True if the test service instance is currently registered.
+       Boolean                                 testFailed;             // True if at least one test case failed.
+       
+}      ProbeConflictTestContext;
+
+static void DNSSD_API
+       _ProbeConflictTestRegisterCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inType,
+               const char *            inDomain,
+               void *                          inContext );
+static void            _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError );
+static OSStatus        _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext );
+static OSStatus        _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed );
+static void            _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext ) ATTRIBUTE_NORETURN;
+
+static void    ProbeConflictTestCmd( void )
+{
+       OSStatus                                                err;
+       ProbeConflictTestContext *              context;
+       const char *                                    serviceName;
+       char                                                    tag[ 6 + 1 ];
+       
+       context = (ProbeConflictTestContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       if( gProbeConflictTest_Interface )
+       {
+               err = InterfaceIndexFromArgString( gProbeConflictTest_Interface, &context->ifIndex );
+               require_noerr_quiet( err, exit );
+       }
+       else
+       {
+               err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_All, NULL, &context->ifIndex );
+               require_noerr_quiet( err, exit );
+       }
+       
+       if( gProbeConflictTest_OutputFilePath )
+       {
+               context->outputFilePath = strdup( gProbeConflictTest_OutputFilePath );
+               require_action( context->outputFilePath, exit, err = kNoMemoryErr );
+       }
+       
+       err = OutputFormatFromArgString( gProbeConflictTest_OutputFormat, &context->outputFormat );
+       require_noerr_quiet( err, exit );
+       
+       context->results = CFArrayCreateMutable( NULL, kProbeConflictTestCaseCount, &kCFTypeArrayCallBacks );
+       require_action( context->results, exit, err = kNoMemoryErr );
+       
+       serviceName = gProbeConflictTest_UseComputerName ? NULL : kProbeConflictTestService_DefaultName;
+       
+       ASPrintF( &context->serviceType, "_pctest-%s._udp",
+               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+       require_action( context->serviceType, exit, err = kNoMemoryErr );
+       
+       context->testStartTime = NanoTimeGetCurrent();
+       err = DNSServiceRegister( &context->registration, 0, context->ifIndex, serviceName, context->serviceType, "local.",
+               NULL, htons( kProbeConflictTestService_Port ), 0, NULL, _ProbeConflictTestRegisterCallback, context );
+       require_noerr( err, exit );
+       
+       err = DNSServiceSetDispatchQueue( context->registration, dispatch_get_main_queue() );
+       require_noerr( err, exit );
+       
+       dispatch_main();
+       
+exit:
+       exit( 1 );
+}
+
+//===========================================================================================================================
+//     _ProbeConflictTestRegisterCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _ProbeConflictTestRegisterCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inType,
+               const char *            inDomain,
+               void *                          inContext )
+{
+       OSStatus                                                                err;
+       ProbeConflictTestContext * const                context = (ProbeConflictTestContext *) inContext;
+       
+       Unused( inSDRef );
+       Unused( inType );
+       Unused( inDomain );
+       
+       err = inError;
+       require_noerr( err, exit );
+       
+       if( !context->registered )
+       {
+               if( inFlags & kDNSServiceFlagsAdd )
+               {
+                       uint8_t *                       ptr;
+                       size_t                          recordNameLen;
+                       unsigned int            len;
+                       uint8_t                         name[ kDomainNameLengthMax ];
+                       
+                       context->registered = true;
+                       
+                       FreeNullSafe( context->serviceName );
+                       context->serviceName = strdup( inName );
+                       require_action( context->serviceName, exit, err = kNoMemoryErr );
+                       
+                       err = DomainNameFromString( name, context->serviceName, NULL );
+                       require_noerr( err, exit );
+                       
+                       err = DomainNameAppendString( name, context->serviceType, NULL );
+                       require_noerr( err, exit );
+                       
+                       err = DomainNameAppendString( name, "local", NULL );
+                       require_noerr( err, exit );
+                       
+                       ForgetMem( &context->recordName );
+                       err = DomainNameDup( name, &context->recordName, &recordNameLen );
+                       require_noerr( err, exit );
+                       require_fatal( recordNameLen > 0, "Record name length is zero." );      // Prevents dubious static analyzer warning.
+                       
+                       // Make the first label all caps so that it's easier to spot in system logs.
+                       
+                       ptr = context->recordName;
+                       for( len = *ptr++; len > 0; --len, ++ptr ) *ptr = (uint8_t) toupper_safe( *ptr );
+                       
+                       err = _ProbeConflictTestStartNextTest( context );
+                       require_noerr( err, exit );
+               }
+       }
+       else
+       {
+               if( !( inFlags & kDNSServiceFlagsAdd ) )
+               {
+                       context->registered = false;
+                       err = _ProbeConflictTestStopCurrentTest( context, true );
+                       require_noerr( err, exit );
+               }
+       }
+       err = kNoErr;
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     _ProbeConflictTestColliderStopHandler
+//===========================================================================================================================
+
+static void    _ProbeConflictTestColliderStopHandler( void *inContext, OSStatus inError )
+{
+       OSStatus                                                                err;
+       ProbeConflictTestContext * const                context = (ProbeConflictTestContext *) inContext;
+       
+       err = inError;
+       require_noerr_quiet( err, exit );
+       
+       ForgetCF( &context->collider );
+       
+       err = _ProbeConflictTestStopCurrentTest( context, false );
+       require_noerr( err, exit );
+       
+       err = _ProbeConflictTestStartNextTest( context );
+       require_noerr( err, exit );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     _ProbeConflictTestStartNextTest
+//===========================================================================================================================
+
+static OSStatus        _ProbeConflictTestStartNextTest( ProbeConflictTestContext *inContext )
+{
+       OSStatus                                                        err;
+       const ProbeConflictTestCase *           testCase;
+       
+       check( !inContext->collider );
+       
+       if( inContext->testCaseIndex < kProbeConflictTestCaseCount )
+       {
+               testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
+       }
+       else
+       {
+               _ProbeConflictTestFinalizeAndExit( inContext );
+       }
+       
+       err = MDNSColliderCreate( dispatch_get_main_queue(), &inContext->collider );
+       require_noerr( err, exit );
+       
+       err = MDNSColliderSetProgram( inContext->collider, testCase->program );
+       require_noerr( err, exit );
+       
+       err = MDNSColliderSetRecord( inContext->collider, inContext->recordName, kDNSServiceType_TXT,
+               kProbeConflictTestTXTPtr, kProbeConflictTestTXTLen );
+       require_noerr( err, exit );
+       
+       MDNSColliderSetProtocols( inContext->collider, kMDNSColliderProtocol_IPv4 );
+       MDNSColliderSetInterfaceIndex( inContext->collider, inContext->ifIndex );
+       MDNSColliderSetStopHandler( inContext->collider, _ProbeConflictTestColliderStopHandler, inContext );
+       
+       inContext->startTime = NanoTimeGetCurrent();
+       err = MDNSColliderStart( inContext->collider );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ProbeConflictTestStopCurrentTest
+//===========================================================================================================================
+
+#define kProbeConflictTestCaseResultKey_Description                    CFSTR( "description" )
+#define kProbeConflictTestCaseResultKey_StartTime                      CFSTR( "startTime" )
+#define kProbeConflictTestCaseResultKey_EndTime                                CFSTR( "endTime" )
+#define kProbeConflictTestCaseResultKey_ExpectedRename         CFSTR( "expectedRename" )
+#define kProbeConflictTestCaseResultKey_ServiceName                    CFSTR( "serviceName" )
+#define kProbeConflictTestCaseResultKey_Passed                         CFSTR( "passed" )
+
+static OSStatus        _ProbeConflictTestStopCurrentTest( ProbeConflictTestContext *inContext, Boolean inRenamed )
+{
+       OSStatus                                                        err;
+       const ProbeConflictTestCase *           testCase;
+       NanoTime64                                                      now;
+       Boolean                                                         passed;
+       char                                                            startTime[ 32 ];
+       char                                                            endTime[ 32 ];
+       
+       now = NanoTimeGetCurrent();
+       
+       if( inContext->collider )
+       {
+               MDNSColliderSetStopHandler( inContext->collider, NULL, NULL );
+               MDNSColliderStop( inContext->collider );
+               CFRelease( inContext->collider );
+               inContext->collider = NULL;
+       }
+       
+       testCase = &kProbeConflictTestCases[ inContext->testCaseIndex ];
+       passed = ( ( testCase->expectsRename && inRenamed ) || ( !testCase->expectsRename && !inRenamed ) ) ? true : false;
+       if( !passed ) inContext->testFailed = true;
+       
+       _NanoTime64ToTimestamp( inContext->startTime, startTime, sizeof( startTime ) );
+       _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+       
+       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, inContext->results,
+               "{"
+                       "%kO=%s"        // description
+                       "%kO=%b"        // expectedRename
+                       "%kO=%s"        // startTime
+                       "%kO=%s"        // endTime
+                       "%kO=%s"        // serviceName
+                       "%kO=%b"        // passed
+               "}",
+               kProbeConflictTestCaseResultKey_Description,    testCase->description,
+               kProbeConflictTestCaseResultKey_ExpectedRename, testCase->expectsRename,
+               kProbeConflictTestCaseResultKey_StartTime,              startTime,
+               kProbeConflictTestCaseResultKey_EndTime,                endTime,
+               kProbeConflictTestCaseResultKey_ServiceName,    inContext->serviceName,
+               kProbeConflictTestCaseResultKey_Passed,                 passed );
+       require_noerr( err, exit );
+       
+       ++inContext->testCaseIndex;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ProbeConflictTestFinalizeAndExit
+//===========================================================================================================================
+
+#define kProbeConflictTestReportKey_StartTime          CFSTR( "startTime" )
+#define kProbeConflictTestReportKey_EndTime                    CFSTR( "endTime" )
+#define kProbeConflictTestReportKey_ServiceType                CFSTR( "serviceType" )
+#define kProbeConflictTestReportKey_Results                    CFSTR( "results" )
+#define kProbeConflictTestReportKey_Passed                     CFSTR( "passed" )
+
+static void    _ProbeConflictTestFinalizeAndExit( ProbeConflictTestContext *inContext )
+{
+       OSStatus                                err;
+       CFPropertyListRef               plist;
+       NanoTime64                              now;
+       char                                    startTime[ 32 ];
+       char                                    endTime[ 32 ];
+       
+       now = NanoTimeGetCurrent();
+       
+       check( !inContext->collider );
+       
+       _NanoTime64ToTimestamp( inContext->testStartTime, startTime, sizeof( startTime ) );
+       _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+       
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+               "{"
+                       "%kO=%s"        // startTime
+                       "%kO=%s"        // endTime
+                       "%kO=%s"        // serviceType
+                       "%kO=%O"        // results
+                       "%kO=%b"        // passed
+               "}",
+               kProbeConflictTestReportKey_StartTime,          startTime,
+               kProbeConflictTestReportKey_EndTime,            endTime,
+               kProbeConflictTestReportKey_ServiceType,        inContext->serviceType,
+               kProbeConflictTestReportKey_Results,            inContext->results,
+               kProbeConflictTestReportKey_Passed,                     inContext->testFailed ? false : true );
+       require_noerr( err, exit );
+       ForgetCF( &inContext->results );
+       
+       err = OutputPropertyList( plist, inContext->outputFormat, inContext->outputFilePath );
+       CFRelease( plist );
+       require_noerr( err, exit );
+       
+       exit( inContext->testFailed ? 2 : 0 );
+       
+exit:
+       ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedsTestCmd
+//===========================================================================================================================
+
+#define NOTIFICATION_TIME_THRESHOLD 1500    // The maximum wating time allowed before notification happens
+#define TEST_REPETITION             2       // the number of repetition that one test has to passed
+#define LOOPBACK_INTERFACE_NAME     "lo0"
+#define WIFI_TEST_QUESTION_NAME     "www.example.com"
+#define EXPENSIVE_CONSTRAINED_MAX_RETRIES 1
+#define EXPENSIVE_CONSTRAINED_TEST_INTERVAL 5
+// Use "-n tag-expensive-test.ttl-86400.d.test." to run the test locally
+// #define LOOPBACK_TEST_QUESTION_NAME "tag-expensive-test.ttl-86400.d.test."
+
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_START_TIME                CFSTR( "Start Time" )
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_END_TIME                  CFSTR( "End Time" )
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_ALL_PASSED                CFSTR( "All Tests Passed" )
+#define EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_SUBTEST_RESULT            CFSTR( "Subtest Results" )
+
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_START_TIME             CFSTR( "Start Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_END_TIME               CFSTR( "End Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_QNAME                  CFSTR( "Question Name" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_FLAGS                  CFSTR( "DNS Service Flags" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_PROTOCOLS              CFSTR( "Protocols" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_INDEX        CFSTR( "Interface Index" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_NAME         CFSTR( "Interface Name" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_RESULT                 CFSTR( "Result" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_ERROR                  CFSTR( "Error Description" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_TEST_PROGRESS          CFSTR( "Test Progress" )
+
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_START_TIME           CFSTR( "Start Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_END_TIME             CFSTR( "End Time" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_STATE                CFSTR( "State" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPECT_RESULT        CFSTR( "Expected Result" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_ACTUAL_RESULT        CFSTR( "Actual Result" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPENSIVE_PREV_NOW   CFSTR( "Expensive Prev->Now" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CONSTRAINED_PREV_NOW CFSTR( "Constrained Prev->Now" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CALL_BACK            CFSTR( "Call Back" )
+
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_TIMESTAMP       CFSTR( "Timestamp" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_NAME            CFSTR( "Answer Name" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_FLAGS           CFSTR( "Add or Remove" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_INTERFACE       CFSTR( "Interface Index" )
+#define EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_ADDRESS         CFSTR( "Address" )
+
+// All the states that ends with _PREPARE represents the state where the test state is reset and initialized.
+enum ExpensiveConstrainedTestState
+{
+    TEST_BEGIN,
+    TEST_EXPENSIVE_PREPARE,
+    TEST_EXPENSIVE,                     // Test if mDNSResponder can handle "expensive" status change of the corresponding interface
+    TEST_CONSTRAINED_PREPARE,
+    TEST_CONSTRAINED,                   // Test if mDNSResponder can handle "constrained" status change of the corresponding interface
+    TEST_EXPENSIVE_CONSTRAINED_PREPARE,
+    TEST_EXPENSIVE_CONSTRAINED,          // Test if mDNSResponder can handle "expensive" and "constrained" status change of the corresponding interface at the same time
+    TEST_FAILED,
+    TEST_SUCCEEDED
+};
+enum ExpensiveConstrainedTestOperation
+{
+    RESULT_ADD, // received response for the given query, which means mDNSResponder is able to send out the query over the interface, because the interface status is changed.
+    RESULT_RMV, // received negative response for the given query, which means mDNSResponder is not able to send out the query over the interface, because the interface status is changed.
+    NO_UPDATE   // no status update notification
+};
+
+typedef struct
+{
+    uint32_t                    subtestIndex;           // The index of parameter for the subtest
+    DNSServiceRef               opRef;                  // sdRef for the DNSServiceGetAddrInfo operation.
+    const char *                name;                   // Hostname to resolve.
+    DNSServiceFlags             flags;                  // Flags argument for DNSServiceGetAddrInfo().
+    DNSServiceProtocol          protocols;              // Protocols argument for DNSServiceGetAddrInfo().
+    uint32_t                    ifIndex;                // Interface index argument for DNSServiceGetAddrInfo().
+    char                        ifName[IFNAMSIZ];       // Interface name for the given interface index.
+    dispatch_source_t           timer;                  // The test will check if the current behavior is valid, which is called by
+                                                        // the timer per 2s.
+    pid_t                       serverPID;
+    Boolean                     isExpensivePrev;        // If the interface is expensive in the previous test step.
+    Boolean                     isExpensiveNow;         // If the interface is expensive now.
+    Boolean                     isConstrainedPrev;      // If the interface is constrained in the previous test step.
+    Boolean                     isConstrainedNow;       // If the interface is constrained now.
+    Boolean                     startFromExpensive;     // All the test will start from expensive/constrained interface, so there won's be an answer until the interface is changed.
+    uint8_t                     numOfRetries;           // the number of retries we can have if the test fail
+    struct timeval              updateTime;             // The time when interface status(expensive or constrained) is changed.
+    struct timeval              notificationTime;       // The time when callback function, which is passed to DNSServiceGetAddrInfo, gets called.
+    uint32_t                    counter;                // To record how many times the test has repeated.
+    enum ExpensiveConstrainedTestState          state;              // The current test state.
+    enum ExpensiveConstrainedTestOperation      expectedOperation;  // the test expects this kind of notification
+    enum ExpensiveConstrainedTestOperation      operation;          // represents what notification the callback function gets.
+
+    NanoTime64                  testReport_startTime;       // when the entire test starts
+    CFMutableArrayRef           subtestReport;              // stores the log message for every subtest
+    NanoTime64                  subtestReport_startTime;    // when the subtest starts
+    CFMutableArrayRef           subtestProgress;            // one test iteration
+    NanoTime64                  subtestProgress_startTime;  // when the test iteration starts
+    CFMutableArrayRef           subtestProgress_callBack;   // array of ADD/REMOVE events
+    char *                      outputFilePath;             // File to write test results to. If NULL, then write to stdout. (malloced)
+    OutputFormatType            outputFormat;               // Format of test report output.
+} ExpensiveConstrainedContext;
+
+// structure that controls how the subtest is run
+typedef struct
+{
+    const char  *qname;                 // the name of the query, when the ends with ".d.test.", test will send query to local DNS server
+    Boolean     deny_expensive;         // if the query should avoid using expensive interface
+    Boolean     deny_constrained;       // if the query should avoid using constrained interface
+    Boolean     start_from_expensive;   // if the query should starts from using an expensive interface
+    Boolean     ipv4_query;             // only allow IPv4 query
+    Boolean     ipv6_query;             // only allow IPv6 query
+    int8_t      test_passed;            // if the subtest passes
+} ExpensiveConstrainedTestParams;
+
+static ExpensiveConstrainedTestParams   ExpensiveConstrainedSubtestParams[] =
+{
+//  qname                                                   deny_expensive  deny_constrained    start_from_expensive    ipv4_query  ipv6_query
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           false,              false,                  true,       true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           false,              true,                   true,       true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    false,          true,               false,                  true,       true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    false,          true,               true,                   true,       true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           true,               false,                  true,       true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           true,               true,                   true,       true,       -1},
+// IPv4 Only
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           false,              false,                  true,       false,      -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           false,              true,                   true,       false,      -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    false,          true,               false,                  true,       false,      -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    false,          true,               true,                   true,       false,      -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           true,               false,                  true,       false,      -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           true,               true,                   true,       false,      -1},
+// IPv6 Only
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           false,              false,                  false,      true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           false,              true,                   false,      true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    false,          true,               false,                  false,      true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    false,          true,               true,                   false,      true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           true,               false,                  false,      true,       -1},
+    {"tag-expensive_constrained-test.ttl-86400.d.test.",    true,           true,               true,                   false,      true,       -1}
+};
+
+static void ExpensiveConstrainedSetupLocalDNSServer( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedStartTestHandler( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedStopTestHandler( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedSetupTimer( ExpensiveConstrainedContext *context, uint32_t second );
+static void ExpensiveConstrainedTestTimerEventHandler( ExpensiveConstrainedContext *context );
+static void DNSSD_API
+    ExpensiveConstrainedCallback(
+        DNSServiceRef           inSDRef,
+        DNSServiceFlags         inFlags,
+        uint32_t                inInterfaceIndex,
+        DNSServiceErrorType     inError,
+        const char *            inHostname,
+        const struct sockaddr * inSockAddr,
+        uint32_t                inTTL,
+        void *                  inContext );
+static void ExpensiveConstrainedInitializeContext( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedStopAndCleanTheTest( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedSubtestProgressReport( ExpensiveConstrainedContext *context );
+static void ExpensiveConstrainedSubtestReport( ExpensiveConstrainedContext *context, const char *error_description );
+static void ExpensiveConstrainedFinalResultReport( ExpensiveConstrainedContext *context, Boolean allPassed );
+static const char *ExpensiveConstrainedProtocolString(DNSServiceProtocol protocol);
+static const char *ExpensiveConstrainedStateString(enum ExpensiveConstrainedTestState state);
+static const char *ExpensiveConstrainedOperationString(enum ExpensiveConstrainedTestOperation operation);
+static Boolean expensiveConstrainedEndsWith( const char *str, const char *suffix );
+
+//===========================================================================================================================
+//    ExpensiveConstrainedTestCmd
+//===========================================================================================================================
+static void ExpensiveConstrainedTestCmd( void )
+{
+    OSStatus                        err;
+    dispatch_source_t               signalSource   = NULL;
+    ExpensiveConstrainedContext *   context        = NULL;
+
+    // Set up SIGINT handler.
+    signal( SIGINT, SIG_IGN );
+    err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+    require_noerr( err, exit );
+    dispatch_resume( signalSource );
+
+    // create the test context
+    context = (ExpensiveConstrainedContext *) calloc( 1, sizeof(*context) );
+    require_action( context, exit, err = kNoMemoryErr );
+
+    // get the command line option
+    err = OutputFormatFromArgString( gExpensiveConstrainedTest_OutputFormat, &context->outputFormat );
+    require_noerr_quiet( err, exit );
+    if ( gExpensiveConstrainedTest_OutputFilePath )
+    {
+        context->outputFilePath = strdup( gExpensiveConstrainedTest_OutputFilePath );
+        require_noerr_quiet( context->outputFilePath, exit );
+    }
+
+    // initialize context
+    context->subtestIndex = 0;
+    context->numOfRetries = EXPENSIVE_CONSTRAINED_MAX_RETRIES;
+
+    // initialize the CFArray used to store the log
+    context->subtestReport = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+    context->testReport_startTime = NanoTimeGetCurrent();
+
+    // setup local DNS server
+    ExpensiveConstrainedSetupLocalDNSServer( context );
+
+    ExpensiveConstrainedStartTestHandler( context );
+
+    dispatch_main();
+
+exit:
+    exit( 1 );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedSetupLocalDNSServer
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSetupLocalDNSServer( ExpensiveConstrainedContext *context )
+{
+    pid_t current_pid = getpid();
+    OSStatus err = SpawnCommand( &context->serverPID, "dnssdutil server -l --follow %d", current_pid );
+    if (err != 0)
+    {
+        FPrintF( stdout, "dnssdutil server -l --follow <PID> failed, error: %d\n", err );
+        exit( 1 );
+    }
+    sleep(2);
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedStartTestHandler
+//===========================================================================================================================
+
+static void ExpensiveConstrainedStartTestHandler( ExpensiveConstrainedContext *context )
+{
+    // setup 3s timer
+    ExpensiveConstrainedSetupTimer( context, EXPENSIVE_CONSTRAINED_TEST_INTERVAL );
+
+    // set the event handler for the 3s timer
+    dispatch_source_set_event_handler( context->timer, ^{
+        ExpensiveConstrainedTestTimerEventHandler( context );
+    } );
+
+    dispatch_resume( context->timer );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedStartTestHandler
+//===========================================================================================================================
+
+static void ExpensiveConstrainedStopTestHandler( ExpensiveConstrainedContext *context )
+{
+    dispatch_cancel( context->timer );
+    dispatch_release( context->timer );
+    context->timer = NULL;
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedSetupTimer
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSetupTimer( ExpensiveConstrainedContext *context, uint32_t second )
+{
+    // set the timer source, the event handler will be called for every "second" seconds
+    context->timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue() );
+    if ( context->timer == NULL )
+    {
+        FPrintF( stdout, "dispatch_source_create:DISPATCH_SOURCE_TYPE_TIMER failed\n" );
+        exit( 1 );
+    }
+    // the first block will be put into the queue "second"s after calling dispatch_resume
+    dispatch_source_set_timer( context->timer, dispatch_time( DISPATCH_TIME_NOW, second * NSEC_PER_SEC ),
+                               (unsigned long long)(second) * NSEC_PER_SEC, 100ull * NSEC_PER_MSEC );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedTestTimerEventHandler
+//===========================================================================================================================
+
+static void ExpensiveConstrainedTestTimerEventHandler( ExpensiveConstrainedContext *context )
+{
+    OSStatus    err;
+    char        buffer[ 1024 ];
+    const char *errorDescription = NULL;
+
+    // do not log the state if we are in transition state
+    if (context->state != TEST_BEGIN
+        && context->state != TEST_SUCCEEDED
+        && context->state != TEST_CONSTRAINED_PREPARE
+        && context->state != TEST_EXPENSIVE_CONSTRAINED_PREPARE)
+        ExpensiveConstrainedSubtestProgressReport( context );
+
+    switch ( context->state ) {
+        case TEST_BEGIN:
+        {
+            ExpensiveConstrainedStopTestHandler( context );
+
+            // clear mDNSResponder cache
+            err = systemf( NULL, "killall -HUP mDNSResponder" );
+            require_noerr_action( err, test_failed, errorDescription = "systemf failed");
+
+            // initialize the global parameters
+            ExpensiveConstrainedInitializeContext( context );
+
+            // The local DNS server is set up on the local only interface.
+            gExpensiveConstrainedTest_Interface = LOOPBACK_INTERFACE_NAME;
+            strncpy( context->ifName, gExpensiveConstrainedTest_Interface, sizeof( context->ifName ) );
+
+            // The local DNS server is unscoped, so we must set our question to unscoped.
+            context->ifIndex = kDNSServiceInterfaceIndexAny;
+
+            // The question name must end with "d.test.", "tag-expensive-test.ttl-86400.d.test." for example, then the test will
+            // use the local dns server set up previously to run the test locally.
+            require_action( gExpensiveConstrainedTest_Name != NULL && expensiveConstrainedEndsWith( gExpensiveConstrainedTest_Name, "d.test." ), test_failed,
+                           SNPrintF( buffer, sizeof( buffer ), "The question name (%s) must end with \"d.test.\".\n", gExpensiveConstrainedTest_Name );
+                           errorDescription = buffer );
+
+            // get the quesion name
+            context->name = gExpensiveConstrainedTest_Name;
+
+            // set the initial state for the interface
+            context->startFromExpensive = gExpensiveConstrainedTest_StartFromExpensive;
+            err = systemf( NULL, "ifconfig %s %sexpensive && ifconfig %s -constrained", context->ifName, context->startFromExpensive ? "" : "-", context->ifName );
+            require_noerr_action( err, test_failed, errorDescription = "systemf failed");
+            sleep( 5 ); // wait for 5s to allow the interface change event de delivered to others
+
+            // get question flag
+            if ( gExpensiveConstrainedTest_DenyExpensive )    context->flags     |= kDNSServiceFlagsDenyExpensive;
+            if ( gExpensiveConstrainedTest_DenyConstrained )  context->flags     |= kDNSServiceFlagsDenyConstrained;
+            if ( gExpensiveConstrainedTest_ProtocolIPv4 )     context->protocols |= kDNSServiceProtocol_IPv4;
+            if ( gExpensiveConstrainedTest_ProtocolIPv6 )     context->protocols |= kDNSServiceProtocol_IPv6;
+
+            // prevent mDNSResponder from doing extra path evaluation and changing the interface to others(such as Bluetooth)
+            #if( TARGET_OS_WATCH )
+            context->flags |= kDNSServiceFlagsPathEvaluationDone;
+            #endif
+
+            // start the query
+            DNSServiceGetAddrInfo( &context->opRef, context->flags, context->ifIndex, context->protocols, context->name, ExpensiveConstrainedCallback, context );
+
+            // set the initial test status
+            context->subtestReport_startTime    = NanoTimeGetCurrent();
+            context->subtestProgress_startTime  = NanoTimeGetCurrent();
+            context->state                      = TEST_EXPENSIVE_PREPARE; // start from expensive test
+            context->isExpensiveNow             = context->startFromExpensive ? true : false;
+            context->isConstrainedNow           = false;
+            context->expectedOperation          = context->isExpensiveNow && ( context->flags & kDNSServiceFlagsDenyExpensive ) ? NO_UPDATE : RESULT_ADD;
+            context->operation                  = NO_UPDATE;
+            context->subtestProgress            = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks);
+            require_action( context->subtestProgress != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+            context->subtestProgress_callBack   = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks);
+            require_action( context->subtestProgress != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+            // set the queue where the callback will be called when there is an answer for the query
+            err = DNSServiceSetDispatchQueue( context->opRef, dispatch_get_main_queue() );
+            require_noerr( err, test_failed );
+
+            ExpensiveConstrainedStartTestHandler( context );
+        }
+            break;
+        case TEST_EXPENSIVE_PREPARE:
+            require_action( context->isConstrainedNow == false, test_failed,
+                            SNPrintF( buffer, sizeof( buffer ), "Interface %s should be unconstrained.\n", context->ifName );
+                            errorDescription = buffer );
+            require_action( context->expectedOperation == context->operation, test_failed,
+                            errorDescription = "Operation is not expected" );
+
+            context->subtestProgress_startTime  = NanoTimeGetCurrent();
+            context->state                      = TEST_EXPENSIVE;   // begin to test expensive flag
+            context->counter                    = 0;                // the number of test repetition that has passed
+            context->isExpensivePrev            = context->isExpensiveNow;
+            context->isExpensiveNow             = !context->isExpensiveNow; // flip the expensive status
+            context->isConstrainedPrev          = false;            // the interface is currently unconstrained
+            context->isConstrainedNow           = false;            // the interface will be unconstrained in the current test
+            if ( gExpensiveConstrainedTest_DenyExpensive )
+                context->expectedOperation      = context->isExpensiveNow ? RESULT_RMV : RESULT_ADD;
+            else
+                context->expectedOperation      = NO_UPDATE;
+            context->operation                  = NO_UPDATE;        // NO_UPDATE means the call back function has not been called
+            context->subtestProgress_callBack   = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+            require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+            err = systemf( NULL, "ifconfig %s %sexpensive", context->ifName, context->isExpensiveNow ? "" : "-" );
+            require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+            // record the starting timestamp
+            gettimeofday( &context->updateTime, NULL );
+
+            break;
+        case TEST_EXPENSIVE:
+            // Since we are testing expensive flag, we should always turn the expensive flag on and off.
+            require_action( context->isExpensivePrev ^ context->isExpensiveNow, test_failed,
+                            SNPrintF( buffer, sizeof( buffer ), "The current expensive status should be different with the previous one: %d -> %d\n", context->isExpensivePrev, context->isExpensiveNow);
+                            errorDescription = buffer );
+            // constrained flag is always turned off when testing expensive
+            require_action( context->isConstrainedNow == false, test_failed,
+                            SNPrintF( buffer, sizeof( buffer ), "The interface %s should be unconstrained when testing \"expensive\"\n", context->ifName );
+                            errorDescription = buffer );
+            require_action( context->expectedOperation == context->operation, test_failed, errorDescription = "Operation is not expected" );
+
+            context->counter++; // one test repetition has passed
+            if ( context->counter == TEST_REPETITION ) // expensive test finished
+            {
+                // prepare to test constrained flag
+                context->state = TEST_CONSTRAINED_PREPARE;
+
+                // reset the interface
+                err = systemf( NULL, "ifconfig %s -expensive && ifconfig %s -constrained", context->ifName, context->ifName );
+                require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+                context->isExpensiveNow = false;
+                context->isConstrainedNow = false;
+                gettimeofday( &context->updateTime, NULL );
+            }
+            else
+            {
+                context->subtestProgress_startTime  = NanoTimeGetCurrent();
+                context->isExpensivePrev            = context->isExpensiveNow;
+                context->isExpensiveNow             = !context->isExpensiveNow; // flip the expensive status
+                if ( gExpensiveConstrainedTest_DenyExpensive )
+                    context->expectedOperation      = context->isExpensiveNow ? RESULT_RMV : RESULT_ADD;
+                else
+                    context->expectedOperation      = NO_UPDATE;
+                context->operation                  = NO_UPDATE;
+                context->subtestProgress_callBack   = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+                require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+                err = systemf( NULL, "ifconfig %s %sexpensive", context->ifName, context->isExpensiveNow ? "" : "-" );
+                require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+                gettimeofday( &context->updateTime, NULL );
+            }
+            break;
+        case TEST_CONSTRAINED_PREPARE:
+            // The interface should be inexpensive and unconstrained when the constrained test starts
+            require_action( context->isExpensiveNow == false, test_failed, SNPrintF( buffer, sizeof( buffer ), "Interface %s should be inexpensive.", context->ifName );
+                            errorDescription = buffer );
+            require_action( context->isConstrainedNow == false, test_failed, SNPrintF( buffer, sizeof( buffer ), "Interface %s should be unconstrained.\n", context->ifName );
+                            errorDescription = buffer );
+
+            context->subtestProgress_startTime  = NanoTimeGetCurrent();
+            context->state                      = TEST_CONSTRAINED; // constrained interface is now under testing
+            context->counter                    = 0;
+            context->isExpensivePrev            = false;
+            context->isExpensiveNow             = false;
+            context->isConstrainedPrev          = false;
+            context->isConstrainedNow           = true;             // will set constrained flag on the interface
+            if ( gExpensiveConstrainedTest_DenyConstrained )
+                context->expectedOperation      = RESULT_RMV;
+            else
+                context->expectedOperation      = NO_UPDATE;
+            context->operation                  = NO_UPDATE;
+            context->subtestProgress_callBack   = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+            require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+            // change interface to the constrained one
+            err = systemf( NULL, "ifconfig %s -expensive && ifconfig %s constrained", context->ifName, context->ifName );
+            require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+            gettimeofday( &context->updateTime, NULL );
+            break;
+        case TEST_CONSTRAINED:
+            // Since we are testing constrained flag, we should always turn the constrained flag on and off.
+            require_action( context->isConstrainedPrev ^ context->isConstrainedNow, test_failed,
+                            SNPrintF( buffer, sizeof( buffer ), "The current constrained status should be different with the previous one: %d -> %d\n", context->isConstrainedPrev, context->isConstrainedNow );
+                            errorDescription = buffer );
+            require_action( context->isExpensiveNow == false, test_failed,
+                            SNPrintF( buffer, sizeof( buffer ), "The interface %s should be inexpensive when testing \"constrained\"\n", context->ifName );
+                            errorDescription = buffer );
+            require_action( context->expectedOperation == context->operation, test_failed, errorDescription = "Operation is not expected");
+
+            context->counter++;
+            if (context->counter == TEST_REPETITION)
+            {
+                // test changing expensive and constrained flags at the same time
+                context->state = TEST_EXPENSIVE_CONSTRAINED_PREPARE;
+
+                // reset interface
+                err = systemf( NULL, "ifconfig %s -expensive && ifconfig %s -constrained", context->ifName, context->ifName );
+                require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+                context->isExpensiveNow = false;
+                context->isConstrainedNow = false;
+                gettimeofday( &context->updateTime, NULL );
+            }
+            else
+            {
+                context->subtestProgress_startTime  = NanoTimeGetCurrent();
+                context->isConstrainedPrev          = context->isConstrainedNow;
+                context->isConstrainedNow           = !context->isConstrainedNow; // flip constrained flag
+                if ( gExpensiveConstrainedTest_DenyConstrained )
+                    context->expectedOperation      = context->isConstrainedNow ? RESULT_RMV : RESULT_ADD;
+                else
+                    context->expectedOperation      = NO_UPDATE;
+                context->operation                  = NO_UPDATE;
+                context->subtestProgress_callBack   = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+                require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+                err = systemf( NULL, "ifconfig %s %sconstrained", context->ifName, context->isConstrainedNow ? "" : "-" );
+                require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+                gettimeofday(&context->updateTime, NULL);
+            }
+            break;
+        case TEST_EXPENSIVE_CONSTRAINED_PREPARE:
+            // The interface should be inexpensive and unconstrained when the constrained test starts
+            require_action( context->isExpensiveNow == false,   test_failed,
+                            SNPrintF( buffer, sizeof( buffer ), "Interface %s should be inexpensive.\n", context->ifName );
+                            errorDescription = buffer );
+            require_action( context->isConstrainedNow == false, test_failed,
+                            SNPrintF(buffer, sizeof( buffer ), "Interface %s should be unconstrained.\n", context->ifName );
+                            errorDescription = buffer );
+
+            // now flip expensive and constrained at the same time
+            context->subtestProgress_startTime  = NanoTimeGetCurrent();
+            context->state                      = TEST_EXPENSIVE_CONSTRAINED;
+            context->counter                    = 0;
+            context->isExpensivePrev            = false;
+            context->isExpensiveNow             = true;
+            context->isConstrainedPrev          = false;
+            context->isConstrainedNow           = true;
+            if (gExpensiveConstrainedTest_DenyConstrained || gExpensiveConstrainedTest_DenyExpensive)
+                context->expectedOperation      = RESULT_RMV;
+            else
+                context->expectedOperation      = NO_UPDATE;
+            context->operation                  = NO_UPDATE;
+            context->subtestProgress_callBack   = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+            require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+            err = systemf(NULL, "ifconfig %s expensive && ifconfig %s constrained", context->ifName, context->ifName );
+            require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+            gettimeofday( &context->updateTime, NULL );
+            break;
+        case TEST_EXPENSIVE_CONSTRAINED:
+            // expensive and constrained flag should always be changed
+            require_action( ( context->isExpensivePrev ^ context->isExpensiveNow ) && ( context->isConstrainedPrev ^ context->isConstrainedNow ), test_failed,
+                            SNPrintF( buffer, sizeof( buffer ), "Both expensive and constrained status need to be changed" );
+                            errorDescription = buffer );
+            require_action( context->isExpensiveNow == context->isConstrainedNow, test_failed, errorDescription = "context->isExpensiveNow != context->isConstrainedNow" );
+            require_action( context->expectedOperation == context->operation, test_failed, errorDescription = "Operation is not expected" );
+
+            context->counter++;
+            if ( context->counter == TEST_REPETITION )
+            {
+                context->state = TEST_SUCCEEDED;
+            }
+            else
+            {
+                context->subtestProgress_startTime  = NanoTimeGetCurrent();
+                context->isExpensivePrev            = context->isExpensiveNow;
+                context->isExpensiveNow             = !context->isExpensiveNow;
+                context->isConstrainedPrev          = context->isConstrainedNow;
+                context->isConstrainedNow           = !context->isConstrainedNow;
+                if (gExpensiveConstrainedTest_DenyConstrained || gExpensiveConstrainedTest_DenyExpensive)
+                    context->expectedOperation      = context->isExpensiveNow ? RESULT_RMV : RESULT_ADD;
+                else
+                    context->expectedOperation      = NO_UPDATE;
+                context->operation                  = NO_UPDATE;
+                context->subtestProgress_callBack   = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+                require_action( context->subtestProgress_callBack != NULL, test_failed, errorDescription = "CFArrayCreateMutable failed" );
+
+                err = systemf( NULL, "ifconfig %s %sexpensive && ifconfig %s %sconstrained", context->ifName, context->isExpensiveNow ? "" : "-", context->ifName, context->isConstrainedNow ? "" : "-" );
+                require_noerr_action( err, test_failed, errorDescription = "systemf failed" );
+
+                gettimeofday( &context->updateTime, NULL );
+            }
+            break;
+        case TEST_FAILED:
+        test_failed:
+            ExpensiveConstrainedSubtestReport( context, errorDescription );
+            ExpensiveConstrainedStopAndCleanTheTest( context );
+            if ( context->numOfRetries > 0 )
+            {
+                context->state = TEST_BEGIN;
+                context->numOfRetries--;
+                break;
+            }
+            ExpensiveConstrainedSubtestParams[context->subtestIndex++].test_passed = 0;
+            if (context->subtestIndex == (int) countof( ExpensiveConstrainedSubtestParams ))
+            {
+                ExpensiveConstrainedFinalResultReport( context, false );
+                exit( 2 );
+            }
+            if (context->timer == NULL)
+            {
+                // If timer is NULL, it means that we encounter error before we set up the test handler, which is unrecoverable.
+                ExpensiveConstrainedFinalResultReport( context, false );
+                exit( 1 );
+            }
+            context->state = TEST_BEGIN;
+            break;
+        case TEST_SUCCEEDED:
+            ExpensiveConstrainedSubtestReport( context, NULL );
+            ExpensiveConstrainedStopAndCleanTheTest( context );
+            ExpensiveConstrainedSubtestParams[context->subtestIndex++].test_passed = 1;
+            if (context->subtestIndex == (int) countof( ExpensiveConstrainedSubtestParams ))
+            {
+                // all the subtests have been run
+                Boolean hasFailed = false;
+                for ( int i = 0; i < (int) countof( ExpensiveConstrainedSubtestParams ) && !hasFailed; i++ )
+                    hasFailed = ( ExpensiveConstrainedSubtestParams[i].test_passed != 1 );
+
+                ExpensiveConstrainedFinalResultReport( context, !hasFailed );
+                exit( hasFailed ? 2 : 0 );
+            }
+            context->state = TEST_BEGIN;
+            break;
+        default:
+            FPrintF( stdout, "unknown error\n" );
+            exit( 1 );
+    }
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+    ExpensiveConstrainedCallback(
+        __unused DNSServiceRef  inSDRef,
+        DNSServiceFlags         inFlags,
+        uint32_t                inInterfaceIndex,
+        DNSServiceErrorType     inError,
+        const char *            inHostname,
+        const struct sockaddr * inSockAddr,
+        __unused uint32_t       inTTL,
+        void *                  inContext )
+{
+    ExpensiveConstrainedContext * const   context = (ExpensiveConstrainedContext *)inContext;
+    OSStatus                                    err;
+    const char *                                addrStr;
+    char                                        addrStrBuf[ kSockAddrStringMaxSize ];
+    char                                        inFlagsDescription[ 128 ];
+    NanoTime64                                  now;
+    char                                        nowTimestamp[ 32 ];
+
+    switch ( inError ) {
+        case kDNSServiceErr_NoError:
+        case kDNSServiceErr_NoSuchRecord:
+            break;
+
+        case kDNSServiceErr_Timeout:
+            Exit( kExitReason_Timeout );
+
+        default:
+            err = inError;
+            goto exit;
+    }
+
+    if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+    {
+        dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+        err = kTypeErr;
+        goto exit;
+    }
+
+    if( !inError )
+    {
+        err = SockAddrToString( inSockAddr, kSockAddrStringFlagsNone, addrStrBuf );
+        require_noerr( err, exit );
+        addrStr = addrStrBuf;
+    }
+    else
+    {
+        addrStr = ( inSockAddr->sa_family == AF_INET ) ? kNoSuchRecordAStr : kNoSuchRecordAAAAStr;
+    }
+
+    now = NanoTimeGetCurrent();
+    _NanoTime64ToTimestamp( now, nowTimestamp, sizeof( nowTimestamp ) );
+    SNPrintF( inFlagsDescription, sizeof( inFlagsDescription ), "%{du:cbflags}", inFlags );
+    err = CFPropertyListAppendFormatted( kCFAllocatorDefault,  context->subtestProgress_callBack,
+        "{"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%lli"
+            "%kO=%s"
+        "}",
+        EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_TIMESTAMP,  nowTimestamp,
+        EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_NAME,       inHostname,
+        EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_FLAGS,      inFlagsDescription,
+        EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_INTERFACE,  (int64_t) inInterfaceIndex,
+        EXPENSIVE_CONSTRAINED_SUBTEST_ACTUAL_RESULT_KEY_ADDRESS,    addrStr
+    );
+    require_noerr_quiet( err, exit );
+
+    if ( inFlags & kDNSServiceFlagsMoreComing )
+        return;
+
+    if ( inFlags & kDNSServiceFlagsAdd )
+        context->operation = RESULT_ADD;
+    else
+        context->operation = RESULT_RMV;
+
+    gettimeofday(&context->notificationTime, NULL);
+exit:
+    if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedInitializeContext
+//===========================================================================================================================
+
+static void ExpensiveConstrainedInitializeContext( ExpensiveConstrainedContext *context )
+{
+    // clear the flags of the previous subtest
+    context->flags      = 0;
+    context->protocols  = 0;
+
+    // get the parameter for the current subtest
+    const ExpensiveConstrainedTestParams *param     = &ExpensiveConstrainedSubtestParams[context->subtestIndex];
+    gExpensiveConstrainedTest_Name                  = param->qname;
+    gExpensiveConstrainedTest_DenyExpensive         = param->deny_expensive;
+    gExpensiveConstrainedTest_DenyConstrained       = param->deny_constrained;
+    gExpensiveConstrainedTest_StartFromExpensive    = param->start_from_expensive;
+    gExpensiveConstrainedTest_ProtocolIPv4          = param->ipv4_query;
+    gExpensiveConstrainedTest_ProtocolIPv6          = param->ipv6_query;
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedStopAndCleanTheTest
+//===========================================================================================================================
+
+static void ExpensiveConstrainedStopAndCleanTheTest( ExpensiveConstrainedContext *context )
+{
+    // Stop the ongoing query
+    if ( context->opRef != NULL )
+        DNSServiceRefDeallocate( context->opRef );
+
+    context->opRef      = NULL;
+    context->flags      = 0;
+    context->protocols  = 0;
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedSubtestProgressReport
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSubtestProgressReport( ExpensiveConstrainedContext *context )
+{
+    OSStatus            err;
+    NanoTime64          now;
+    char                startTime[ 32 ];
+    char                endTime[ 32 ];
+    char                expensive[ 32 ];
+    char                constrained[ 32 ];
+
+    now = NanoTimeGetCurrent();
+    _NanoTime64ToTimestamp( context->subtestProgress_startTime, startTime, sizeof( startTime ) );
+    _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+
+    snprintf( expensive, sizeof( expensive ), "%s -> %s", context->isExpensivePrev ? "True" : "False", context->isExpensiveNow ? "True" : "False" );
+    snprintf( constrained, sizeof( constrained ), "%s -> %s", context->isConstrainedPrev ? "True" : "False", context->isConstrainedNow ? "True" : "False" );
+
+    err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->subtestProgress,
+        "{"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%O"
+        "}",
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_START_TIME,              startTime,
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_END_TIME,                endTime,
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_STATE,                   ExpensiveConstrainedStateString(context->state),
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPECT_RESULT,           ExpensiveConstrainedOperationString(context->expectedOperation),
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_ACTUAL_RESULT,           ExpensiveConstrainedOperationString(context->operation),
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_EXPENSIVE_PREV_NOW,      expensive,
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CONSTRAINED_PREV_NOW,    constrained,
+        EXPENSIVE_CONSTRAINED_SUBTEST_PROGRESS_KEY_CALL_BACK,               context->subtestProgress_callBack
+    );
+    require_noerr( err, exit );
+    ForgetCF( &context->subtestProgress_callBack );
+    return;
+
+exit:
+    ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedFinalSubtestReport
+//===========================================================================================================================
+
+static void ExpensiveConstrainedSubtestReport( ExpensiveConstrainedContext *context, const char *error_description )
+{
+    OSStatus            err;
+    NanoTime64          now;
+    char                startTime[ 32 ];
+    char                endTime[ 32 ];
+    char                flagDescription[ 1024 ];
+
+    now = NanoTimeGetCurrent();
+    _NanoTime64ToTimestamp( context->subtestReport_startTime, startTime, sizeof( startTime ) );
+    _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+    SNPrintF( flagDescription, sizeof( flagDescription ), "%#{flags}", context->flags, kDNSServiceFlagsDescriptors );
+
+    if (error_description != NULL)
+    {
+        err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->subtestReport,
+            "{"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%lli"
+                "%kO=%s"
+                "%kO=%O"
+                "%kO=%s"
+                "%kO=%O"
+            "}",
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_START_TIME,        startTime,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_END_TIME,          endTime,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_QNAME,             context->name,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_FLAGS,             flagDescription,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_PROTOCOLS,         ExpensiveConstrainedProtocolString( context->protocols ),
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_INDEX,   (int64_t) context->ifIndex,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_NAME,    context->ifName,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_RESULT,            CFSTR( "Fail" ),
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_ERROR,             error_description,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_TEST_PROGRESS,     context->subtestProgress
+        );
+    }
+    else
+    {
+        err = CFPropertyListAppendFormatted( kCFAllocatorDefault, context->subtestReport,
+            "{"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%s"
+                "%kO=%lli"
+                "%kO=%s"
+                "%kO=%O"
+                "%kO=%O"
+            "}",
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_START_TIME,        startTime,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_END_TIME,          endTime,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_QNAME,             context->name,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_FLAGS,             flagDescription,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_PROTOCOLS,         ExpensiveConstrainedProtocolString( context->protocols ),
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_INDEX,   (int64_t) context->ifIndex,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_INTERFACE_NAME,    context->ifName,
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_RESULT,            CFSTR( "Pass" ),
+            EXPENSIVE_CONSTRAINED_SUBTEST_REPORT_KEY_TEST_PROGRESS,     context->subtestProgress
+        );
+    }
+
+    require_noerr( err, exit );
+    ForgetCF( &context->subtestProgress );
+    return;
+exit:
+    ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedFinalResultReport
+//===========================================================================================================================
+
+static void ExpensiveConstrainedFinalResultReport( ExpensiveConstrainedContext *context, Boolean allPassed )
+{
+    OSStatus            err;
+    CFPropertyListRef   plist;
+    NanoTime64          now;
+    char                startTime[ 32 ];
+    char                endTime[ 32 ];
+
+    now = NanoTimeGetCurrent();
+    _NanoTime64ToTimestamp( context->testReport_startTime, startTime, sizeof( startTime ) );
+    _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+
+    err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+        "{"
+            "%kO=%s"
+            "%kO=%s"
+            "%kO=%b"
+            "%kO=%O"
+        "}",
+        EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_START_TIME,       startTime,
+        EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_END_TIME,         endTime,
+        EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_ALL_PASSED,       allPassed,
+        EXPENSIVE_CONSTRAINED_TEST_REPORT_KEY_SUBTEST_RESULT,   context->subtestReport
+    );
+    require_noerr( err, exit );
+    ForgetCF( &context->subtestReport );
+
+    err = OutputPropertyList( plist, context->outputFormat, context->outputFilePath );
+    CFRelease( plist );
+    require_noerr( err, exit );
+
+    return;
+exit:
+    ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedProtocolString
+//===========================================================================================================================
+
+static const char *ExpensiveConstrainedProtocolString( DNSServiceProtocol protocol )
+{
+    const char *str = NULL;
+    switch ( protocol ) {
+        case kDNSServiceProtocol_IPv4:
+            str = "IPv4";
+            break;
+        case kDNSServiceProtocol_IPv6:
+            str = "IPv6";
+            break;
+        case kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6:
+            str = "IPv4 & IPv6";
+            break;
+        default:
+            break;
+    }
+    return str;
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedStateString
+//===========================================================================================================================
+
+static const char *ExpensiveConstrainedStateString( enum ExpensiveConstrainedTestState state )
+{
+    const char *str = NULL;
+    switch ( state ) {
+        case TEST_BEGIN:
+            str = "TEST_BEGIN";
+            break;
+        case TEST_EXPENSIVE_PREPARE:
+            str = "TEST_EXPENSIVE_PREPARE";
+            break;
+        case TEST_EXPENSIVE:
+            str = "TEST_EXPENSIVE";
+            break;
+        case TEST_CONSTRAINED_PREPARE:
+            str = "TEST_CONSTRAINED_PREPARE";
+            break;
+        case TEST_CONSTRAINED:
+            str = "TEST_CONSTRAINED";
+            break;
+        case TEST_EXPENSIVE_CONSTRAINED_PREPARE:
+            str = "TEST_EXPENSIVE_CONSTRAINED_PREPARE";
+            break;
+        case TEST_EXPENSIVE_CONSTRAINED:
+            str = "TEST_EXPENSIVE_CONSTRAINED";
+            break;
+        case TEST_FAILED:
+            str = "TEST_FAILED";
+            break;
+        case TEST_SUCCEEDED:
+            str = "TEST_SUCCEEDED";
+            break;
+        default:
+            str = "UNKNOWN";
+            break;
+    }
+
+    return str;
+}
+
+//===========================================================================================================================
+//    ExpensiveConstrainedOperationString
+//===========================================================================================================================
+
+static const char *ExpensiveConstrainedOperationString( enum ExpensiveConstrainedTestOperation operation )
+{
+    const char *str = NULL;
+    switch ( operation ) {
+        case RESULT_ADD:
+            str = "RESULT_ADD";
+            break;
+        case RESULT_RMV:
+            str = "RESULT_RMV";
+            break;
+        case NO_UPDATE:
+            str = "NO_UPDATE";
+            break;
+        default:
+            str = "UNKNOWN";
+            break;
+    }
+    return str;
+}
+
+//===========================================================================================================================
+//    expensiveConstrainedEndsWith
+//===========================================================================================================================
+static Boolean expensiveConstrainedEndsWith( const char *str, const char *suffix )
+{
+    if ( !str || !suffix )
+        return false;
+    size_t lenstr = strlen( str );
+    size_t lensuffix = strlen( suffix );
+    if ( lensuffix > lenstr )
+        return false;
+    return strncmp( str + lenstr - lensuffix, suffix, lensuffix ) == 0;
+}
+
+//===========================================================================================================================
+//    RegistrationTestCmd
+//===========================================================================================================================
+
+typedef struct RegistrationSubtest             RegistrationSubtest;
+
+typedef struct
+{
+       CFMutableArrayRef                       subtestReports;                         // Array of subtest reports.
+       dispatch_source_t                       timer;                                          // Timer to enforce subtest durations.
+       dispatch_source_t                       sigSourceINT;                           // SIGINT signal handler for a clean test exit.
+       dispatch_source_t                       sigSourceTERM;                          // SIGTERM signal handler for a clean test exit.
+       RegistrationSubtest *           subtest;                                        // Current subtest.
+       char *                                          outputFilePath;                         // Path of test result output file. If NULL, stdout will be used.
+       OutputFormatType                        outputFormat;                           // Format of test results output.
+       CFStringRef                                     computerNamePrev;                       // Previous ComputerName.
+       CFStringRef                                     localHostNamePrev;                      // Previous LocalHostName.
+       NanoTime64                                      startTime;                                      // Test's start time.
+       char *                                          computerName;                           // Temporary ComputerName to set during testing. (malloc'd)
+       char *                                          localHostName;                          // Temporary LocalHostName to set during testing. (malloc'd)
+       CFStringEncoding                        computerNamePrevEncoding;       // Previous ComputerName's encoding.
+       int                                                     subtestIndex;                           // Index of current subtest.
+       Boolean                                         computerNameSet;                        // True if a temporary ComputerName was set.
+       Boolean                                         localHostNameSet;                       // True if a temporary LocalHostName was set.
+       Boolean                                         failed;                                         // True if at least one non-skipped subtest failed.
+       Boolean                                         forBATS;                                        // True if the test is running in a BATS environment.
+       
+}      RegistrationTest;
+
+typedef enum
+{
+       kRegistrationInterfaceSet_Null                  = 0,
+       kRegistrationInterfaceSet_All                   = 1,
+       kRegistrationInterfaceSet_AllPlusAWDL   = 2,
+       kRegistrationInterfaceSet_LoopbackOnly  = 3,
+       kRegistrationInterfaceSet_AWDLOnly              = 4
+       
+}      RegistrationInterfaceSet;
+
+typedef struct
+{
+       RegistrationInterfaceSet                interfaceSet;   // Interfaces to register the service over.
+       Boolean                                                 useDefaultName; // True if registration is to use the default service name.
+       Boolean                                                 useLODiscovery; // True if discovery is to use kDNSServiceInterfaceIndexLocalOnly.
+       
+}      RegistrationSubtestParams;
+
+static const RegistrationSubtestParams         kRegistrationSubtestParams[] =
+{
+       { kRegistrationInterfaceSet_All,                        true,   false },
+       { kRegistrationInterfaceSet_All,                        false,  false },
+       { kRegistrationInterfaceSet_AllPlusAWDL,        true,   false },
+       { kRegistrationInterfaceSet_AllPlusAWDL,        false,  false },
+       { kRegistrationInterfaceSet_LoopbackOnly,       true,   false },
+       { kRegistrationInterfaceSet_LoopbackOnly,       false,  false },
+       { kRegistrationInterfaceSet_AWDLOnly,           true,   false },
+       { kRegistrationInterfaceSet_AWDLOnly,           false,  false },
+       { kRegistrationInterfaceSet_All,                        true,   true  },
+       { kRegistrationInterfaceSet_All,                        false,  true  },
+       { kRegistrationInterfaceSet_AllPlusAWDL,        true,   true  },
+       { kRegistrationInterfaceSet_AllPlusAWDL,        false,  true  },
+       { kRegistrationInterfaceSet_LoopbackOnly,       true,   true  },
+       { kRegistrationInterfaceSet_LoopbackOnly,       false,  true  },
+       { kRegistrationInterfaceSet_AWDLOnly,           true,   true  },
+       { kRegistrationInterfaceSet_AWDLOnly,           false,  true  }
+};
+
+typedef struct
+{
+       NanoTime64              browseResultTime;       // Per-interface browse result time.
+       NanoTime64              querySRVResultTime;     // Per-interface SRV record query result time.
+       NanoTime64              queryTXTResultTime;     // Per-interface TXT record query result time.
+       
+}      RegistrationResultTimes;
+
+typedef struct
+{
+       MDNSInterfaceItem                       base;   // Underlying MDNSInterface linked-list item.
+       RegistrationResultTimes         times;  // Per-interface result times.
+       
+}      RegistrationInterfaceItem;
+
+struct RegistrationSubtest
+{
+       DNSServiceRef                                   registration;           // DNS-SD service registration.
+       DNSServiceRef                                   connection;                     // Shared DNS-SD connection.
+       DNSServiceRef                                   browse;                         // DNS-SD browse for service's type.
+       DNSServiceRef                                   querySRV;                       // DNS-SD query request for service's SRV record.
+       DNSServiceRef                                   queryTXT;                       // DNS-SD query request for service's TXT record.
+       CFMutableArrayRef                               unexpected;                     // Array of unexpected registration, browse, and query results.
+#if( TARGET_OS_WATCH )
+       CFMutableArrayRef                               ignored;                        // Array of unexpected, but ignored, browse and query results.
+#endif
+       const char *                                    serviceName;            // Service's name.
+       char *                                                  serviceNameCustom;      // Service's name if using a custom name. (malloc'd)
+       char *                                                  serviceType;            // Service's service type. (malloc'd)
+       size_t                                                  serviceTypeLen;         // C string length of service's service type.
+       char *                                                  serviceFQDN;            // Service's FQDN, i.e., name of its SRV and TXT records.
+       uint8_t *                                               txtPtr;                         // Pointer to service's TXT record data. (malloc'd)
+       size_t                                                  txtLen;                         // Length of service's TXT record data.
+       RegistrationInterfaceItem *             ifList;                         // If ifIndex == 0, interfaces that service should register over.
+       RegistrationResultTimes                 ifTimes;                        // If ifIndex != 0, result times for interface with that index.
+       RegistrationTest *                              test;                           // Pointer to parent test.
+       NanoTime64                                              startTime;                      // Subtest's start time.
+       char *                                                  description;            // Subtest's description. (malloc'd)
+       uint32_t                                                ifIndex;                        // Interface index used for service registration.
+       uint16_t                                                port;                           // Service's port number.
+       Boolean                                                 useLODiscovery;         // True if discovery is to use kDNSServiceInterfaceIndexLocalOnly.
+       Boolean                                                 includeAWDL;            // True if the IncludeAWDL flag was used during registration.
+       Boolean                                                 ifIsAWDL;                       // True if ifIndex is the index of an AWDL interface.
+       Boolean                                                 skipped;                        // True if this subtest is to be skipped.
+       Boolean                                                 registered;                     // True if the test service was successfully registered.
+       Boolean                                                 useDefaultName;         // True if the service is to use the default service name.
+};
+
+static OSStatus        _RegistrationTestCreate( RegistrationTest **outTest );
+static void            _RegistrationTestFree( RegistrationTest *inTest );
+static void            _RegistrationTestBegin( void *inContext );
+static void            _RegistrationTestProceed( RegistrationTest *inTest );
+static OSStatus        _RegistrationTestStart( RegistrationTest *inTest );
+static void            _RegistrationTestStop( RegistrationTest *inTest );
+#define _RegistrationTestForget( X )           ForgetCustomEx( X, _RegistrationTestStop, _RegistrationTestFree )
+static OSStatus
+       _RegistrationTestStartSubtest(
+               RegistrationTest *                                      inTest,
+               const RegistrationSubtestParams *       inParams,
+               Boolean *                                                       outSkipped );
+static OSStatus        _RegistrationTestEndSubtest( RegistrationTest *inTest );
+static void            _RegistrationTestEnd( RegistrationTest *inTest ) ATTRIBUTE_NORETURN;
+static void            _RegistrationTestExit( RegistrationTest *inTest, OSStatus inError ) ATTRIBUTE_NORETURN;
+static OSStatus        _RegistrationSubtestCreate( RegistrationSubtest **outSubtest );
+static void            _RegistrationSubtestStop( RegistrationSubtest *inSubtest );
+static void            _RegistrationSubtestFree( RegistrationSubtest *inSubtest );
+#define _RegistrationSubtestForget( X )                ForgetCustomEx( X, _RegistrationSubtestStop, _RegistrationSubtestFree )
+static OSStatus        _RegistrationTestInterfaceListCreate( Boolean inIncludeAWDL, RegistrationInterfaceItem **outList );
+static OSStatus
+       _RegistrationTestCreateRandomTXTRecord(
+               size_t          inMinLen,
+               size_t          inMaxLen,
+               uint8_t **      outTXTPtr,
+               size_t *        outTXTLen );
+static void DNSSD_API
+       _RegistrationSubtestRegisterCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inType,
+               const char *            inDomain,
+               void *                          inContext );
+static void DNSSD_API
+       _RegistrationSubtestBrowseCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inIfIndex,
+               DNSServiceErrorType     inError,
+               const char *            inServiceName,
+               const char *            inServiceType,
+               const char *            inDomain,
+               void *                          inContext );
+static void DNSSD_API
+       _RegistrationSubtestQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inIfIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static Boolean _RegistrationSubtestValidServiceType( const RegistrationSubtest *inSubtest, const char *inServiceType );
+static RegistrationResultTimes *
+       _RegistrationSubtestGetInterfaceResultTimes(
+               RegistrationSubtest *   inSubtest,
+               uint32_t                                inIfIndex,
+               Boolean *                               outIsAWDL );
+static void            _RegistrationTestTimerHandler( void *inContext );
+#if( TARGET_OS_WATCH )
+static Boolean _RegistrationTestInterfaceIsWiFi( const char *inIfName );
+#endif
+
+static void    RegistrationTestCmd( void )
+{
+       OSStatus                                err;
+       RegistrationTest *              test;
+       
+       err = _RegistrationTestCreate( &test );
+       require_noerr( err, exit );
+       
+       if( gRegistrationTest_BATSEnvironment ) test->forBATS = true;
+       if( gRegistrationTest_OutputFilePath )
+       {
+               test->outputFilePath = strdup( gRegistrationTest_OutputFilePath );
+               require_action( test->outputFilePath, exit, err = kNoMemoryErr );
+       }
+       
+       err = OutputFormatFromArgString( gRegistrationTest_OutputFormat, &test->outputFormat );
+       require_noerr_quiet( err, exit );
+       
+       dispatch_async_f( dispatch_get_main_queue(), test, _RegistrationTestBegin );
+       dispatch_main();
+       
+exit:
+       if( test ) _RegistrationTestFree( test );
+       ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+
+static OSStatus        _RegistrationTestCreate( RegistrationTest **outTest )
+{
+       OSStatus                                err;
+       RegistrationTest *              obj;
+       
+       obj = (RegistrationTest *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->subtestReports = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( obj->subtestReports, exit, err = kNoMemoryErr );
+       
+       *outTest = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _RegistrationTestFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestFree( RegistrationTest *inTest )
+{
+       check( !inTest->timer );
+       check( !inTest->sigSourceINT );
+       check( !inTest->sigSourceTERM );
+       check( !inTest->computerNameSet );
+       check( !inTest->localHostNameSet );
+       check( !inTest->subtest );
+       ForgetCF( &inTest->subtestReports );
+       ForgetMem( &inTest->outputFilePath );
+       ForgetCF( &inTest->computerNamePrev );
+       ForgetCF( &inTest->localHostNamePrev );
+       ForgetMem( &inTest->computerName );
+       ForgetMem( &inTest->localHostName );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestBegin( void *inContext )
+{
+       _RegistrationTestProceed( (RegistrationTest *) inContext );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestProceed( RegistrationTest *inTest )
+{
+       OSStatus                err;
+       Boolean                 skippedSubtest;
+       
+       do
+       {
+               int             subtestIndex;
+               
+               if( !inTest->startTime )
+               {
+                       err = _RegistrationTestStart( inTest );
+                       require_noerr_quiet( err, exit );
+                       
+                       inTest->startTime = NanoTimeGetCurrent();
+               }
+               else
+               {
+                       err = _RegistrationTestEndSubtest( inTest );
+                       require_noerr( err, exit );
+                       
+                       ++inTest->subtestIndex;
+               }
+               
+               subtestIndex = inTest->subtestIndex;
+               if( subtestIndex < (int) countof( kRegistrationSubtestParams ) )
+               {
+                       err = _RegistrationTestStartSubtest( inTest, &kRegistrationSubtestParams[ subtestIndex ], &skippedSubtest );
+                       require_noerr_quiet( err, exit );
+               }
+               else
+               {
+                       _RegistrationTestEnd( inTest );
+               }
+               
+       }       while( skippedSubtest );
+       
+exit:
+       if( err ) _RegistrationTestExit( inTest, err );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestSignalHandler( void *inContext );
+
+static OSStatus        _RegistrationTestStart( RegistrationTest *inTest )
+{
+       OSStatus                err;
+       char                    tag[ 6 + 1 ];
+       
+       // Save original ComputerName and LocalHostName.
+       
+       check( !inTest->computerNamePrev );
+       inTest->computerNamePrev = SCDynamicStoreCopyComputerName( NULL, &inTest->computerNamePrevEncoding );
+       err = map_scerror( inTest->computerNamePrev );
+       require_noerr( err, exit );
+       
+       check( !inTest->localHostNamePrev );
+       inTest->localHostNamePrev = SCDynamicStoreCopyLocalHostName( NULL );
+       err = map_scerror( inTest->localHostNamePrev );
+       require_noerr( err, exit );
+       
+       // Generate a unique test ComputerName.
+       
+       check( !inTest->computerName ); 
+       ASPrintF( &inTest->computerName, "dnssdutil-regtest-computer-name-%s",
+               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+       require_action( inTest->computerName, exit, err = kNoMemoryErr );
+       
+       // Generate a unique test LocalHostName.
+       
+       check( !inTest->localHostName ); 
+       ASPrintF( &inTest->localHostName, "dnssdutil-regtest-local-hostname-%s",
+               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+       require_action( inTest->localHostName, exit, err = kNoMemoryErr );
+       
+       // Set up SIGINT signal handler.
+       
+       signal( SIGINT, SIG_IGN );
+       check( !inTest->sigSourceINT ); 
+       err = DispatchSignalSourceCreate( SIGINT, _RegistrationTestSignalHandler, inTest, &inTest->sigSourceINT );
+       require_noerr( err, exit );
+       dispatch_resume( inTest->sigSourceINT );
+       
+       // Set up SIGTERM signal handler.
+       
+       signal( SIGTERM, SIG_IGN );
+       check( !inTest->sigSourceTERM ); 
+       err = DispatchSignalSourceCreate( SIGTERM, _RegistrationTestSignalHandler, inTest, &inTest->sigSourceTERM );
+       require_noerr( err, exit );
+       dispatch_resume( inTest->sigSourceTERM );
+       
+       // Set test ComputerName.
+       
+       check( !inTest->computerNameSet );
+       err = _SetComputerNameWithUTF8CString( inTest->computerName );
+       require_noerr( err, exit );
+       inTest->computerNameSet = true;
+       
+       // Set test LocalHostName.
+       
+       check( !inTest->localHostNameSet );
+       err = _SetLocalHostNameWithUTF8CString( inTest->localHostName );
+       require_noerr( err, exit );
+       inTest->localHostNameSet = true;
+       
+exit:
+       if( err ) _RegistrationTestStop( inTest );
+       return( err );
+}
+
+static void    _RegistrationTestSignalHandler( void *inContext )
+{
+       RegistrationTest * const                test = (RegistrationTest *) inContext;
+       
+       FPrintF( stderr, "Registration test got a SIGINT or SIGTERM signal, exiting..." );
+       
+       _RegistrationTestExit( test, kCanceledErr );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestStop( RegistrationTest *inTest )
+{
+       OSStatus                err;
+       
+       dispatch_source_forget( &inTest->timer );
+       dispatch_source_forget( &inTest->sigSourceINT );
+       dispatch_source_forget( &inTest->sigSourceTERM );
+       _RegistrationSubtestForget( &inTest->subtest );
+       if( inTest->computerNameSet )
+       {
+               err = _SetComputerName( inTest->computerNamePrev, inTest->computerNamePrevEncoding );
+               check_noerr( err );
+               if( !err ) inTest->computerNameSet = false;
+       }
+       if( inTest->localHostNameSet )
+       {
+               err = _SetLocalHostName( inTest->localHostNamePrev );
+               check_noerr( err );
+               if( !err ) inTest->localHostNameSet = false;
+       }
+}
+
+//===========================================================================================================================
+
+#define kRegistrationTestSubtestDurationSecs           5
+
+static OSStatus
+       _RegistrationTestStartSubtest(
+               RegistrationTest *                                      inTest,
+               const RegistrationSubtestParams *       inParams,
+               Boolean *                                                       outSkipped )
+{
+       OSStatus                                        err;
+       RegistrationSubtest *           subtest;
+       const char *                            interfaceDesc;
+       DNSServiceFlags                         flags;
+       char                                            tag[ 6 + 1 ];
+       
+       subtest = NULL;
+       err = _RegistrationSubtestCreate( &subtest );
+       require_noerr( err, exit );
+       
+       subtest->test                   = inTest;
+       subtest->useDefaultName = inParams->useDefaultName;
+       subtest->useLODiscovery = inParams->useLODiscovery;
+       
+       // Determine registration interfaces.
+       
+       switch( inParams->interfaceSet )
+       {
+               case kRegistrationInterfaceSet_All:
+                       subtest->ifIndex = kDNSServiceInterfaceIndexAny;
+                       
+                       if( !subtest->useLODiscovery )
+                       {
+                               err = _RegistrationTestInterfaceListCreate( false, &subtest->ifList );
+                               require_noerr( err, exit );
+                       }
+                       interfaceDesc = "all interfaces (excluding AWDL)";
+                       break;
+               
+               case kRegistrationInterfaceSet_AllPlusAWDL:
+                       subtest->ifIndex                = kDNSServiceInterfaceIndexAny;
+                       subtest->includeAWDL    = true;
+                       
+                       if( !subtest->useLODiscovery )
+                       {
+                               err = _RegistrationTestInterfaceListCreate( true, &subtest->ifList );
+                               require_noerr( err, exit );
+                       }
+                       interfaceDesc = "all interfaces (including AWDL)";
+                       break;
+               
+               case kRegistrationInterfaceSet_LoopbackOnly:
+                       subtest->ifIndex = if_nametoindex( "lo0" );
+                       if( subtest->ifIndex == 0 )
+                       {
+                               FPrintF( stderr, "Failed to get index for loopback interface lo0.\n" );
+                               err = kNoResourcesErr;
+                               goto exit;
+                       }
+                       interfaceDesc = "loopback interface";
+                       break;
+               
+               case kRegistrationInterfaceSet_AWDLOnly:
+                       err = _MDNSInterfaceGetAny( kMDNSInterfaceSubset_AWDL, NULL, &subtest->ifIndex );
+                       if( err == kNotFoundErr )
+                       {
+                               FPrintF( stderr, "Warning: No mDNS-capable AWDL interface is available.\n" );
+                               subtest->skipped = true;
+                               err = kNoErr;
+                       }
+                       require_noerr( err, exit );
+                       
+                       subtest->ifIsAWDL = true;
+                       interfaceDesc = "AWDL interface";
+                       break;
+               
+               default:
+                       err = kParamErr;
+                       goto exit;
+       }
+       
+       // Create description.
+       
+       ASPrintF( &subtest->description, "Service registration over %s using %s service name.%s",
+               interfaceDesc, subtest->useDefaultName ? "default" : "custom",
+               subtest->useLODiscovery ? " (LocalOnly discovery)" : "" );
+       require_action( subtest->description, exit, err = kNoMemoryErr );
+       
+       if( subtest->skipped )
+       {
+               subtest->startTime = NanoTimeGetCurrent();
+       }
+       else
+       {
+               // Generate a service name.
+               
+               if( subtest->useDefaultName )
+               {
+                       subtest->serviceName = inTest->computerName;
+               }
+               else
+               {
+                       ASPrintF( &subtest->serviceNameCustom, "dnssdutil-regtest-service-name-%s",
+                               _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+                       require_action( subtest->serviceNameCustom, exit, err = kNoMemoryErr );
+                       
+                       subtest->serviceName = subtest->serviceNameCustom;
+               }
+               
+               // Generate a service type.
+               
+               ASPrintF( &subtest->serviceType, "_regtest-%s._udp",
+                       _RandomStringExact( kLowerAlphaNumericCharSet, kLowerAlphaNumericCharSetSize, sizeof( tag ) - 1, tag ) );
+               require_action( subtest->serviceType, exit, err = kNoMemoryErr );
+               
+               subtest->serviceTypeLen = strlen( subtest->serviceType );
+               
+               // Create SRV and TXT record name FQDN.
+               
+               ASPrintF( &subtest->serviceFQDN, "%s.%s.local.", subtest->serviceName, subtest->serviceType );
+               require_action( subtest->serviceFQDN, exit, err = kNoMemoryErr );
+               
+               // Generate a port number.
+               
+               subtest->port = (uint16_t) RandomRange( 60000, 65535 );
+               
+               // Generate TXT record data.
+               
+               err = _RegistrationTestCreateRandomTXTRecord( 100, 1000, &subtest->txtPtr, &subtest->txtLen );
+               require_noerr( err, exit );
+               
+               // Register service.
+               
+               subtest->startTime = NanoTimeGetCurrent();
+               
+               flags = kDNSServiceFlagsNoAutoRename;
+               if( subtest->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+               err = DNSServiceRegister( &subtest->registration, flags, subtest->ifIndex,
+                       subtest->useDefaultName ? NULL : subtest->serviceNameCustom, subtest->serviceType, "local.",
+                       NULL, htons( subtest->port ), (uint16_t) subtest->txtLen, subtest->txtPtr,
+                       _RegistrationSubtestRegisterCallback, subtest );
+               require_noerr( err, exit );
+               
+               err = DNSServiceSetDispatchQueue( subtest->registration, dispatch_get_main_queue() );
+               require_noerr( err, exit );
+               
+               // Start timer.
+               
+               check( !inTest->timer );
+               err = DispatchTimerOneShotCreate( dispatch_time_seconds( kRegistrationTestSubtestDurationSecs ),
+                       INT64_C_safe( kRegistrationTestSubtestDurationSecs ) * kNanosecondsPerSecond / 10, dispatch_get_main_queue(),
+                       _RegistrationTestTimerHandler, inTest, &inTest->timer );
+               require_noerr( err, exit );
+               dispatch_resume( inTest->timer );
+       }
+       
+       *outSkipped = subtest->skipped;
+       
+       check( !inTest->subtest );
+       inTest->subtest = subtest;
+       subtest = NULL;
+       
+exit:
+       _RegistrationSubtestForget( &subtest );
+       return( err );
+}
+
+//===========================================================================================================================
+
+#define kRegistrationTestReportKey_ComputerName                        CFSTR( "computerName" )                 // String
+#define kRegistrationTestReportKey_Description                 CFSTR( "description" )                  // String
+#define kRegistrationTestReportKey_Domain                              CFSTR( "domain" )                               // String
+#define kRegistrationTestReportKey_EndTime                             CFSTR( "endTime" )                              // String
+#define kRegistrationTestReportKey_Error                               CFSTR( "error" )                                // Integer
+#define kRegistrationTestReportKey_Flags                               CFSTR( "flags" )                                // Integer
+#define kRegistrationTestReportKey_IgnoredResults              CFSTR( "ignoredResults" )               // Array of dictionaries
+#define kRegistrationTestReportKey_InterfaceIndex              CFSTR( "ifIndex" )                              // Integer
+#define kRegistrationTestReportKey_InterfaceName               CFSTR( "ifName" )                               // String
+#define kRegistrationTestReportKey_LocalHostName               CFSTR( "localHostName" )                // String
+#define kRegistrationTestReportKey_MissingResults              CFSTR( "missingResults" )               // Array of dictionaries
+#define kRegistrationTestReportKey_Pass                                        CFSTR( "pass" )                                 // Boolean
+#define kRegistrationTestReportKey_Port                                        CFSTR( "port" )                                 // Integer
+#define kRegistrationTestReportKey_RDataFormatted              CFSTR( "rdataFormatted" )               // String
+#define kRegistrationTestReportKey_RDataHexString              CFSTR( "rdataHexString" )               // String
+#define kRegistrationTestReportKey_RecordClass                 CFSTR( "recordClass" )                  // Integer
+#define kRegistrationTestReportKey_RecordType                  CFSTR( "recordType" )                   // Integer
+#define kRegistrationTestReportKey_Registered                  CFSTR( "registered" )                   // Boolean
+#define kRegistrationTestReportKey_ResultType                  CFSTR( "resultType" )                   // String
+#define kRegistrationTestReportKey_ServiceFQDN                 CFSTR( "serviceFQDN" )                  // String
+#define kRegistrationTestReportKey_ServiceName                 CFSTR( "serviceName" )                  // String
+#define kRegistrationTestReportKey_ServiceType                 CFSTR( "serviceType" )                  // String
+#define kRegistrationTestReportKey_Skipped                             CFSTR( "skipped" )                              // Boolean
+#define kRegistrationTestReportKey_StartTime                   CFSTR( "startTime" )                    // String
+#define kRegistrationTestReportKey_Subtests                            CFSTR( "subtests" )                             // Array of dictionaries
+#define kRegistrationTestReportKey_Timestamp                   CFSTR( "timestamp" )                    // String
+#define kRegistrationTestReportKey_TXT                                 CFSTR( "txt" )                                  // String
+#define kRegistrationTestReportKey_UnexpectedResults   CFSTR( "unexpectedResults" )    // Array of dictionaries
+#define kRegistrationTestReportKey_UsedDefaultName             CFSTR( "usedDefaultName" )              // Boolean
+#define kRegistrationTestReportKey_UsedLODiscovery             CFSTR( "usedLODiscovery" )              // Boolean
+
+#define kRegistrationTestResultType_Browse                             CFSTR( "browse" )
+#define kRegistrationTestResultType_Query                              CFSTR( "query" )
+#define kRegistrationTestResultType_QuerySRV                   CFSTR( "querySRV" )
+#define kRegistrationTestResultType_QueryTXT                   CFSTR( "queryTXT" )
+#define kRegistrationTestResultType_Registration               CFSTR( "registration" )
+
+static OSStatus
+       _RegistrationTestAppendMissingResults(
+               CFMutableArrayRef                               inMissingResults,
+               const RegistrationResultTimes * inTimes,
+               uint32_t                                                inIfIndex,
+               const char *                                    inIfName );
+
+static OSStatus        _RegistrationTestEndSubtest( RegistrationTest *inTest )
+{
+       OSStatus                                        err;
+       RegistrationSubtest *           subtest;
+       CFMutableDictionaryRef          subtestReport;
+       CFMutableArrayRef                       missing;
+       char *                                          txtStr;
+       NanoTime64                                      now;
+       Boolean                                         subtestFailed;
+       char                                            startTime[ 32 ];
+       char                                            endTime[ 32 ];
+       char                                            ifNameBuf[ IF_NAMESIZE + 1 ];
+       
+       now = NanoTimeGetCurrent();
+       
+       subtest = inTest->subtest;
+       inTest->subtest = NULL;
+       _RegistrationSubtestStop( subtest );
+       
+       missing                 = NULL;
+       subtestReport   = NULL;
+       txtStr                  = NULL;
+       if( subtest->txtPtr )
+       {
+               err = DNSRecordDataToString( subtest->txtPtr, subtest->txtLen, kDNSServiceType_TXT, NULL, 0, &txtStr );
+               require_noerr( err, exit );
+       }
+       _NanoTime64ToTimestamp( subtest->startTime, startTime, sizeof( startTime ) );
+       _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &subtestReport,
+               "{"
+                       "%kO=%s"        // description
+                       "%kO=%s"        // startTime
+                       "%kO=%s"        // endTime
+                       "%kO=%s"        // serviceFQDN
+                       "%kO=%lli"      // ifIndex
+                       "%kO=%s"        // ifName
+                       "%kO=%lli"      // port
+                       "%kO=%s"        // txt
+                       "%kO=%b"        // registered
+                       "%kO=%b"        // usedDefaultName
+                       "%kO=%b"        // usedLODiscovery
+               "}",
+               kRegistrationTestReportKey_Description,         subtest->description,
+               kRegistrationTestReportKey_StartTime,           startTime,
+               kRegistrationTestReportKey_EndTime,                     endTime,
+               kRegistrationTestReportKey_ServiceFQDN,         subtest->serviceFQDN,
+               kRegistrationTestReportKey_InterfaceIndex,      (int64_t) subtest->ifIndex,
+               kRegistrationTestReportKey_InterfaceName,       if_indextoname( subtest->ifIndex, ifNameBuf ),
+               kRegistrationTestReportKey_Port,                        (int64_t) subtest->port,
+               kRegistrationTestReportKey_TXT,                         txtStr,
+               kRegistrationTestReportKey_Registered,          (int) subtest->registered,
+               kRegistrationTestReportKey_UsedDefaultName,     (int) subtest->useDefaultName,
+               kRegistrationTestReportKey_UsedLODiscovery,     (int) subtest->useLODiscovery );
+       ForgetMem( &txtStr );
+       require_noerr( err, exit );
+       
+       if( !subtest->skipped && subtest->registered )
+       {
+               missing = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+               require_action( missing, exit, err = kNoMemoryErr );
+               
+               if( subtest->ifList )
+               {
+                       RegistrationInterfaceItem *             item;
+                       
+                       for( item = subtest->ifList; item; item = (RegistrationInterfaceItem *) item->base.next )
+                       {
+                       #if( TARGET_OS_WATCH )
+                               if( inTest->forBATS && item->base.isWiFi ) continue;
+                       #endif
+                               err = _RegistrationTestAppendMissingResults( missing, &item->times, item->base.ifIndex, item->base.ifName );
+                               require_noerr( err, exit );
+                       }
+               }
+               else
+               {
+                       err = _RegistrationTestAppendMissingResults( missing, &subtest->ifTimes, subtest->ifIndex, NULL );
+                       require_noerr( err, exit );
+               }
+               
+               subtestFailed = false;
+               if( CFArrayGetCount( missing ) > 0 )
+               {
+                       subtestFailed = true;
+                       CFDictionarySetValue( subtestReport, kRegistrationTestReportKey_MissingResults, missing );
+               }
+               if( CFArrayGetCount( subtest->unexpected ) > 0 )
+               {
+                       subtestFailed = true;
+                       CFDictionarySetValue( subtestReport, kRegistrationTestReportKey_UnexpectedResults, subtest->unexpected );
+               }
+       #if( TARGET_OS_WATCH )
+               if( CFArrayGetCount( subtest->ignored ) > 0 )
+               {
+                       CFDictionarySetValue( subtestReport, kRegistrationTestReportKey_IgnoredResults, subtest->ignored );
+               }
+       #endif
+       }
+       else
+       {
+               subtestFailed = true;
+       }
+       
+       CFDictionarySetBoolean( subtestReport, kRegistrationTestReportKey_Pass, subtestFailed ? false : true );
+       if( subtestFailed )
+       {
+               CFDictionarySetBoolean( subtestReport, kRegistrationTestReportKey_Skipped, subtest->skipped );
+               if( !subtest->skipped ) inTest->failed = true;
+       }
+       CFArrayAppendValue( inTest->subtestReports, subtestReport );
+       
+exit:
+       CFReleaseNullSafe( missing );
+       CFReleaseNullSafe( subtestReport );
+       _RegistrationSubtestFree( subtest );
+       return( err );
+}
+
+static OSStatus
+       _RegistrationTestAppendMissingResult(
+               CFMutableArrayRef       inMissingResults,
+               CFStringRef                     inType,
+               uint32_t                        inIfIndex,
+               const char *            inIfName );
+
+static OSStatus
+       _RegistrationTestAppendMissingResults(
+               CFMutableArrayRef                               inMissingResults,
+               const RegistrationResultTimes * inTimes,
+               uint32_t                                                inIfIndex,
+               const char *                                    inIfName )
+{
+       OSStatus                err;
+       
+       if( !inTimes->browseResultTime )
+       {
+               err = _RegistrationTestAppendMissingResult( inMissingResults, kRegistrationTestResultType_Browse,
+                       inIfIndex, inIfName );
+               require_noerr( err, exit );
+       }
+       if( !inTimes->querySRVResultTime )
+       {
+               err = _RegistrationTestAppendMissingResult( inMissingResults, kRegistrationTestResultType_QuerySRV,
+                       inIfIndex, inIfName );
+               require_noerr( err, exit );
+       }
+       if( !inTimes->queryTXTResultTime )
+       {
+               err = _RegistrationTestAppendMissingResult( inMissingResults, kRegistrationTestResultType_QueryTXT,
+                       inIfIndex, inIfName );
+               require_noerr( err, exit );
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+static OSStatus
+       _RegistrationTestAppendMissingResult(
+               CFMutableArrayRef       inMissingResults,
+               CFStringRef                     inType,
+               uint32_t                        inIfIndex,
+               const char *            inIfName )
+{
+       OSStatus                err;
+       char                    ifName[ IF_NAMESIZE + 1 ];
+       
+       err = CFPropertyListAppendFormatted( kCFAllocatorDefault, inMissingResults,
+               "{"
+                       "%kO=%O"        // resultType
+                       "%kO=%lli"      // ifIndex
+                       "%kO=%s"        // ifName
+               "}",
+               kRegistrationTestReportKey_ResultType,          inType,
+               kRegistrationTestReportKey_InterfaceIndex,      (int64_t) inIfIndex,
+               kRegistrationTestReportKey_InterfaceName,       inIfName ? inIfName : if_indextoname( inIfIndex, ifName ) );
+       return( err );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestEnd( RegistrationTest *inTest )
+{
+       OSStatus                                err;
+       NanoTime64                              now;
+       CFPropertyListRef               plist;
+       char                                    startTime[ 32 ];
+       char                                    endTime[ 32 ];
+       
+       now = NanoTimeGetCurrent();
+       _NanoTime64ToTimestamp( inTest->startTime, startTime, sizeof( startTime ) );
+       _NanoTime64ToTimestamp( now, endTime, sizeof( endTime ) );
+       
+       err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &plist,
+               "{"
+                       "%kO=%s"        // startTime
+                       "%kO=%s"        // endTime
+                       "%kO=%s"        // computerName
+                       "%kO=%s"        // localHostName
+                       "%kO=%O"        // subtests
+                       "%kO=%b"        // pass
+               "}",
+               kRegistrationTestReportKey_StartTime,           startTime,
+               kRegistrationTestReportKey_EndTime,                     endTime,
+               kRegistrationTestReportKey_ComputerName,        inTest->computerName,
+               kRegistrationTestReportKey_LocalHostName,       inTest->localHostName,
+               kRegistrationTestReportKey_Subtests,            inTest->subtestReports,
+               kRegistrationTestReportKey_Pass,                        inTest->failed ? false : true );
+       require_noerr( err, exit );
+       
+       err = OutputPropertyList( plist, inTest->outputFormat, inTest->outputFilePath );
+       CFRelease( plist );
+       require_noerr( err, exit );
+       
+exit:
+       _RegistrationTestExit( inTest, err );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestExit( RegistrationTest *inTest, OSStatus inError )
+{
+       int             exitCode;
+       
+       if( inError )
+       {
+               FPrintF( stderr, "error: %#m\n", inError );
+               exitCode = 1;
+       }
+       else
+       {
+               exitCode = inTest->failed ? 2 : 0;
+       }
+       _RegistrationTestForget( &inTest );
+       exit( exitCode );
+}
+
+//===========================================================================================================================
+
+static OSStatus        _RegistrationSubtestCreate( RegistrationSubtest **outSubtest )
+{
+       OSStatus                                        err;
+       RegistrationSubtest *           obj;
+       
+       obj = (RegistrationSubtest *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->unexpected = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( obj->unexpected, exit, err = kNoMemoryErr );
+       
+#if( TARGET_OS_WATCH )
+       obj->ignored = CFArrayCreateMutable( NULL, 0, &kCFTypeArrayCallBacks );
+       require_action( obj->ignored, exit, err = kNoMemoryErr );
+#endif
+       
+       *outSubtest = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _RegistrationSubtestFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationSubtestFree( RegistrationSubtest *inSubtest )
+{
+       check( !inSubtest->registration );
+       check( !inSubtest->browse );
+       check( !inSubtest->querySRV );
+       check( !inSubtest->queryTXT );
+       check( !inSubtest->connection );
+       ForgetMem( &inSubtest->serviceNameCustom );
+       ForgetMem( &inSubtest->serviceType );
+       ForgetMem( &inSubtest->serviceFQDN );
+       ForgetMem( &inSubtest->txtPtr );
+       ForgetCF( &inSubtest->unexpected );
+#if( TARGET_OS_WATCH )
+       ForgetCF( &inSubtest->ignored );
+#endif
+       _MDNSInterfaceListForget( (MDNSInterfaceItem **) &inSubtest->ifList );
+       ForgetMem( &inSubtest->description );
+       free( inSubtest );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationSubtestStop( RegistrationSubtest *inSubtest )
+{
+       DNSServiceForget( &inSubtest->registration );
+       DNSServiceForget( &inSubtest->browse );
+       DNSServiceForget( &inSubtest->querySRV );
+       DNSServiceForget( &inSubtest->queryTXT );
+       DNSServiceForget( &inSubtest->connection );
+}
+
+//===========================================================================================================================
+
+static OSStatus        _RegistrationTestInterfaceListCreate( Boolean inIncludeAWDL, RegistrationInterfaceItem **outList )
+{
+       OSStatus                                                err;
+       RegistrationInterfaceItem *             list;
+       const MDNSInterfaceSubset               subset = inIncludeAWDL ? kMDNSInterfaceSubset_All : kMDNSInterfaceSubset_NonAWDL;
+       
+       err = _MDNSInterfaceListCreate( subset, sizeof( *list ), (MDNSInterfaceItem **) &list );
+       require_noerr( err, exit );
+       
+       *outList = list;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+
+static OSStatus
+       _RegistrationTestCreateRandomTXTRecord(
+               size_t          inMinLen,
+               size_t          inMaxLen,
+               uint8_t **      outTXTPtr,
+               size_t *        outTXTLen )
+{
+       OSStatus                        err;
+       uint8_t *                       ptr;
+       const uint8_t *         txtEnd;
+       uint8_t *                       txtPtr = NULL;
+       size_t                          txtLen;
+       
+       require_action_quiet( inMinLen <= inMaxLen, exit, err = kSizeErr );
+       
+       txtLen = RandomRange( inMinLen, inMaxLen );
+       txtPtr = (uint8_t *) malloc( txtLen + 1 );
+       require_action( txtPtr, exit, err = kNoMemoryErr );
+       
+       _RandomStringExact( kAlphaNumericCharSet, sizeof_string( kAlphaNumericCharSet ), txtLen, (char *)txtPtr );
+       
+       ptr             = txtPtr;
+       txtEnd  = &txtPtr[ txtLen ];
+       while( ptr < txtEnd )
+       {
+               size_t          maxLen, len;
+               
+               maxLen = ( (size_t)( txtEnd - ptr ) ) - 1;
+               len = RandomRange( 1, 255 );
+               if( len > maxLen ) len = maxLen;
+               
+               *ptr = (uint8_t) len;
+               ptr += ( 1 + len );
+       }
+       check( ptr == txtEnd );
+       
+       if( outTXTPtr )
+       {
+               *outTXTPtr = txtPtr;
+               txtPtr = NULL;
+       }
+       if( outTXTLen ) *outTXTLen = txtLen;
+       err = kNoErr;
+       
+exit:
+       FreeNullSafe( txtPtr );
+       return( err );
+}
+
+//===========================================================================================================================
+
+static void DNSSD_API
+       _RegistrationSubtestRegisterCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               DNSServiceErrorType     inError,
+               const char *            inServiceName,
+               const char *            inServiceType,
+               const char *            inDomain,
+               void *                          inContext )
+{
+       OSStatus                                                err;
+       const NanoTime64                                now             = NanoTimeGetCurrent();
+       RegistrationSubtest * const             subtest = (RegistrationSubtest *) inContext;
+       
+       Unused( inSDRef );
+       
+       if( ( inFlags & kDNSServiceFlagsAdd ) && !inError &&
+               ( strcasecmp( inServiceName, subtest->serviceName ) == 0 ) &&
+               _RegistrationSubtestValidServiceType( subtest, inServiceType ) &&
+               ( strcasecmp( inDomain, "local." ) == 0 ) )
+       {
+               if( !subtest->registered )
+               {
+                       DNSServiceRef                           sdRef;
+                       const DNSServiceFlags           flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsIncludeAWDL;
+                       
+                       subtest->registered = true;
+                       
+                       // Create shared connection.
+                       
+                       check( !subtest->connection );
+                       err = DNSServiceCreateConnection( &subtest->connection );
+                       require_noerr( err, exit );
+                       
+                       err = DNSServiceSetDispatchQueue( subtest->connection, dispatch_get_main_queue() );
+                       require_noerr( err, exit );
+                       
+                       // Start browse.
+                       
+                       check( !subtest->browse );
+                       sdRef = subtest->connection;
+                       err = DNSServiceBrowse( &sdRef, flags,
+                               subtest->useLODiscovery ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny,
+                               subtest->serviceType, "local.", _RegistrationSubtestBrowseCallback, subtest );
+                       require_noerr( err, exit );
+                       
+                       subtest->browse = sdRef;
+               }
+       }
+       else
+       {
+               char            timestamp[ 32 ];
+               
+               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, subtest->unexpected,
+                       "{"
+                               "%kO=%O"        // resultType
+                               "%kO=%s"        // timestamp
+                               "%kO=%lli"      // flags
+                               "%kO=%lli"      // error
+                               "%kO=%s"        // serviceName
+                               "%kO=%s"        // serviceType
+                               "%kO=%s"        // domain
+                       "}",
+                       kRegistrationTestReportKey_ResultType,  kRegistrationTestResultType_Registration,
+                       kRegistrationTestReportKey_Timestamp,   _NanoTime64ToTimestamp( now, timestamp, sizeof( timestamp ) ),
+                       kRegistrationTestReportKey_Flags,               (int64_t) inFlags,
+                       kRegistrationTestReportKey_Error,               (int64_t) inError,
+                       kRegistrationTestReportKey_ServiceName, inServiceName,
+                       kRegistrationTestReportKey_ServiceType, inServiceType,
+                       kRegistrationTestReportKey_Domain,              inDomain );
+               require_noerr( err, exit );
+       }
+       err = kNoErr;
+       
+exit:
+       if( err ) _RegistrationTestExit( subtest->test, err );
+}
+
+//===========================================================================================================================
+
+static void DNSSD_API
+       _RegistrationSubtestBrowseCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inIfIndex,
+               DNSServiceErrorType     inError,
+               const char *            inServiceName,
+               const char *            inServiceType,
+               const char *            inDomain,
+               void *                          inContext )
+{
+       OSStatus                                                err;
+       NanoTime64                                              now;
+       RegistrationSubtest * const             subtest = (RegistrationSubtest *) inContext;
+       Boolean                                                 serviceIsCorrect, resultIsExpected;
+       
+       Unused( inSDRef );
+       
+       now = NanoTimeGetCurrent();
+       if( !inError && ( strcasecmp( inServiceName, subtest->serviceName ) == 0 ) &&
+               _RegistrationSubtestValidServiceType( subtest, inServiceType ) && ( strcasecmp( inDomain, "local." ) == 0 ) )
+       {
+               serviceIsCorrect = true;
+       }
+       else
+       {
+               serviceIsCorrect = false;
+       }
+       
+       resultIsExpected = false;
+       if( serviceIsCorrect && ( inFlags & kDNSServiceFlagsAdd ) )
+       {
+               RegistrationResultTimes *               times;
+               
+               times = _RegistrationSubtestGetInterfaceResultTimes( subtest, inIfIndex, NULL );
+               if( times )
+               {
+                       DNSServiceRef                           sdRef;
+                       const DNSServiceFlags           flags = kDNSServiceFlagsShareConnection | kDNSServiceFlagsIncludeAWDL;
+                       uint32_t                                        ifIndex;
+                       
+                       resultIsExpected = true;
+                       if( !times->browseResultTime ) times->browseResultTime = now;
+                       
+                       ifIndex = subtest->useLODiscovery ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny;
+                       if( !subtest->querySRV )
+                       {
+                               // Start SRV record query.
+                               
+                               sdRef = subtest->connection;
+                               err = DNSServiceQueryRecord( &sdRef, flags, ifIndex, subtest->serviceFQDN, kDNSServiceType_SRV,
+                                       kDNSServiceClass_IN, _RegistrationSubtestQueryCallback, subtest );
+                               require_noerr( err, exit );
+                               
+                               subtest->querySRV = sdRef;
+                       }
+                       if( !subtest->queryTXT )
+                       {
+                               // Start TXT record query.
+                               
+                               sdRef = subtest->connection;
+                               err = DNSServiceQueryRecord( &sdRef, flags, ifIndex, subtest->serviceFQDN, kDNSServiceType_TXT,
+                                       kDNSServiceClass_IN, _RegistrationSubtestQueryCallback, subtest );
+                               require_noerr( err, exit );
+                               
+                               subtest->queryTXT = sdRef;
+                       }
+               }
+       }
+       
+       if( !resultIsExpected )
+       {
+               CFMutableArrayRef               resultArray;
+               char                                    timestamp[ 32 ];
+               const char *                    ifNamePtr;
+               char                                    ifNameBuf[ IF_NAMESIZE + 1 ];
+               
+               ifNamePtr = if_indextoname( inIfIndex, ifNameBuf );
+               resultArray = subtest->unexpected;
+       #if( TARGET_OS_WATCH )
+               if( subtest->test->forBATS && ( subtest->ifIndex == kDNSServiceInterfaceIndexAny ) &&
+                       ifNamePtr && _RegistrationTestInterfaceIsWiFi( ifNamePtr ) && serviceIsCorrect )
+               {
+                       resultArray = subtest->ignored;
+               }
+       #endif
+               err = CFPropertyListAppendFormatted( kCFAllocatorDefault, resultArray,
+                       "{"
+                               "%kO=%O"        // resultType
+                               "%kO=%s"        // timestamp
+                               "%kO=%lli"      // flags
+                               "%kO=%lli"      // ifIndex
+                               "%kO=%s"        // ifName
+                               "%kO=%lli"      // error
+                               "%kO=%s"        // serviceName
+                               "%kO=%s"        // serviceType
+                               "%kO=%s"        // domain
+                       "}",
+                       kRegistrationTestReportKey_ResultType,          kRegistrationTestResultType_Browse,
+                       kRegistrationTestReportKey_Timestamp,           _NanoTime64ToTimestamp( now, timestamp, sizeof( timestamp ) ),
+                       kRegistrationTestReportKey_Flags,                       (int64_t) inFlags,
+                       kRegistrationTestReportKey_InterfaceIndex,      (int64_t) inIfIndex,
+                       kRegistrationTestReportKey_InterfaceName,       ifNamePtr,
+                       kRegistrationTestReportKey_Error,                       (int64_t) inError,
+                       kRegistrationTestReportKey_ServiceName,         inServiceName,
+                       kRegistrationTestReportKey_ServiceType,         inServiceType,
+                       kRegistrationTestReportKey_Domain,                      inDomain );
+               require_noerr( err, exit );
+       }
+       err = kNoErr;
+       
+exit:
+       if( err ) _RegistrationTestExit( subtest->test, err );
+}
+
+//===========================================================================================================================
+
+static Boolean
+       _RegistrationSubtestIsSRVRecordDataValid(
+               RegistrationSubtest *   inSubtest,
+               const uint8_t *                 inRDataPtr,
+               size_t                                  inRDataLen,
+               Boolean                                 inExpectRandHostname );
+
+static void DNSSD_API
+       _RegistrationSubtestQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inIfIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                                                err;
+       NanoTime64                                              now;
+       RegistrationSubtest * const             subtest = (RegistrationSubtest *) inContext;
+       Boolean                                                 resultIsExpected;
+       
+       Unused( inSDRef );
+       Unused( inTTL );
+       
+       now = NanoTimeGetCurrent();
+       resultIsExpected = false;
+       if( ( inFlags & kDNSServiceFlagsAdd ) && !inError && ( strcasecmp( inName, subtest->serviceFQDN ) == 0 ) &&
+               ( inClass == kDNSServiceClass_IN ) )
+       {
+               RegistrationResultTimes *               times;
+               Boolean                                                 isAWDL;
+               
+               times = _RegistrationSubtestGetInterfaceResultTimes( subtest, inIfIndex, &isAWDL );
+               if( times )
+               {
+                       if( inType == kDNSServiceType_SRV )
+                       {
+                               Boolean         expectRandHostname;
+                               
+                               if( isAWDL || ( ( subtest->ifIndex == kDNSServiceInterfaceIndexAny ) && subtest->includeAWDL ) )
+                               {
+                                       expectRandHostname = true;
+                               }
+                               else
+                               {
+                                       expectRandHostname = false;
+                               }
+                               if( _RegistrationSubtestIsSRVRecordDataValid( subtest, inRDataPtr, inRDataLen, expectRandHostname ) )
+                               {
+                                       resultIsExpected = true;
+                                       if( !times->querySRVResultTime ) times->querySRVResultTime = now;
+                               }
+                       }
+                       else if( inType == kDNSServiceType_TXT )
+                       {
+                               if( MemEqual( inRDataPtr, inRDataLen, subtest->txtPtr, subtest->txtLen ) )
+                               {
+                                       resultIsExpected = true;
+                                       if( !times->queryTXTResultTime ) times->queryTXTResultTime = now;
+                               }
+                       }
+               }
+       }
+       
+       if( !resultIsExpected )
+       {
+               CFMutableArrayRef                       resultArray;
+               CFMutableDictionaryRef          resultDict;
+               CFStringRef                                     rdataKey;
+               char *                                          rdataStr;
+               const char *                            ifNamePtr;
+               char                                            timestamp[ 32 ];
+               char                                            ifNameBuf[ IF_NAMESIZE + 1 ];
+               
+               ifNamePtr = if_indextoname( inIfIndex, ifNameBuf );
+               resultArray = subtest->unexpected;
+       #if( TARGET_OS_WATCH )
+               if( subtest->test->forBATS && ( subtest->ifIndex == kDNSServiceInterfaceIndexAny ) &&
+                       ifNamePtr && _RegistrationTestInterfaceIsWiFi( ifNamePtr ) && !inError &&
+                       ( strcasecmp( inName, subtest->serviceFQDN ) == 0 ) )
+               {
+                       if( inType == kDNSServiceType_SRV )
+                       {
+                               const Boolean           expectRandHostname = subtest->includeAWDL ? true : false;
+                               
+                               if( _RegistrationSubtestIsSRVRecordDataValid( subtest, inRDataPtr, inRDataLen, expectRandHostname ) )
+                               {
+                                       resultArray = subtest->ignored;
+                               }
+                       }
+                       else if( inType == kDNSServiceType_TXT )
+                       {
+                               if( MemEqual( inRDataPtr, inRDataLen, subtest->txtPtr, subtest->txtLen ) )
+                               {
+                                       resultArray = subtest->ignored;
+                               }
+                       }
+               }
+       #endif
+               err = CFPropertyListCreateFormatted( kCFAllocatorDefault, &resultDict,
+                       "{"
+                               "%kO=%O"        // resultType
+                               "%kO=%s"        // timestamp
+                               "%kO=%lli"      // flags
+                               "%kO=%lli"      // ifIndex
+                               "%kO=%s"        // ifName
+                               "%kO=%lli"      // error
+                               "%kO=%s"        // serviceFQDN
+                               "%kO=%lli"      // recordType
+                               "%kO=%lli"      // class
+                       "}",
+                       kRegistrationTestReportKey_ResultType,          kRegistrationTestResultType_Query,
+                       kRegistrationTestReportKey_Timestamp,           _NanoTime64ToTimestamp( now, timestamp, sizeof( timestamp ) ),
+                       kRegistrationTestReportKey_Flags,                       (int64_t) inFlags,
+                       kRegistrationTestReportKey_InterfaceIndex,      (int64_t) inIfIndex,
+                       kRegistrationTestReportKey_InterfaceName,       ifNamePtr,
+                       kRegistrationTestReportKey_Error,                       (int64_t) inError,
+                       kRegistrationTestReportKey_ServiceFQDN,         inName,
+                       kRegistrationTestReportKey_RecordType,          (int64_t) inType,
+                       kRegistrationTestReportKey_RecordClass,         (int64_t) inClass );
+               require_noerr( err, exit );
+               
+               rdataStr = NULL;
+               DNSRecordDataToString( inRDataPtr, inRDataLen, inType, NULL, 0, &rdataStr );
+               if( rdataStr )
+               {
+                       rdataKey = kRegistrationTestReportKey_RDataFormatted;
+               }
+               else
+               {
+                       ASPrintF( &rdataStr, "%#H", inRDataPtr, inRDataLen, inRDataLen );
+                       require_action( rdataStr, exit, err = kNoMemoryErr );
+                       
+                       rdataKey = kRegistrationTestReportKey_RDataHexString;
+               }
+               err = CFDictionarySetCString( resultDict, rdataKey, rdataStr, kSizeCString );
+               ForgetMem( &rdataStr );
+               if( err ) CFRelease( resultDict );
+               require_noerr( err, exit );
+               
+               CFArrayAppendValue( resultArray, resultDict );
+               CFRelease( resultDict );
+       }
+       err = kNoErr;
+       
+exit:
+       if( err ) _RegistrationTestExit( subtest->test, err );
+}
+
+static Boolean
+       _RegistrationSubtestIsSRVRecordDataValid(
+               RegistrationSubtest *   inSubtest,
+               const uint8_t *                 inRDataPtr,
+               size_t                                  inRDataLen,
+               Boolean                                 inExpectRandHostname )
+{
+       const dns_fixed_fields_srv *            fields;
+       const uint8_t * const                           end             = &inRDataPtr[ inRDataLen ];
+       const uint8_t *                                         label;
+       size_t                                                          len;
+       uint16_t                                                        port;
+       Boolean                                                         isValid;
+       
+       isValid = false;
+       require_quiet( inRDataLen >= sizeof( dns_fixed_fields_srv ), exit );
+       
+       fields  = (const dns_fixed_fields_srv *) inRDataPtr;
+       port    = dns_fixed_fields_srv_get_port( fields );
+       require_quiet( port == inSubtest->port, exit );
+       
+       // First target label should be a UUID string for the AWDL interface.
+       
+       label = (const uint8_t *) &fields[ 1 ];
+       require_quiet( ( end - label ) >= 1, exit );
+       
+       len = label[ 0 ];
+       require_quiet( ( (size_t)( end - label ) ) >= ( 1 + len ), exit );
+       
+       if( inExpectRandHostname )
+       {
+               if( StringToUUID( (const char *) &label[ 1 ], len, false, NULL ) != kNoErr ) goto exit;
+       }
+       else
+       {
+               if( strnicmpx( &label[ 1 ], len, inSubtest->test->localHostName ) != 0 ) goto exit;
+       }
+       
+       // Second target label should be "local".
+       
+       label = &label[ 1 + len ];
+       require_quiet( ( end - label ) >= 1, exit );
+       
+       len = label[ 0 ];
+       require_quiet( ( (size_t)( end - label ) ) >= ( 1 + len ), exit );
+       
+       if( ( len != kLocalLabel[ 0 ] ) || ( _memicmp( &label[ 1 ], &kLocalLabel[ 1 ], kLocalLabel[ 0 ] ) != 0 ) ) goto exit;
+       
+       // Third target label should be the root label.
+       
+       label = &label[ 1 + len ];
+       require_quiet( ( end - label ) >= 1, exit );
+       
+       len = label[ 0 ];
+       if( len != 0 ) goto exit;
+       
+       isValid = true;
+       
+exit:
+       return( isValid );
+}
+
+//===========================================================================================================================
+
+static Boolean _RegistrationSubtestValidServiceType( const RegistrationSubtest *inSubtest, const char *inServiceType )
+{
+       if( stricmp_prefix( inServiceType, inSubtest->serviceType ) == 0 )
+       {
+               const char * const              ptr = &inServiceType[ inSubtest->serviceTypeLen ];
+               
+               if( ( ptr[ 0 ] == '\0' ) || ( ( ptr[ 0 ] == '.' ) && ( ptr[ 1 ] == '\0' ) ) ) return( true );
+       }
+       return( false );
+}
+
+//===========================================================================================================================
+
+static RegistrationResultTimes *
+       _RegistrationSubtestGetInterfaceResultTimes(
+               RegistrationSubtest *   inSubtest,
+               uint32_t                                inIfIndex,
+               Boolean *                               outIsAWDL )
+{
+       if( inSubtest->ifList )
+       {
+               RegistrationInterfaceItem *             item;
+               
+               for( item = inSubtest->ifList; item; item = (RegistrationInterfaceItem *) item->base.next )
+               {
+                       if( inIfIndex == item->base.ifIndex )
+                       {
+                               if( outIsAWDL ) *outIsAWDL = item->base.isAWDL ? true : false;
+                               return( &item->times );
+                       }
+               }
+       }
+       else
+       {
+               if( inIfIndex == inSubtest->ifIndex )
+               {
+                       if( outIsAWDL ) *outIsAWDL = inSubtest->ifIsAWDL ? true : false;
+                       return( &inSubtest->ifTimes );
+               }
+       }
+       return( NULL );
+}
+
+//===========================================================================================================================
+
+static void    _RegistrationTestTimerHandler( void *inContext )
+{
+       RegistrationTest * const                test = (RegistrationTest *) inContext;
+       
+       dispatch_source_forget( &test->timer );
+       _RegistrationTestProceed( test );
+}
+
+//===========================================================================================================================
+
+#if( TARGET_OS_WATCH )
+static Boolean _RegistrationTestInterfaceIsWiFi( const char *inIfName )
+{
+       NetTransportType                type = kNetTransportType_Undefined;
+       
+       SocketGetInterfaceInfo( kInvalidSocketRef, inIfName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &type );
+       return( ( type == kNetTransportType_WiFi ) ? true : false );
+}
+#endif
+
+//===========================================================================================================================
+//     SSDPDiscoverCmd
+//===========================================================================================================================
+
+#define kSSDPPort              1900
+
+typedef struct
+{
+       HTTPHeader                              header;                 // HTTP header object for sending and receiving.
+       dispatch_source_t               readSourceV4;   // Read dispatch source for IPv4 socket.
+       dispatch_source_t               readSourceV6;   // Read dispatch source for IPv6 socket.
+       int                                             receiveSecs;    // After send, the amount of time to spend receiving.
+       uint32_t                                ifindex;                // Index of the interface over which to send the query.
+       Boolean                                 useIPv4;                // True if the query should be sent via IPv4 multicast.
+       Boolean                                 useIPv6;                // True if the query should be sent via IPv6 multicast.
+       
+}      SSDPDiscoverContext;
+
+static void            SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext );
+static void            SSDPDiscoverReadHandler( void *inContext );
+static int             SocketToPortNumber( SocketRef inSock );
+static OSStatus        WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST );
+
+static void    SSDPDiscoverCmd( void )
+{
+       OSStatus                                        err;
+       struct timeval                          now;
+       SSDPDiscoverContext *           context;
+       dispatch_source_t                       signalSource    = NULL;
+       SocketRef                                       sockV4                  = kInvalidSocketRef;
+       SocketRef                                       sockV6                  = kInvalidSocketRef;
+       ssize_t                                         n;
+       int                                                     sendCount;
+       
+       // Set up SIGINT handler.
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, Exit, kExitReason_SIGINT, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       // Check command parameters.
+       
+       if( gSSDPDiscover_ReceiveSecs < -1 )
+       {
+               FPrintF( stdout, "Invalid receive time: %d seconds.\n", gSSDPDiscover_ReceiveSecs );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       // Create context.
+       
+       context = (SSDPDiscoverContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->receiveSecs    = gSSDPDiscover_ReceiveSecs;
+       context->useIPv4                = ( gSSDPDiscover_UseIPv4 || !gSSDPDiscover_UseIPv6 ) ? true : false;
+       context->useIPv6                = ( gSSDPDiscover_UseIPv6 || !gSSDPDiscover_UseIPv4 ) ? true : false;
+       
+       err = InterfaceIndexFromArgString( gInterface, &context->ifindex );
+       require_noerr_quiet( err, exit );
+       
+       // Set up IPv4 socket.
+       
+       if( context->useIPv4 )
+       {
+               int port;
+               err = UDPClientSocketOpen( AF_INET, NULL, 0, -1, &port, &sockV4 );
+               require_noerr( err, exit );
+               
+               err = SocketSetMulticastInterface( sockV4, NULL, context->ifindex );
+               require_noerr( err, exit );
+               
+               err = setsockopt( sockV4, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
+               err = map_socket_noerr_errno( sockV4, err );
+               require_noerr( err, exit );
+       }
+       
+       // Set up IPv6 socket.
+       
+       if( context->useIPv6 )
+       {
+               err = UDPClientSocketOpen( AF_INET6, NULL, 0, -1, NULL, &sockV6 );
+               require_noerr( err, exit );
+               
+               err = SocketSetMulticastInterface( sockV6, NULL, context->ifindex );
+               require_noerr( err, exit );
+               
+               err = setsockopt( sockV6, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
+               err = map_socket_noerr_errno( sockV6, err );
+               require_noerr( err, exit );
+       }
+       
+       // Print prologue.
+       
+       SSDPDiscoverPrintPrologue( context );
+       
+       // Send mDNS query message.
+       
+       sendCount = 0;
+       if( IsValidSocket( sockV4 ) )
+       {
+               struct sockaddr_in              mcastAddr4;
+               
+               memset( &mcastAddr4, 0, sizeof( mcastAddr4 ) );
+               SIN_LEN_SET( &mcastAddr4 );
+               mcastAddr4.sin_family           = AF_INET;
+               mcastAddr4.sin_port                     = htons( kSSDPPort );
+               mcastAddr4.sin_addr.s_addr      = htonl( 0xEFFFFFFA );  // 239.255.255.250
+               
+               err = WriteSSDPSearchRequest( &context->header, &mcastAddr4, gSSDPDiscover_MX, gSSDPDiscover_ST );
+               require_noerr( err, exit );
+               
+               n = sendto( sockV4, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr4,
+                       (socklen_t) sizeof( mcastAddr4 ) );
+               err = map_socket_value_errno( sockV4, n == (ssize_t) context->header.len, n );
+               if( err )
+               {
+                       FPrintF( stderr, "*** Failed to send query on IPv4 socket with error %#m\n", err );
+                       ForgetSocket( &sockV4 );
+               }
+               else
+               {
+                       if( gSSDPDiscover_Verbose )
+                       {
+                               gettimeofday( &now, NULL );
+                               FPrintF( stdout, "---\n" );
+                               FPrintF( stdout, "Send time:    %{du:time}\n",  &now );
+                               FPrintF( stdout, "Source Port:  %d\n",                  SocketToPortNumber( sockV4 ) );
+                               FPrintF( stdout, "Destination:  %##a\n",                &mcastAddr4 );
+                               FPrintF( stdout, "Message size: %zu\n",                 context->header.len );
+                               FPrintF( stdout, "HTTP header:\n%1{text}",              context->header.buf, context->header.len );
+                       }
+                       ++sendCount;
+               }
+       }
+       
+       if( IsValidSocket( sockV6 ) )
+       {
+               struct sockaddr_in6             mcastAddr6;
+               
+               memset( &mcastAddr6, 0, sizeof( mcastAddr6 ) );
+               SIN6_LEN_SET( &mcastAddr6 );
+               mcastAddr6.sin6_family                          = AF_INET6;
+               mcastAddr6.sin6_port                            = htons( kSSDPPort );
+               mcastAddr6.sin6_addr.s6_addr[  0 ]      = 0xFF; // SSDP IPv6 link-local multicast address FF02::C
+               mcastAddr6.sin6_addr.s6_addr[  1 ]      = 0x02;
+               mcastAddr6.sin6_addr.s6_addr[ 15 ]      = 0x0C;
+               
+               err = WriteSSDPSearchRequest( &context->header, &mcastAddr6, gSSDPDiscover_MX, gSSDPDiscover_ST );
+               require_noerr( err, exit );
+               
+               n = sendto( sockV6, context->header.buf, context->header.len, 0, (const struct sockaddr *) &mcastAddr6,
+                       (socklen_t) sizeof( mcastAddr6 ) );
+               err = map_socket_value_errno( sockV6, n == (ssize_t) context->header.len, n );
+               if( err )
+               {
+                       FPrintF( stderr, "*** Failed to send query on IPv6 socket with error %#m\n", err );
+                       ForgetSocket( &sockV6 );
+               }
+               else
+               {
+                       if( gSSDPDiscover_Verbose )
+                       {
+                               gettimeofday( &now, NULL );
+                               FPrintF( stdout, "---\n" );
+                               FPrintF( stdout, "Send time:    %{du:time}\n",  &now );
+                               FPrintF( stdout, "Source Port:  %d\n",                  SocketToPortNumber( sockV6 ) );
+                               FPrintF( stdout, "Destination:  %##a\n",                &mcastAddr6 );
+                               FPrintF( stdout, "Message size: %zu\n",                 context->header.len );
+                               FPrintF( stdout, "HTTP header:\n%1{text}",              context->header.buf, context->header.len );
+                       }
+                       ++sendCount;
+               }
+       }
+       require_action_quiet( sendCount > 0, exit, err = kUnexpectedErr );
+       
+       // If there's no wait period after the send, then exit.
+       
+       if( context->receiveSecs == 0 ) goto exit;
+       
+       // Create dispatch read sources for socket(s).
+       
+       if( IsValidSocket( sockV4 ) )
+       {
+               SocketContext *         sockCtx;
+               
+               err = SocketContextCreate( sockV4, context, &sockCtx );
+               require_noerr( err, exit );
+               sockV4 = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
+                       &context->readSourceV4 );
+               if( err ) ForgetSocketContext( &sockCtx );
+               require_noerr( err, exit );
+               
+               dispatch_resume( context->readSourceV4 );
+       }
+       
+       if( IsValidSocket( sockV6 ) )
+       {
+               SocketContext *         sockCtx;
+               
+               err = SocketContextCreate( sockV6, context, &sockCtx );
+               require_noerr( err, exit );
+               sockV6 = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, NULL, SSDPDiscoverReadHandler, SocketContextCancelHandler, sockCtx,
+                       &context->readSourceV6 );
+               if( err ) ForgetSocketContext( &sockCtx );
+               require_noerr( err, exit );
+               
+               dispatch_resume( context->readSourceV6 );
+       }
+       
+       if( context->receiveSecs > 0 )
+       {
+               dispatch_after_f( dispatch_time_seconds( context->receiveSecs ), dispatch_get_main_queue(), kExitReason_Timeout,
+                       Exit );
+       }
+       dispatch_main();
+       
+exit:
+       ForgetSocket( &sockV4 );
+       ForgetSocket( &sockV6 );
+       dispatch_source_forget( &signalSource );
+       exit( err ? 1 : 0 );
+}
+
+static int     SocketToPortNumber( SocketRef inSock )
+{
+       OSStatus                err;
+       sockaddr_ip             sip;
+       socklen_t               len;
+       
+       len = (socklen_t) sizeof( sip );
+       err = getsockname( inSock, &sip.sa, &len );
+       err = map_socket_noerr_errno( inSock, err );
+       check_noerr( err );
+       return( err ? -1 : SockAddrGetPort( &sip ) );
+}
+
+static OSStatus        WriteSSDPSearchRequest( HTTPHeader *inHeader, const void *inHostSA, int inMX, const char *inST )
+{
+       OSStatus                err;
+       
+       err = HTTPHeader_InitRequest( inHeader, "M-SEARCH", "*", "HTTP/1.1" );
+       require_noerr( err, exit );
+       
+       err = HTTPHeader_SetField( inHeader, "Host", "%##a", inHostSA );
+       require_noerr( err, exit );
+       
+       err = HTTPHeader_SetField( inHeader, "ST", "%s", inST ? inST : "ssdp:all" );
+       require_noerr( err, exit );
+       
+       err = HTTPHeader_SetField( inHeader, "Man", "\"ssdp:discover\"" );
+       require_noerr( err, exit );
+       
+       err = HTTPHeader_SetField( inHeader, "MX", "%d", inMX );
+       require_noerr( err, exit );
+       
+       err = HTTPHeader_Commit( inHeader );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     SSDPDiscoverPrintPrologue
+//===========================================================================================================================
+
+static void    SSDPDiscoverPrintPrologue( const SSDPDiscoverContext *inContext )
+{
+       const int                               receiveSecs = inContext->receiveSecs;
+       const char *                    ifName;
+       char                                    ifNameBuf[ IF_NAMESIZE + 1 ];
+       NetTransportType                ifType;
+       
+       ifName = if_indextoname( inContext->ifindex, ifNameBuf );
+       
+       ifType = kNetTransportType_Undefined;
+       if( ifName ) SocketGetInterfaceInfo( kInvalidSocketRef, ifName, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &ifType );
+       
+       FPrintF( stdout, "Interface:        %s/%d/%s\n",
+               ifName ? ifName : "?", inContext->ifindex, NetTransportTypeToString( ifType ) );
+       FPrintF( stdout, "IP protocols:     %?s%?s%?s\n",
+               inContext->useIPv4, "IPv4", ( inContext->useIPv4 && inContext->useIPv6 ), ", ", inContext->useIPv6, "IPv6" );
+       FPrintF( stdout, "Receive duration: " );
+       if( receiveSecs >= 0 )  FPrintF( stdout, "%d second%?c\n", receiveSecs, receiveSecs != 1, 's' );
+       else                                    FPrintF( stdout, "∞\n" );
+       FPrintF( stdout, "Start time:       %{du:time}\n", NULL );
+}
+
+//===========================================================================================================================
+//     SSDPDiscoverReadHandler
+//===========================================================================================================================
+
+static Boolean _HTTPHeader_Validate( HTTPHeader *inHeader );
+
+static void    SSDPDiscoverReadHandler( void *inContext )
+{
+       OSStatus                                                err;
+       struct timeval                                  now;
+       SocketContext * const                   sockCtx = (SocketContext *) inContext;
+       SSDPDiscoverContext * const             context = (SSDPDiscoverContext *) sockCtx->userContext;
+       HTTPHeader * const                              header  = &context->header;
+       sockaddr_ip                                             fromAddr;
+       size_t                                                  msgLen;
+       
+       gettimeofday( &now, NULL );
+       
+       err = SocketRecvFrom( sockCtx->sock, header->buf, sizeof( header->buf ), &msgLen, &fromAddr, sizeof( fromAddr ),
+               NULL, NULL, NULL, NULL );
+       require_noerr( err, exit );
+       
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "Receive time: %{du:time}\n",  &now );
+       FPrintF( stdout, "Source:       %##a\n",                &fromAddr );
+       FPrintF( stdout, "Message size: %zu\n",                 msgLen );
+       header->len = msgLen;
+       if( _HTTPHeader_Validate( header ) )
+       {
+               FPrintF( stdout, "HTTP header:\n%1{text}", header->buf, header->len );
+               if( header->extraDataLen > 0 )
+               {
+                       FPrintF( stdout, "HTTP body: %1.1H", header->extraDataPtr, (int) header->extraDataLen, INT_MAX );
+               }
+       }
+       else
+       {
+               FPrintF( stdout, "Invalid HTTP message:\n%1.1H", header->buf, (int) msgLen, INT_MAX );
+               goto exit;
+       }
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     _HTTPHeader_Validate
+//
+//     Parses for the end of an HTTP header and updates the HTTPHeader structure so it's ready to parse. Returns true if valid.
+//     This assumes the "buf" and "len" fields are set. The other fields are set by this function.
+//
+//     Note: This was copied from CoreUtils because the HTTPHeader_Validate function is currently not exported in the framework.
+//===========================================================================================================================
+
+static Boolean _HTTPHeader_Validate( HTTPHeader *inHeader )
+{
+       const char *            src;
+       const char *            end;
+       
+       // Check for interleaved binary data (4 byte header that begins with $). See RFC 2326 section 10.12.
+       
+       require( inHeader->len < sizeof( inHeader->buf ), exit );
+       src = inHeader->buf;
+       end = src + inHeader->len;
+       if( ( ( end - src ) >= 4 ) && ( src[ 0 ] == '$' ) )
+       {
+               src += 4;
+       }
+       else
+       {
+               // Search for an empty line (HTTP-style header/body separator). CRLFCRLF, LFCRLF, or LFLF accepted.
+               // $$$ TO DO: Start from the last search location to avoid re-searching the same data over and over.
+               
+               for( ;; )
+               {
+                       while( ( src < end ) && ( src[ 0 ] != '\n' ) ) ++src;
+                       if( src >= end ) goto exit;
+                       ++src;
+                       if( ( ( end - src ) >= 2 ) && ( src[ 0 ] == '\r' ) && ( src[ 1 ] == '\n' ) ) // CFLFCRLF or LFCRLF
+                       {
+                               src += 2;
+                               break;
+                       }
+                       else if( ( ( end - src ) >= 1 ) && ( src[ 0 ] == '\n' ) ) // LFLF
+                       {
+                               src += 1;
+                               break;
+                       }
+               }
+       }
+       inHeader->extraDataPtr  = src;
+       inHeader->extraDataLen  = (size_t)( end - src );
+       inHeader->len                   = (size_t)( src - inHeader->buf );
+       return( true );
+       
+exit:
+       return( false );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+//     ResQueryCmd
+//===========================================================================================================================
+
+// res_query() from libresolv is actually called res_9_query (see /usr/include/resolv.h).
+
+SOFT_LINK_LIBRARY_EX( "/usr/lib", resolv );
+SOFT_LINK_FUNCTION_EX( resolv, res_9_query,
+       int,
+       ( const char *dname, int class, int type, u_char *answer, int anslen ),
+       ( dname, class, type, answer, anslen ) );
+
+// res_query() from libinfo
+
+SOFT_LINK_LIBRARY_EX( "/usr/lib", info );
+SOFT_LINK_FUNCTION_EX( info, res_query,
+       int,
+       ( const char *dname, int class, int type, u_char *answer, int anslen ),
+       ( dname, class, type, answer, anslen ) );
+
+typedef int ( *res_query_f )( const char *dname, int class, int type, u_char *answer, int anslen );
+
+static void    ResQueryCmd( void )
+{
+       OSStatus                err;
+       res_query_f             res_query_ptr;
+       int                             n;
+       uint16_t                type, class;
+       uint8_t                 answer[ 1024 ];
+       
+       // Get pointer to one of the res_query() functions.
+       
+       if( gResQuery_UseLibInfo )
+       {
+               if( !SOFT_LINK_HAS_FUNCTION( info, res_query ) )
+               {
+                       FPrintF( stderr, "Failed to soft link res_query from libinfo.\n" );
+                       err = kNotFoundErr;
+                       goto exit;
+               }
+               res_query_ptr = soft_res_query;
+       }
+       else
+       {
+               if( !SOFT_LINK_HAS_FUNCTION( resolv, res_9_query ) )
+               {
+                       FPrintF( stderr, "Failed to soft link res_query from libresolv.\n" );
+                       err = kNotFoundErr;
+                       goto exit;
+               }
+               res_query_ptr = soft_res_9_query;
+       }
+       
+       // Get record type.
+       
+       err = RecordTypeFromArgString( gResQuery_Type, &type );
+       require_noerr( err, exit );
+       
+       // Get record class.
+       
+       if( gResQuery_Class )
+       {
+               err = RecordClassFromArgString( gResQuery_Class, &class );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               class = kDNSServiceClass_IN;
+       }
+       
+       // Print prologue.
+       
+       FPrintF( stdout, "Name:       %s\n",                    gResQuery_Name );
+       FPrintF( stdout, "Type:       %s (%u)\n",               RecordTypeToString( type ), type );
+       FPrintF( stdout, "Class:      %s (%u)\n",               ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
+       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
+       FPrintF( stdout, "---\n" );
+       
+       // Call res_query().
+       
+       n = res_query_ptr( gResQuery_Name, class, type, (u_char *) answer, (int) sizeof( answer ) );
+       if( n < 0 )
+       {
+               FPrintF( stderr, "res_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
+               err = kUnknownErr;
+               goto exit;
+       }
+       
+       // Print result.
+       
+       FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     ResolvDNSQueryCmd
+//===========================================================================================================================
+
+// dns_handle_t is defined as a pointer to a privately-defined struct in /usr/include/dns.h. It's defined as a void * here to
+// avoid including the header file.
+
+typedef void *         dns_handle_t;
+
+SOFT_LINK_FUNCTION_EX( resolv, dns_open, dns_handle_t, ( const char *path ), ( path ) );
+SOFT_LINK_FUNCTION_VOID_RETURN_EX( resolv, dns_free, ( dns_handle_t *dns ), ( dns ) );
+SOFT_LINK_FUNCTION_EX( resolv, dns_query,
+       int32_t, (
+               dns_handle_t            dns,
+               const char *            name,
+               uint32_t                        dnsclass,
+               uint32_t                        dnstype,
+               char *                          buf,
+               uint32_t                        len,
+               struct sockaddr *       from,
+               uint32_t *                      fromlen ),
+       ( dns, name, dnsclass, dnstype, buf, len, from, fromlen ) );
+
+static void    ResolvDNSQueryCmd( void )
+{
+       OSStatus                        err;
+       int                                     n;
+       dns_handle_t            dns = NULL;
+       uint16_t                        type, class;
+       sockaddr_ip                     from;
+       uint32_t                        fromLen;
+       uint8_t                         answer[ 1024 ];
+       
+       // Make sure that the required symbols are available.
+       
+       if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_open ) )
+       {
+               FPrintF( stderr, "Failed to soft link dns_open from libresolv.\n" );
+               err = kNotFoundErr;
+               goto exit;
+       }
+       
+       if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_free ) )
+       {
+               FPrintF( stderr, "Failed to soft link dns_free from libresolv.\n" );
+               err = kNotFoundErr;
+               goto exit;
+       }
+       
+       if( !SOFT_LINK_HAS_FUNCTION( resolv, dns_query ) )
+       {
+               FPrintF( stderr, "Failed to soft link dns_query from libresolv.\n" );
+               err = kNotFoundErr;
+               goto exit;
+       }
+       
+       // Get record type.
+       
+       err = RecordTypeFromArgString( gResolvDNSQuery_Type, &type );
+       require_noerr( err, exit );
+       
+       // Get record class.
+       
+       if( gResolvDNSQuery_Class )
+       {
+               err = RecordClassFromArgString( gResolvDNSQuery_Class, &class );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               class = kDNSServiceClass_IN;
+       }
+       
+       // Get dns handle.
+       
+       dns = soft_dns_open( gResolvDNSQuery_Path );
+       if( !dns )
+       {
+               FPrintF( stderr, "dns_open( %s ) failed.\n", gResolvDNSQuery_Path );
+               err = kUnknownErr;
+               goto exit;
+       }
+       
+       // Print prologue.
+       
+       FPrintF( stdout, "Name:       %s\n",                    gResolvDNSQuery_Name );
+       FPrintF( stdout, "Type:       %s (%u)\n",               RecordTypeToString( type ), type );
+       FPrintF( stdout, "Class:      %s (%u)\n",               ( class == kDNSServiceClass_IN ) ? "IN" : "???", class );
+       FPrintF( stdout, "Path:       %s\n",                    gResolvDNSQuery_Path ? gResolvDNSQuery_Name : "<NULL>" );
+       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
+       FPrintF( stdout, "---\n" );
+       
+       // Call dns_query().
+       
+       memset( &from, 0, sizeof( from ) );
+       fromLen = (uint32_t) sizeof( from );
+       n = soft_dns_query( dns, gResolvDNSQuery_Name, class, type, (char *) answer, (uint32_t) sizeof( answer ), &from.sa,
+               &fromLen );
+       if( n < 0 )
+       {
+               FPrintF( stderr, "dns_query() failed with error: %d (%s).\n", h_errno, hstrerror( h_errno ) );
+               err = kUnknownErr;
+               goto exit;
+       }
+       
+       // Print result.
+       
+       FPrintF( stdout, "From:         %##a\n", &from );
+       FPrintF( stdout, "Message size: %d\n\n%{du:dnsmsg}", n, answer, (size_t) n );
+       
+exit:
+       if( dns ) soft_dns_free( dns );
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     CFHostCmd
+//===========================================================================================================================
+
+static void
+       _CFHostResolveCallback(
+               CFHostRef                               inHost,
+               CFHostInfoType                  inInfoType,
+               const CFStreamError *   inError,
+               void *                                  inInfo );
+
+static void    CFHostCmd( void )
+{
+       OSStatus                                err;
+       CFStringRef                             name;
+       Boolean                                 success;
+       CFHostRef                               host = NULL;
+       CFHostClientContext             context;
+       CFStreamError                   streamErr;
+       
+       name = CFStringCreateWithCString( kCFAllocatorDefault, gCFHost_Name, kCFStringEncodingUTF8 );
+       require_action( name, exit, err = kUnknownErr );
+       
+       host = CFHostCreateWithName( kCFAllocatorDefault, name );
+       ForgetCF( &name );
+       require_action( host, exit, err = kUnknownErr );
+       
+       memset( &context, 0, sizeof( context ) );
+       success = CFHostSetClient( host, _CFHostResolveCallback, &context );
+       require_action( success, exit, err = kUnknownErr );
+       
+       CFHostScheduleWithRunLoop( host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode );
+       
+       // Print prologue.
+       
+       FPrintF( stdout, "Hostname:   %s\n",                    gCFHost_Name );
+       FPrintF( stdout, "Start time: %{du:time}\n",    NULL );
+       FPrintF( stdout, "---\n" );
+       
+       success = CFHostStartInfoResolution( host, kCFHostAddresses, &streamErr );
+       require_action( success, exit, err = kUnknownErr );
+       err = kNoErr;
+       
+       CFRunLoopRun();
+       
+exit:
+       CFReleaseNullSafe( host );
+       if( err ) exit( 1 );
+}
+
+static void    _CFHostResolveCallback( CFHostRef inHost, CFHostInfoType inInfoType, const CFStreamError *inError, void *inInfo )
+{
+       OSStatus                        err;
+       struct timeval          now;
+       
+       gettimeofday( &now, NULL );
+       
+       Unused( inInfoType );
+       Unused( inInfo );
+       
+       if( inError && ( inError->domain != 0 ) && ( inError->error ) )
+       {
+               err = inError->error;
+               if( inError->domain == kCFStreamErrorDomainNetDB )
+               {
+                       FPrintF( stderr, "Error %d: %s.\n", err, gai_strerror( err ) );
+               }
+               else
+               {
+                       FPrintF( stderr, "Error %#m\n", err );
+               }
+       }
+       else
+       {
+               CFArrayRef                                      addresses;
+               CFIndex                                         count, i;
+               CFDataRef                                       addrData;
+               const struct sockaddr *         sockAddr;
+               Boolean                                         wasResolved = false;
+               
+               addresses = CFHostGetAddressing( inHost, &wasResolved );
+               check( wasResolved );
+               
+               if( addresses )
+               {
+                       count = CFArrayGetCount( addresses );
+                       for( i = 0; i < count; ++i )
+                       {
+                               addrData = CFArrayGetCFDataAtIndex( addresses, i, &err );
+                               require_noerr( err, exit );
+                               
+                               sockAddr = (const struct sockaddr *) CFDataGetBytePtr( addrData );
+                               FPrintF( stdout, "%##a\n", sockAddr );
+                       }
+               }
+               err = kNoErr;
+       }
+       
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "End time:   %{du:time}\n", &now );
+       
+       if( gCFHost_WaitSecs > 0 ) sleep( (unsigned int) gCFHost_WaitSecs );
+       
+exit:
+       exit( err ? 1 : 0 );
+}
+
+//===========================================================================================================================
+//     DNSConfigAddCmd
+//
+//     Note: Based on ajn's supplemental test tool.
+//===========================================================================================================================
+
+static void    DNSConfigAddCmd( void )
+{
+       OSStatus                                        err;
+       CFMutableDictionaryRef          dict    = NULL;
+       CFMutableArrayRef                       array   = NULL;
+       size_t                                          i;
+       SCDynamicStoreRef                       store   = NULL;
+       CFStringRef                                     key             = NULL;
+       Boolean                                         success;
+       
+       // Create dictionary.
+       
+       dict = CFDictionaryCreateMutable( NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
+       require_action( dict, exit, err = kNoMemoryErr );
+       
+       // Add DNS server IP addresses.
+       
+       array = CFArrayCreateMutable( NULL, (CFIndex) gDNSConfigAdd_IPAddrCount, &kCFTypeArrayCallBacks );
+       require_action( array, exit, err = kNoMemoryErr );
+       
+       for( i = 0; i < gDNSConfigAdd_IPAddrCount; ++i )
+       {
+               CFStringRef             addrStr;
+               
+               addrStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_IPAddrArray[ i ], kCFStringEncodingUTF8 );
+               require_action( addrStr, exit, err = kUnknownErr );
+               
+               CFArrayAppendValue( array, addrStr );
+               CFRelease( addrStr );
+       }
+       
+       CFDictionarySetValue( dict, kSCPropNetDNSServerAddresses, array );
+       ForgetCF( &array );
+       
+       // Add domains, if any.
+       
+       array = CFArrayCreateMutable( NULL, (CFIndex) Min( gDNSConfigAdd_DomainCount, 1 ), &kCFTypeArrayCallBacks );
+       require_action( array, exit, err = kNoMemoryErr );
+       
+       if( gDNSConfigAdd_DomainCount > 0 )
+       {
+               for( i = 0; i < gDNSConfigAdd_DomainCount; ++i )
+               {
+                       CFStringRef             domainStr;
+                       
+                       domainStr = CFStringCreateWithCString( NULL, gDNSConfigAdd_DomainArray[ i ], kCFStringEncodingUTF8 );
+                       require_action( domainStr, exit, err = kUnknownErr );
+                       
+                       CFArrayAppendValue( array, domainStr );
+                       CFRelease( domainStr );
+               }
+       }
+       else
+       {
+               // There are no domains, but the domain array needs to be non-empty, so add a zero-length string to the array.
+               
+               CFArrayAppendValue( array, CFSTR( "" ) );
+       }
+       
+       CFDictionarySetValue( dict, kSCPropNetDNSSupplementalMatchDomains, array );
+       ForgetCF( &array );
+       
+       // Add interface, if any.
+       
+       if( gDNSConfigAdd_Interface )
+       {
+               err = CFDictionarySetCString( dict, kSCPropInterfaceName, gDNSConfigAdd_Interface, kSizeCString );
+               require_noerr( err, exit );
+               
+               CFDictionarySetValue( dict, kSCPropNetDNSConfirmedServiceID, gDNSConfigAdd_ID );
+       }
+       
+       // Set dictionary in dynamic store.
+       
+       store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+       err = map_scerror( store );
+       require_noerr( err, exit );
+       
+       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigAdd_ID, kSCEntNetDNS );
+       require_action( key, exit, err = kUnknownErr );
+       
+       success = SCDynamicStoreSetValue( store, key, dict );
+       require_action( success, exit, err = kUnknownErr );
+       
+exit:
+       CFReleaseNullSafe( dict );
+       CFReleaseNullSafe( array );
+       CFReleaseNullSafe( store );
+       CFReleaseNullSafe( key );
+       gExitCode = err ? 1 : 0;
+}
+
+//===========================================================================================================================
+//     DNSConfigRemoveCmd
+//===========================================================================================================================
+
+static void    DNSConfigRemoveCmd( void )
+{
+       OSStatus                                err;
+       SCDynamicStoreRef               store   = NULL;
+       CFStringRef                             key             = NULL;
+       Boolean                                 success;
+       
+       store = SCDynamicStoreCreate( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+       err = map_scerror( store );
+       require_noerr( err, exit );
+       
+       key = SCDynamicStoreKeyCreateNetworkServiceEntity( NULL, kSCDynamicStoreDomainState, gDNSConfigRemove_ID, kSCEntNetDNS );
+       require_action( key, exit, err = kUnknownErr );
+       
+       success = SCDynamicStoreRemoveValue( store, key );
+       require_action( success, exit, err = kUnknownErr );
+       
+exit:
+       CFReleaseNullSafe( store );
+       CFReleaseNullSafe( key );
+       gExitCode = err ? 1 : 0;
+}
+
+//===========================================================================================================================
+//     XPCSendCmd
+//===========================================================================================================================
+
+static OSStatus        _XPCDictionaryCreateFromString( const char *inString, xpc_object_t *outDict );
+
+static void    XPCSendCmd( void )
+{
+       OSStatus                        err;
+       xpc_object_t            msg, reply;
+       
+       err = _XPCDictionaryCreateFromString( gXPCSend_MessageStr, &msg );
+       require_noerr_quiet( err, exit );
+       
+       FPrintF( stdout, "Service:    %s\n", gXPCSend_ServiceName );
+       FPrintF( stdout, "Message:    %s\n", gXPCSend_MessageStr );
+       FPrintF( stdout, "Start time: %{du:time}\n", NULL );
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "XPC Message:\n%{xpc}\n", msg );
+       
+       err = xpc_send_message_sync( gXPCSend_ServiceName, 0, 0, msg, &reply );
+       xpc_forget( &msg );
+       require_noerr_quiet( err, exit );
+       
+       FPrintF( stdout, "XPC Reply:\n%{xpc}\n", reply );
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "End time:   %{du:time}\n", NULL );
+       xpc_forget( &reply );
+       
+exit:
+       if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+//===========================================================================================================================
+//     _XPCDictionaryCreateFromString
+//===========================================================================================================================
+
+#define kXPCObjectPrefix_Bool          "bool:"
+#define kXPCObjectPrefix_Data          "data:"
+#define kXPCObjectPrefix_Int64         "int:"
+#define kXPCObjectPrefix_String                "string:"
+#define kXPCObjectPrefix_UInt64                "uint:"
+#define kXPCObjectPrefix_UUID          "uuid:"
+
+typedef struct XPCListItem             XPCListItem;
+struct XPCListItem
+{
+       XPCListItem *           next;
+       xpc_object_t            obj;
+       char *                          key;
+};
+
+static OSStatus        _XPCListItemCreate( xpc_object_t inObject, const char *inKey, XPCListItem **outItem );
+static void            _XPCListItemFree( XPCListItem *inItem );
+static void            _XPCListFree( XPCListItem *inList );
+
+static OSStatus        _XPCObjectFromString( const char *inString, xpc_object_t *outObject );
+
+static OSStatus        _XPCDictionaryCreateFromString( const char *inString, xpc_object_t *outDict )
+{
+       OSStatus                                err;
+       xpc_object_t                    container;
+       const char *                    ptr             = inString;
+       const char * const              end             = inString + strlen( inString );
+       XPCListItem *                   list    = NULL;
+       
+       container = xpc_dictionary_create( NULL, NULL, 0 );
+       require_action( container, exit, err = kNoMemoryErr );
+       
+       while( *ptr )
+       {
+               xpc_type_t                              containerType;
+               xpc_object_t                    value;
+               int                                             c;
+               char                                    keyStr[ 256 ];
+               char                                    valStr[ 256 ];
+               
+               // At this point, zero or more of the current container's elements have been parsed.
+               // Skip the white space leading up to the container's next element, if any, or the container's end.
+               
+               while( isspace_safe( *ptr ) ) ++ptr;
+               
+               // Check if we're done with the current container.
+               
+               c = *ptr;
+               if( c == '\0' ) break;
+               
+               containerType = xpc_get_type( container );
+               if( ( ( containerType == XPC_TYPE_DICTIONARY ) && ( c == '}' ) ) ||
+                       ( ( containerType == XPC_TYPE_ARRAY )      && ( c == ']' ) ) )
+               {
+                       XPCListItem *           item;
+                       
+                       item = list;
+                       require_action_quiet( item, exit, err = kMalformedErr );
+                       
+                       ++ptr;
+                       
+                       // Add the current container to its parent container.
+                       
+                       if( item->key )
+                       {
+                               xpc_dictionary_set_value( item->obj, item->key, container );
+                       }
+                       else
+                       {
+                               xpc_array_append_value( item->obj, container );
+                       }
+                       
+                       // Continue with the parent container.
+                       
+                       xpc_release( container );
+                       container = xpc_retain( item->obj );
+                       list = item->next;
+                       _XPCListItemFree( item );
+                       continue;
+               }
+               
+               // If the current container is a dictionary, parse the key string.
+               
+               if( containerType == XPC_TYPE_DICTIONARY )
+               {
+                       err = _ParseEscapedString( ptr, end, "={}[]" kWhiteSpaceCharSet, keyStr, sizeof( keyStr ), NULL, NULL, &ptr );
+                       require_noerr_quiet( err, exit );
+                       
+                       c = *ptr;
+                       require_action_quiet( c == '=', exit, err = kMalformedErr );
+                       ++ptr;
+               }
+               
+               // Check if the value is a dictionary ({...}) or an array ([...]).
+               
+               c = *ptr;
+               if( ( c == '{' ) || ( c == '[' ) )
+               {
+                       XPCListItem *           item;
+                       
+                       ++ptr;
+                       
+                       // Save the current container.
+                       
+                       err = _XPCListItemCreate( container, ( containerType == XPC_TYPE_DICTIONARY ) ? keyStr : NULL, &item );
+                       require_noerr( err, exit );
+                       
+                       item->next = list;
+                       list = item;
+                       item = NULL;
+                       
+                       // Create and continue with the child container.
+                       
+                       xpc_release( container );
+                       if( c == '{' )
+                       {
+                               container = xpc_dictionary_create( NULL, NULL, 0 );
+                               require_action( container, exit, err = kNoMemoryErr );
+                       }
+                       else
+                       {
+                               container = xpc_array_create( NULL, 0 );
+                               require_action( container, exit, err = kNoMemoryErr );
+                       }
+                       continue;
+               }
+               
+               // Parse the value string.
+               
+               err = _ParseEscapedString( ptr, end, "{}[]" kWhiteSpaceCharSet, valStr, sizeof( valStr ), NULL, NULL, &ptr );
+               require_noerr_quiet( err, exit );
+               
+               err = _XPCObjectFromString( valStr, &value );
+               require_noerr_quiet( err, exit );
+               
+               if( containerType == XPC_TYPE_DICTIONARY )
+               {
+                       xpc_dictionary_set_value( container, keyStr, value );
+               }
+               else
+               {
+                       xpc_array_append_value( container, value );
+               }
+               xpc_forget( &value );
+       }
+       require_action_quiet( !list, exit, err = kMalformedErr );
+       
+       check( container );
+       check( xpc_get_type( container ) == XPC_TYPE_DICTIONARY );
+       
+       *outDict = container;
+       container = NULL;
+       err = kNoErr;
+       
+exit:
+       xpc_release_null_safe( container );
+       if( list ) _XPCListFree( list );
+       return( err );
+}
+
+static OSStatus        _XPCObjectFromString( const char *inString, xpc_object_t *outObject )
+{
+       OSStatus                        err;
+       xpc_object_t            object;
+       
+       if( 0 ) {}
+       
+       // Bool
+       
+       else if( stricmp_prefix( inString, kXPCObjectPrefix_Bool ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kXPCObjectPrefix_Bool );
+               bool                                    value;
+               
+               if( IsTrueString(  str, kSizeCString ) )
+               {
+                       value = true;
+               }
+               else if( IsFalseString( str, kSizeCString ) )
+               {
+                       value = false;
+               }
+               else
+               {
+                       err = kValueErr;
+                       goto exit;
+               }
+               
+               object = xpc_bool_create( value );
+               require_action( object, exit, err = kNoMemoryErr );
+       }
+       
+       // Data
+       
+       else if( stricmp_prefix( inString, kXPCObjectPrefix_Data ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kXPCObjectPrefix_Data );
+               uint8_t *                               dataPtr;
+               size_t                                  dataLen;
+               
+               err = HexToDataCopy( str, kSizeCString, kHexToData_DefaultFlags, &dataPtr, &dataLen, NULL );
+               require_noerr( err, exit );
+               
+               object = xpc_data_create( dataPtr, dataLen );
+               free( dataPtr );
+               require_action( object, exit, err = kNoMemoryErr );
+       }
+       
+       // Int64
+       
+       else if( stricmp_prefix( inString, kXPCObjectPrefix_Int64 ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kXPCObjectPrefix_Int64 );
+               int64_t                                 i64;
+               
+               i64 = _StringToInt64( str, &err );
+               require_noerr_quiet( err, exit );
+               
+               object = xpc_int64_create( i64 );
+               require_action( object, exit, err = kNoMemoryErr );
+       }
+       
+       // String
+       
+       else if( stricmp_prefix( inString, kXPCObjectPrefix_String ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kXPCObjectPrefix_String );
+               
+               object = xpc_string_create( str );
+               require_action( object, exit, err = kNoMemoryErr );
+       }
+       
+       // UInt64
+       
+       else if( stricmp_prefix( inString, kXPCObjectPrefix_UInt64 ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kXPCObjectPrefix_UInt64 );
+               uint64_t                                u64;
+               
+               u64 = _StringToUInt64( str, &err );
+               require_noerr_quiet( err, exit );
+               
+               object = xpc_uint64_create( u64 );
+               require_action( object, exit, err = kNoMemoryErr );
+       }
+       
+       // UUID
+       
+       else if( stricmp_prefix( inString, kXPCObjectPrefix_UUID ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kXPCObjectPrefix_UUID );
+               uuid_t                                  uuid;
+               
+               err = uuid_parse( str, uuid );
+               require_noerr_action_quiet( err, exit, err = kValueErr );
+               
+               object = xpc_uuid_create( uuid );
+               require_action( object, exit, err = kNoMemoryErr );
+       }
+       
+       // Unsupported prefix
+       
+       else
+       {
+               err = kValueErr;
+               goto exit;
+       }
+       
+       *outObject = object;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+static OSStatus        _XPCListItemCreate( xpc_object_t inObject, const char *inKey, XPCListItem **outItem )
+{
+       OSStatus                        err;
+       XPCListItem *           item;
+       
+       item = (XPCListItem *) calloc( 1, sizeof( *item ) );
+       require_action( item, exit, err = kNoMemoryErr );
+       
+       item->obj = xpc_retain( inObject );
+       if( ( xpc_get_type( item->obj ) == XPC_TYPE_DICTIONARY ) && inKey )
+       {
+               item->key = strdup( inKey );
+               require_action( item->key, exit, err = kNoMemoryErr );
+       }
+       
+       *outItem = item;
+       item = NULL;
+       err = kNoErr;
+       
+exit:
+       if( item ) _XPCListItemFree( item );
+       return( err );
+}
+
+static void    _XPCListItemFree( XPCListItem *inItem )
+{
+       xpc_forget( &inItem->obj );
+       ForgetMem( &inItem->key );
+       free( inItem );
+}
+
+static void _XPCListFree( XPCListItem *inList )
+{
+       XPCListItem *           item;
+       
+       while( ( item = inList ) != NULL )
+       {
+               inList = item->next;
+               _XPCListItemFree( item );
+       }
+}
+#endif // TARGET_OS_DARWIN
+
+#if( MDNSRESPONDER_PROJECT )
+//===========================================================================================================================
+//     InterfaceMonitorCmd
+//===========================================================================================================================
+
+static void    _InterfaceMonitorPrint( mdns_interface_monitor_t inMonitor );
+static void    _InterfaceMonitorSignalHandler( void *inContext );
+
+static void    InterfaceMonitorCmd( void )
+{
+       OSStatus                                                err;
+       mdns_interface_monitor_t                monitor;
+       dispatch_source_t                               signalSource = NULL;
+       uint32_t                                                ifIndex;
+       __block int                                             exitCode;
+       
+       err = InterfaceIndexFromArgString( gInterface, &ifIndex );
+       require_noerr_quiet( err, exit );
+       
+       monitor = mdns_interface_monitor_create( ifIndex );
+       require_action( monitor, exit, err = kNoResourcesErr );
+       
+       exitCode = 0;
+       mdns_interface_monitor_set_queue( monitor, dispatch_get_main_queue() );
+       mdns_interface_monitor_set_event_handler( monitor,
+       ^( mdns_event_t inEvent, OSStatus inError )
+       {
+               switch( inEvent )
+               {
+                       case mdns_event_error:
+                               FPrintF( stderr, "error: Interface monitor failed: %#m\n", inError );
+                               mdns_interface_monitor_invalidate( monitor );
+                               exitCode = 1;
+                               break;
+                       
+                       case mdns_event_invalidated:
+                               FPrintF( stdout, "Interface monitor invalidated.\n" );
+                               mdns_release( monitor );
+                               exit( exitCode );
+                       
+                       default:
+                               FPrintF( stdout, "Unhandled event '%s' (%ld)\n", mdns_event_to_string( inEvent ), (long) inEvent );
+                               break;
+               }
+       } );
+       mdns_interface_monitor_set_update_handler( monitor,
+       ^( __unused mdns_interface_flags_t inChangeFlags )
+       {
+               _InterfaceMonitorPrint( monitor );
+       } );
+       
+       _InterfaceMonitorPrint( monitor );
+       mdns_interface_monitor_activate( monitor );
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, _InterfaceMonitorSignalHandler, monitor, &signalSource );
+       require_noerr( err, exit );
+       dispatch_resume( signalSource );
+       
+       dispatch_main();
+       
+exit:
+       if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+static void    _InterfaceMonitorPrint( mdns_interface_monitor_t inMonitor )
+{
+       FPrintF( stdout, "%{du:time} %@\n", NULL, inMonitor );
+}
+
+static void    _InterfaceMonitorSignalHandler( void *inContext )
+{
+       mdns_interface_monitor_invalidate( (mdns_interface_monitor_t) inContext );
+}
+
+//===========================================================================================================================
+//     DNSProxyCmd
+//===========================================================================================================================
+
+static void    _DNSProxyCallback( DNSXConnRef inConnection, DNSXErrorType inError );
+static void    _DNSProxyCmdSignalHandler( void *inContext );
+
+static void    DNSProxyCmd( void )
+{
+       OSStatus                                err;
+       size_t                                  i;
+       DNSXConnRef                             connection;
+       IfIndex                                 inputIfIndexes[ MaxInputIf ];
+       dispatch_source_t               sigIntSource    = NULL;
+       dispatch_source_t               sigTermSource   = NULL;
+       uint32_t                                outputIfIndex;
+       char                                    ifName[ kInterfaceNameBufLen ];
+       
+       if( gDNSProxy_InputInterfaceCount > MaxInputIf )
+       {
+               FPrintF( stderr, "error: Invalid input interface count: %zu > %d (max).\n",
+                       gDNSProxy_InputInterfaceCount, MaxInputIf );
+               err = kRangeErr;
+               goto exit;
+       }
+       
+       for( i = 0; i < gDNSProxy_InputInterfaceCount; ++i )
+       {
+               uint32_t                ifIndex;
+               
+               err = InterfaceIndexFromArgString( gDNSProxy_InputInterfaces[ i ], &ifIndex );
+               require_noerr_quiet( err, exit );
+               
+               inputIfIndexes[ i ] = ifIndex;
+       }
+       while( i < MaxInputIf ) inputIfIndexes[ i++ ] = 0;      // Remaining interface indexes are required to be 0.
+       
+       if( gDNSProxy_OutputInterface )
+       {
+               err = InterfaceIndexFromArgString( gDNSProxy_OutputInterface, &outputIfIndex );
+               require_noerr_quiet( err, exit );
+       }
+       else
+       {
+               outputIfIndex = kDNSIfindexAny;
+       }
+       
+       FPrintF( stdout, "Input Interfaces:" );
+       for( i = 0; i < gDNSProxy_InputInterfaceCount; ++i )
+       {
+               const uint32_t          ifIndex = (uint32_t) inputIfIndexes[ i ];
+               
+               FPrintF( stdout, "%s %u (%s)", ( i == 0 ) ? "" : ",", ifIndex, InterfaceIndexToName( ifIndex, ifName ) );
+       }
+       FPrintF( stdout, "\n" );
+       FPrintF( stdout, "Output Interface: %u (%s)\n",         outputIfIndex, InterfaceIndexToName( outputIfIndex, ifName ) );
+       FPrintF( stdout, "Start time:       %{du:time}\n",      NULL );
+       FPrintF( stdout, "---\n" );
+       
+       connection = NULL;
+       err = DNSXEnableProxy( &connection, kDNSProxyEnable, inputIfIndexes, outputIfIndex, dispatch_get_main_queue(),
+               _DNSProxyCallback );
+       require_noerr_quiet( err, exit );
+       
+       signal( SIGINT, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGINT, _DNSProxyCmdSignalHandler, connection, &sigIntSource );
+       require_noerr( err, exit );
+       dispatch_activate( sigIntSource );
+       
+       signal( SIGTERM, SIG_IGN );
+       err = DispatchSignalSourceCreate( SIGTERM, _DNSProxyCmdSignalHandler, connection, &sigTermSource );
+       require_noerr( err, exit );
+       dispatch_activate( sigTermSource );
+       
+       dispatch_main();
+       
+exit:
+       if( err ) ErrQuit( 1, "error: %#m\n", err );
+}
+
+static void    _DNSProxyCallback( DNSXConnRef inConnection, DNSXErrorType inError )
+{
+       Unused( inConnection );
+       
+       if( inError ) ErrQuit( 1, "error: DNS proxy failed: %#m\n", inError );
+}
+
+static void    _DNSProxyCmdSignalHandler( void *inContext )
+{
+       DNSXConnRef const               connection = (DNSXConnRef) inContext;
+       struct timeval                  now;
+       
+       gettimeofday( &now, NULL );
+       
+       DNSXRefDeAlloc( connection );
+       
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "End time:         %{du:time}\n", &now );
+       exit( 0 );
+}
+
+#endif // MDNSRESPONDER_PROJECT
+
+//===========================================================================================================================
+//     DaemonVersionCmd
+//===========================================================================================================================
+
+static void    DaemonVersionCmd( void )
+{
+       OSStatus                err;
+       uint32_t                size, version;
+       char                    strBuf[ 16 ];
+       
+       size = (uint32_t) sizeof( version );
+       err = DNSServiceGetProperty( kDNSServiceProperty_DaemonVersion, &version, &size );
+       require_noerr( err, exit );
+       
+       FPrintF( stdout, "Daemon version: %s\n", SourceVersionToCString( version, strBuf ) );
+       
+exit:
+       if( err ) exit( 1 );
+}
+
+//===========================================================================================================================
+//     Exit
+//===========================================================================================================================
+
+static void    Exit( void *inContext )
+{
+       const char * const              reason = (const char *) inContext;
+       
+       FPrintF( stdout, "---\n" );
+       FPrintF( stdout, "End time:   %{du:time}\n", NULL );
+       if( reason ) FPrintF( stdout, "End reason: %s\n", reason );
+       exit( gExitCode );
+}
+
+//===========================================================================================================================
+//     _PrintFExtensionTimestampHandler
+//===========================================================================================================================
+
+static int
+       _PrintFExtensionTimestampHandler(
+               PrintFContext * inContext,
+               PrintFFormat *  inFormat,
+               PrintFVAList *  inArgs,
+               void *                  inUserContext )
+{
+       struct timeval                          now;
+       const struct timeval *          tv;
+       struct tm *                                     localTime;
+       size_t                                          len;
+       int                                                     n;
+       char                                            dateTimeStr[ 32 ];
+       
+       Unused( inUserContext );
+       
+       tv = va_arg( inArgs->args, const struct timeval * );
+       require_action_quiet( !inFormat->suppress, exit, n = 0 );
+       
+       if( !tv )
+       {
+               gettimeofday( &now, NULL );
+               tv = &now;
+       }
+       localTime = localtime( &tv->tv_sec );
+       len = strftime( dateTimeStr, sizeof( dateTimeStr ), "%Y-%m-%d %H:%M:%S", localTime );
+       if( len == 0 ) dateTimeStr[ 0 ] = '\0';
+       
+       n = PrintFCore( inContext, "%s.%06u", dateTimeStr, (unsigned int) tv->tv_usec );
+       
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     _PrintFExtensionDNSMessageHandler
+//===========================================================================================================================
+
+static int
+       _PrintFExtensionDNSMessageHandler(
+               PrintFContext * inContext,
+               PrintFFormat *  inFormat,
+               PrintFVAList *  inArgs,
+               void *                  inUserContext )
+{
+       OSStatus                        err;
+       const void *            msgPtr;
+       size_t                          msgLen;
+       char *                          text;
+       int                                     n;
+       Boolean                         isMDNS;
+       Boolean                         printRawRData;
+       
+       Unused( inUserContext );
+       
+       msgPtr = va_arg( inArgs->args, const void * );
+       msgLen = va_arg( inArgs->args, size_t );
+       require_action_quiet( !inFormat->suppress, exit, n = 0 );
+       
+       isMDNS                  = ( inFormat->altForm   > 0 ) ? true : false;
+       printRawRData   = ( inFormat->precision > 0 ) ? true : false;
+       err = DNSMessageToText( msgPtr, msgLen, isMDNS, printRawRData, &text );
+       if( !err )
+       {
+               n = PrintFCore( inContext, "%*{text}", inFormat->fieldWidth, text, kSizeCString );
+               free( text );
+       }
+       else
+       {
+               n = PrintFCore( inContext, "%*.1H", inFormat->fieldWidth, msgPtr, (int) msgLen, (int) msgLen );
+       }
+       
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     _PrintFExtensionCallbackFlagsHandler
+//===========================================================================================================================
+
+static int
+       _PrintFExtensionCallbackFlagsHandler(
+               PrintFContext * inContext,
+               PrintFFormat *  inFormat,
+               PrintFVAList *  inArgs,
+               void *                  inUserContext )
+{
+       DNSServiceFlags         flags;
+       int                                     n;
+       
+       Unused( inUserContext );
+       
+       flags = va_arg( inArgs->args, DNSServiceFlags );
+       require_action_quiet( !inFormat->suppress, exit, n = 0 );
+       
+       n = PrintFCore( inContext, "%08X %s%c %c%c",
+               flags, DNSServiceFlagsToAddRmvStr( flags ),
+               ( flags & kDNSServiceFlagsMoreComing )       ? '+' : ' ',
+               ( flags & kDNSServiceFlagAnsweredFromCache ) ? 'C' : ' ',
+               ( flags & kDNSServiceFlagsExpiredAnswer )    ? '*' : ' ' );
+       
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     _PrintFExtensionDNSRecordDataHandler
+//===========================================================================================================================
+
+static int
+       _PrintFExtensionDNSRecordDataHandler(
+               PrintFContext * inContext,
+               PrintFFormat *  inFormat,
+               PrintFVAList *  inArgs,
+               void *                  inUserContext )
+{
+       const void *            rdataPtr;
+       unsigned int            rdataLen, rdataType;
+       int                                     n, fieldWidth;
+       
+       Unused( inUserContext );
+       
+       rdataType       = va_arg( inArgs->args, unsigned int );
+       rdataPtr        = va_arg( inArgs->args, const void * );
+       rdataLen        = va_arg( inArgs->args, unsigned int );
+       require_action_quiet( !inFormat->suppress, exit, n = 0 );
+       
+       check( inFormat->fieldWidth < INT_MAX );
+       fieldWidth = inFormat->leftJustify ? -( (int) inFormat->fieldWidth ) : ( (int) inFormat->fieldWidth );
+       
+       if( rdataLen > 0 )
+       {
+               char *          rdataStr = NULL;
+               
+               DNSRecordDataToString( rdataPtr, rdataLen, rdataType, NULL, 0, &rdataStr );
+               if( rdataStr )
+               {
+                       n = PrintFCore( inContext, "%*s", fieldWidth, rdataStr );
+                       free( rdataStr );
+               }
+               else
+               {
+                       n = PrintFCore( inContext, "%*H", fieldWidth, rdataPtr, rdataLen, rdataLen );
+               }
+       }
+       else
+       {
+               n = PrintFCore( inContext, "%*s", fieldWidth, "<< ZERO-LENGTH RDATA >>" );
+       }
+       
+exit:
+       return( n );
+}
+
+//===========================================================================================================================
+//     GetDNSSDFlagsFromOpts
+//===========================================================================================================================
+
+static DNSServiceFlags GetDNSSDFlagsFromOpts( void )
+{
+       DNSServiceFlags         flags;
+       
+       flags = (DNSServiceFlags) gDNSSDFlags;
+       if( flags & kDNSServiceFlagsShareConnection )
+       {
+               FPrintF( stderr, "*** Warning: kDNSServiceFlagsShareConnection (0x%X) is explicitly set in flag parameters.\n",
+                       kDNSServiceFlagsShareConnection );
+       }
+       
+       if( gDNSSDFlag_AllowExpiredAnswers )    flags |= kDNSServiceFlagsAllowExpiredAnswers;
+       if( gDNSSDFlag_BrowseDomains )                  flags |= kDNSServiceFlagsBrowseDomains;
+       if( gDNSSDFlag_DenyCellular )                   flags |= kDNSServiceFlagsDenyCellular;
+       if( gDNSSDFlag_DenyConstrained )                flags |= kDNSServiceFlagsDenyConstrained;
+       if( gDNSSDFlag_DenyExpensive )                  flags |= kDNSServiceFlagsDenyExpensive;
+       if( gDNSSDFlag_ForceMulticast )                 flags |= kDNSServiceFlagsForceMulticast;
+       if( gDNSSDFlag_IncludeAWDL )                    flags |= kDNSServiceFlagsIncludeAWDL;
+       if( gDNSSDFlag_KnownUnique )                    flags |= kDNSServiceFlagsKnownUnique;
+       if( gDNSSDFlag_NoAutoRename )                   flags |= kDNSServiceFlagsNoAutoRename;
+       if( gDNSSDFlag_PathEvaluationDone )             flags |= kDNSServiceFlagsPathEvaluationDone;
+       if( gDNSSDFlag_RegistrationDomains )    flags |= kDNSServiceFlagsRegistrationDomains;
+       if( gDNSSDFlag_ReturnIntermediates )    flags |= kDNSServiceFlagsReturnIntermediates;
+       if( gDNSSDFlag_Shared )                                 flags |= kDNSServiceFlagsShared;
+       if( gDNSSDFlag_SuppressUnusable )               flags |= kDNSServiceFlagsSuppressUnusable;
+       if( gDNSSDFlag_Timeout )                                flags |= kDNSServiceFlagsTimeout;
+       if( gDNSSDFlag_UnicastResponse )                flags |= kDNSServiceFlagsUnicastResponse;
+       if( gDNSSDFlag_Unique )                                 flags |= kDNSServiceFlagsUnique;
+       if( gDNSSDFlag_WakeOnResolve )                  flags |= kDNSServiceFlagsWakeOnResolve;
+       
+       return( flags );
+}
+
+//===========================================================================================================================
+//     CreateConnectionFromArgString
+//===========================================================================================================================
+
+static OSStatus
+       CreateConnectionFromArgString(
+               const char *                    inString,
+               dispatch_queue_t                inQueue,
+               DNSServiceRef *                 outSDRef,
+               ConnectionDesc *                outDesc )
+{
+       OSStatus                        err;
+       DNSServiceRef           sdRef = NULL;
+       ConnectionType          type;
+       int32_t                         pid = -1;       // Initializing because the analyzer claims pid may be used uninitialized.
+       uint8_t                         uuid[ 16 ];
+       
+       if( strcasecmp( inString, kConnectionArg_Normal ) == 0 )
+       {
+               err = DNSServiceCreateConnection( &sdRef );
+               require_noerr( err, exit );
+               type = kConnectionType_Normal;
+       }
+       else if( stricmp_prefix( inString, kConnectionArgPrefix_PID ) == 0 )
+       {
+               const char * const              pidStr = inString + sizeof_string( kConnectionArgPrefix_PID );
+               
+               err = StringToInt32( pidStr, &pid );
+               if( err )
+               {
+                       FPrintF( stderr, "Invalid delegate connection PID value: %s\n", pidStr );
+                       err = kParamErr;
+                       goto exit;
+               }
+               
+               memset( uuid, 0, sizeof( uuid ) );
+               err = DNSServiceCreateDelegateConnection( &sdRef, pid, uuid );
+               if( err )
+               {
+                       FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for PID %d\n", err, pid );
+                       goto exit;
+               }
+               type = kConnectionType_DelegatePID;
+       }
+       else if( stricmp_prefix( inString, kConnectionArgPrefix_UUID ) == 0 )
+       {
+               const char * const              uuidStr = inString + sizeof_string( kConnectionArgPrefix_UUID );
+               
+               check_compile_time_code( sizeof( uuid ) == sizeof( uuid_t ) );
+               
+               err = StringToUUID( uuidStr, kSizeCString, false, uuid );
+               if( err )
+               {
+                       FPrintF( stderr, "Invalid delegate connection UUID value: %s\n", uuidStr );
+                       err = kParamErr;
+                       goto exit;
+               }
+               
+               err = DNSServiceCreateDelegateConnection( &sdRef, 0, uuid );
+               if( err )
+               {
+                       FPrintF( stderr, "DNSServiceCreateDelegateConnection() returned %#m for UUID %#U\n", err, uuid );
+                       goto exit;
+               }
+               type = kConnectionType_DelegateUUID;
+       }
+       else
+       {
+               FPrintF( stderr, "Unrecognized connection string \"%s\".\n", inString );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       err = DNSServiceSetDispatchQueue( sdRef, inQueue );
+       require_noerr( err, exit );
+       
+       *outSDRef = sdRef;
+       if( outDesc )
+       {
+               outDesc->type = type;
+               if(      type == kConnectionType_DelegatePID )  outDesc->delegate.pid = pid;
+               else if( type == kConnectionType_DelegateUUID ) memcpy( outDesc->delegate.uuid, uuid, 16 );
+       }
+       sdRef = NULL;
+       
+exit:
+       if( sdRef ) DNSServiceRefDeallocate( sdRef );
+       return( err );
+}
+
+//===========================================================================================================================
+//     InterfaceIndexFromArgString
+//===========================================================================================================================
+
+static OSStatus        InterfaceIndexFromArgString( const char *inString, uint32_t *outIndex )
+{
+       OSStatus                err;
+       uint32_t                ifIndex;
+       
+       if( inString )
+       {
+               ifIndex = if_nametoindex( inString );
+               if( ifIndex == 0 )
+               {
+                       err = StringToUInt32( inString, &ifIndex );
+                       if( err )
+                       {
+                               FPrintF( stderr, "error: Invalid interface value: %s\n", inString );
+                               err = kParamErr;
+                               goto exit;
+                       }
+               }
+       }
+       else
+       {
+               ifIndex = 0;
+       }
+       
+       *outIndex = ifIndex;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RecordDataFromArgString
+//===========================================================================================================================
+
+static OSStatus        RecordDataFromArgString( const char *inString, uint8_t **outDataPtr, size_t *outDataLen )
+{
+       OSStatus                err;
+       uint8_t *               dataPtr = NULL;
+       size_t                  dataLen;
+       
+       if( 0 ) {}
+       
+       // Domain name
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_Domain ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kRDataArgPrefix_Domain );
+               
+               err = StringToDomainName( str, &dataPtr, &dataLen );
+               require_noerr_quiet( err, exit );
+       }
+       
+       // File path
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_File ) == 0 )
+       {
+               const char * const              path = inString + sizeof_string( kRDataArgPrefix_File );
+               
+               err = CopyFileDataByPath( path, (char **) &dataPtr, &dataLen );
+               require_noerr( err, exit );
+               require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
+       }
+       
+       // Hexadecimal string
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_HexString ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kRDataArgPrefix_HexString );
+               
+               err = HexToDataCopy( str, kSizeCString, kHexToData_DefaultFlags, &dataPtr, &dataLen, NULL );
+               require_noerr( err, exit );
+               require_action( dataLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
+       }
+       
+       // IPv4 address string
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_IPv4 ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kRDataArgPrefix_IPv4 );
+               
+               err = StringToARecordData( str, &dataPtr, &dataLen );
+               require_noerr_quiet( err, exit );
+       }
+       
+       // IPv6 address string
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_IPv6 ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kRDataArgPrefix_IPv6 );
+               
+               err = StringToAAAARecordData( str, &dataPtr, &dataLen );
+               require_noerr_quiet( err, exit );
+       }
+       
+       // SRV record
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_SRV ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kRDataArgPrefix_SRV );
+               
+               err = CreateSRVRecordDataFromString( str, &dataPtr, &dataLen );
+               require_noerr( err, exit );
+       }
+       
+       // String with escaped hex and octal bytes
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_String ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kRDataArgPrefix_String );
+               const char * const              end = str + strlen( str );
+               size_t                                  copiedLen;
+               size_t                                  totalLen;
+               Boolean                                 success;
+               
+               if( str < end )
+               {
+                       success = _ParseQuotedEscapedString( str, end, "", NULL, 0, NULL, &totalLen, NULL );
+                       require_action( success, exit, err = kParamErr );
+                       require_action( totalLen <= kDNSRecordDataLengthMax, exit, err = kSizeErr );
+                       
+                       dataLen = totalLen;
+                       dataPtr = (uint8_t *) malloc( dataLen );
+                       require_action( dataPtr, exit, err = kNoMemoryErr );
+                       
+                       success = _ParseQuotedEscapedString( str, end, "", (char *) dataPtr, dataLen, &copiedLen, NULL, NULL );
+                       require_action( success, exit, err = kParamErr );
+                       check( copiedLen == dataLen );
+               }
+               else
+               {
+                       dataPtr = NULL;
+                       dataLen = 0;
+               }
+       }
+       
+       // TXT record
+       
+       else if( stricmp_prefix( inString, kRDataArgPrefix_TXT ) == 0 )
+       {
+               const char * const              str = inString + sizeof_string( kRDataArgPrefix_TXT );
+               
+               err = CreateTXTRecordDataFromString( str, ',', &dataPtr, &dataLen );
+               require_noerr( err, exit );
+       }
+       
+       // Unrecognized format
+       
+       else
+       {
+               FPrintF( stderr, "Unrecognized record data string \"%s\".\n", inString );
+               err = kParamErr;
+               goto exit;
+       }
+       
+       err = kNoErr;
+       *outDataLen = dataLen;
+       *outDataPtr = dataPtr;
+       dataPtr = NULL;
+       
+exit:
+       FreeNullSafe( dataPtr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     RecordTypeFromArgString
+//===========================================================================================================================
+
+typedef struct
+{
+       uint16_t                        value;  // Record type's numeric value.
+       const char *            name;   // Record type's name as a string (e.g., "A", "PTR", "SRV").
+       
+}      RecordType;
+
+static const RecordType                kRecordTypes[] =
+{
+       // Common types.
+       
+       { kDNSServiceType_A,                    "A" },
+       { kDNSServiceType_AAAA,                 "AAAA" },
+       { kDNSServiceType_PTR,                  "PTR" },
+       { kDNSServiceType_SRV,                  "SRV" },
+       { kDNSServiceType_TXT,                  "TXT" },
+       { kDNSServiceType_CNAME,                "CNAME" },
+       { kDNSServiceType_SOA,                  "SOA" },
+       { kDNSServiceType_NSEC,                 "NSEC" },
+       { kDNSServiceType_NS,                   "NS" },
+       { kDNSServiceType_MX,                   "MX" },
+       { kDNSServiceType_ANY,                  "ANY" },
+       { kDNSServiceType_OPT,                  "OPT" },
+       
+       // Less common types.
+       
+       { kDNSServiceType_MD,                   "MD" },
+       { kDNSServiceType_NS,                   "NS" },
+       { kDNSServiceType_MD,                   "MD" },
+       { kDNSServiceType_MF,                   "MF" },
+       { kDNSServiceType_MB,                   "MB" },
+       { kDNSServiceType_MG,                   "MG" },
+       { kDNSServiceType_MR,                   "MR" },
+       { kDNSServiceType_NULL,                 "NULL" },
+       { kDNSServiceType_WKS,                  "WKS" },
+       { kDNSServiceType_HINFO,                "HINFO" },
+       { kDNSServiceType_MINFO,                "MINFO" },
+       { kDNSServiceType_RP,                   "RP" },
+       { kDNSServiceType_AFSDB,                "AFSDB" },
+       { kDNSServiceType_X25,                  "X25" },
+       { kDNSServiceType_ISDN,                 "ISDN" },
+       { kDNSServiceType_RT,                   "RT" },
+       { kDNSServiceType_NSAP,                 "NSAP" },
+       { kDNSServiceType_NSAP_PTR,             "NSAP_PTR" },
+       { kDNSServiceType_SIG,                  "SIG" },
+       { kDNSServiceType_KEY,                  "KEY" },
+       { kDNSServiceType_PX,                   "PX" },
+       { kDNSServiceType_GPOS,                 "GPOS" },
+       { kDNSServiceType_LOC,                  "LOC" },
+       { kDNSServiceType_NXT,                  "NXT" },
+       { kDNSServiceType_EID,                  "EID" },
+       { kDNSServiceType_NIMLOC,               "NIMLOC" },
+       { kDNSServiceType_ATMA,                 "ATMA" },
+       { kDNSServiceType_NAPTR,                "NAPTR" },
+       { kDNSServiceType_KX,                   "KX" },
+       { kDNSServiceType_CERT,                 "CERT" },
+       { kDNSServiceType_A6,                   "A6" },
+       { kDNSServiceType_DNAME,                "DNAME" },
+       { kDNSServiceType_SINK,                 "SINK" },
+       { kDNSServiceType_APL,                  "APL" },
+       { kDNSServiceType_DS,                   "DS" },
+       { kDNSServiceType_SSHFP,                "SSHFP" },
+       { kDNSServiceType_IPSECKEY,             "IPSECKEY" },
+       { kDNSServiceType_RRSIG,                "RRSIG" },
+       { kDNSServiceType_DNSKEY,               "DNSKEY" },
+       { kDNSServiceType_DHCID,                "DHCID" },
+       { kDNSServiceType_NSEC3,                "NSEC3" },
+       { kDNSServiceType_NSEC3PARAM,   "NSEC3PARAM" },
+       { kDNSServiceType_HIP,                  "HIP" },
+       { kDNSServiceType_SPF,                  "SPF" },
+       { kDNSServiceType_UINFO,                "UINFO" },
+       { kDNSServiceType_UID,                  "UID" },
+       { kDNSServiceType_GID,                  "GID" },
+       { kDNSServiceType_UNSPEC,               "UNSPEC" },
+       { kDNSServiceType_TKEY,                 "TKEY" },
+       { kDNSServiceType_TSIG,                 "TSIG" },
+       { kDNSServiceType_IXFR,                 "IXFR" },
+       { kDNSServiceType_AXFR,                 "AXFR" },
+       { kDNSServiceType_MAILB,                "MAILB" },
+       { kDNSServiceType_MAILA,                "MAILA" }
+};
+
+static OSStatus        RecordTypeFromArgString( const char *inString, uint16_t *outValue )
+{
+       OSStatus                                                err;
+       int32_t                                                 i32;
+       const RecordType *                              type;
+       const RecordType * const                end = kRecordTypes + countof( kRecordTypes );
+       
+       for( type = kRecordTypes; type < end; ++type )
+       {
+               if( strcasecmp( type->name, inString ) == 0 )
+               {
+                       *outValue = type->value;
+                       return( kNoErr );
+               }
+       }
+       
+       err = StringToInt32( inString, &i32 );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
+       
+       *outValue = (uint16_t) i32;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     RecordClassFromArgString
+//===========================================================================================================================
+
+static OSStatus        RecordClassFromArgString( const char *inString, uint16_t *outValue )
+{
+       OSStatus                err;
+       int32_t                 i32;
+       
+       if( strcasecmp( inString, "IN" ) == 0 )
+       {
+               *outValue = kDNSServiceClass_IN;
+               err = kNoErr;
+               goto exit;
+       }
+       
+       err = StringToInt32( inString, &i32 );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( ( i32 >= 0 ) && ( i32 <= UINT16_MAX ), exit, err = kParamErr );
+       
+       *outValue = (uint16_t) i32;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     InterfaceIndexToName
+//===========================================================================================================================
+
+static char * InterfaceIndexToName( uint32_t inIfIndex, char inNameBuf[ kInterfaceNameBufLen ] )
+{
+       switch( inIfIndex )
+       {
+               case kDNSServiceInterfaceIndexAny:
+                       strlcpy( inNameBuf, "Any", kInterfaceNameBufLen );
+                       break;
+               
+               case kDNSServiceInterfaceIndexLocalOnly:
+                       strlcpy( inNameBuf, "LocalOnly", kInterfaceNameBufLen );
+                       break;
+               
+               case kDNSServiceInterfaceIndexUnicast:
+                       strlcpy( inNameBuf, "Unicast", kInterfaceNameBufLen );
+                       break;
+               
+               case kDNSServiceInterfaceIndexP2P:
+                       strlcpy( inNameBuf, "P2P", kInterfaceNameBufLen );
+                       break;
+               
+       #if( defined( kDNSServiceInterfaceIndexBLE ) )
+               case kDNSServiceInterfaceIndexBLE:
+                       strlcpy( inNameBuf, "BLE", kInterfaceNameBufLen );
+                       break;
+       #endif
+               
+               default:
+               {
+                       const char *            name;
+                       
+                       name = if_indextoname( inIfIndex, inNameBuf );
+                       if( !name ) strlcpy( inNameBuf, "NO NAME", kInterfaceNameBufLen );
+                       break;
+               }
+       }
+       
+       return( inNameBuf );
+}
+
+//===========================================================================================================================
+//     RecordTypeToString
+//===========================================================================================================================
+
+static const char *    RecordTypeToString( unsigned int inValue )
+{
+       const RecordType *                              type;
+       const RecordType * const                end = kRecordTypes + countof( kRecordTypes );
+       
+       for( type = kRecordTypes; type < end; ++type )
+       {
+               if( type->value == inValue ) return( type->name );
+       }
+       return( "???" );
+}
+
+//===========================================================================================================================
+//     DNSRecordDataToString
+//===========================================================================================================================
+
+static OSStatus
+       DNSRecordDataToString(
+               const void *    inRDataPtr,
+               size_t                  inRDataLen,
+               unsigned int    inRDataType,
+               const void *    inMsgPtr,
+               size_t                  inMsgLen,
+               char **                 outString )
+{
+       OSStatus                                        err;
+       const uint8_t * const           rdataPtr = (uint8_t *) inRDataPtr;
+       const uint8_t * const           rdataEnd = rdataPtr + inRDataLen;
+       char *                                          rdataStr;
+       const uint8_t *                         ptr;
+       int                                                     n;
+       char                                            domainNameStr[ kDNSServiceMaxDomainName ];
+       
+       rdataStr = NULL;
+       
+       // A Record
+       
+       if( inRDataType == kDNSServiceType_A )
+       {
+               require_action_quiet( inRDataLen == 4, exit, err = kMalformedErr );
+               
+               ASPrintF( &rdataStr, "%.4a", rdataPtr );
+               require_action( rdataStr, exit, err = kNoMemoryErr );
+       }
+       
+       // AAAA Record
+       
+       else if( inRDataType == kDNSServiceType_AAAA )
+       {
+               require_action_quiet( inRDataLen == 16, exit, err = kMalformedErr );
+               
+               ASPrintF( &rdataStr, "%.16a", rdataPtr );
+               require_action( rdataStr, exit, err = kNoMemoryErr );
+       }
+       
+       // PTR, CNAME, or NS Record
+       
+       else if( ( inRDataType == kDNSServiceType_PTR )   ||
+                        ( inRDataType == kDNSServiceType_CNAME ) ||
+                        ( inRDataType == kDNSServiceType_NS ) )
+       {
+               if( inMsgPtr )
+               {
+                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, NULL );
+                       require_noerr( err, exit );
+               }
+               else
+               {
+                       err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, NULL );
+                       require_noerr( err, exit );
+               }
+               
+               rdataStr = strdup( domainNameStr );
+               require_action( rdataStr, exit, err = kNoMemoryErr );
+       }
+       
+       // SRV Record
+       
+       else if( inRDataType == kDNSServiceType_SRV )
+       {
+               const dns_fixed_fields_srv *            fields;
+               const uint8_t *                                         target;
+               unsigned int                                            priority, weight, port;
+               
+               require_action_quiet( inRDataLen > sizeof( dns_fixed_fields_srv ), exit, err = kMalformedErr );
+               
+               fields          = (const dns_fixed_fields_srv *) rdataPtr;
+               priority        = dns_fixed_fields_srv_get_priority( fields );
+               weight          = dns_fixed_fields_srv_get_weight( fields );
+               port            = dns_fixed_fields_srv_get_port( fields );
+               target          = (const uint8_t *) &fields[ 1 ];
+               
+               if( inMsgPtr )
+               {
+                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, target, domainNameStr, NULL );
+                       require_noerr( err, exit );
+               }
+               else
+               {
+                       err = DomainNameToString( target, rdataEnd, domainNameStr, NULL );
+                       require_noerr( err, exit );
+               }
+               
+               ASPrintF( &rdataStr, "%u %u %u %s", priority, weight, port, domainNameStr );
+               require_action( rdataStr, exit, err = kNoMemoryErr );
+       }
+       
+       // TXT Record
+       
+       else if( inRDataType == kDNSServiceType_TXT )
+       {
+               require_action_quiet( inRDataLen > 0, exit, err = kMalformedErr );
+               
+               if( inRDataLen == 1 )
+               {
+                       ASPrintF( &rdataStr, "%#H", rdataPtr, (int) inRDataLen, INT_MAX );
+                       require_action( rdataStr, exit, err = kNoMemoryErr );
+               }
+               else
+               {
+                       ASPrintF( &rdataStr, "%#{txt}", rdataPtr, inRDataLen );
+                       require_action( rdataStr, exit, err = kNoMemoryErr );
+               }
+       }
+       
+       // SOA Record
+       
+       else if( inRDataType == kDNSServiceType_SOA )
+       {
+               const dns_fixed_fields_soa *            fields;
+               uint32_t                                                        serial, refresh, retry, expire, minimum;
+               
+               if( inMsgPtr )
+               {
+                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
+                       require_noerr( err, exit );
+                       
+                       require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
+                       
+                       rdataStr = strdup( domainNameStr );
+                       require_action( rdataStr, exit, err = kNoMemoryErr );
+                       
+                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, ptr, domainNameStr, &ptr );
+                       require_noerr( err, exit );
+               }
+               else
+               {
+                       err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
+                       require_noerr( err, exit );
+                       
+                       rdataStr = strdup( domainNameStr );
+                       require_action( rdataStr, exit, err = kNoMemoryErr );
+                       
+                       err = DomainNameToString( ptr, rdataEnd, domainNameStr, &ptr );
+                       require_noerr( err, exit );
+               }
+               
+               require_action_quiet( ( rdataEnd - ptr ) == sizeof( dns_fixed_fields_soa ), exit, err = kMalformedErr );
+               
+               fields  = (const dns_fixed_fields_soa *) ptr;
+               serial  = dns_fixed_fields_soa_get_serial( fields );
+               refresh = dns_fixed_fields_soa_get_refresh( fields );
+               retry   = dns_fixed_fields_soa_get_retry( fields );
+               expire  = dns_fixed_fields_soa_get_expire( fields );
+               minimum = dns_fixed_fields_soa_get_minimum( fields );
+               
+               n = AppendPrintF( &rdataStr, " %s %u %u %u %u %u\n", domainNameStr, serial, refresh, retry, expire, minimum );
+               require_action( n > 0, exit, err = kUnknownErr );
+       }
+       
+       // NSEC Record
+       
+       else if( inRDataType == kDNSServiceType_NSEC )
+       {
+               unsigned int            windowBlock, bitmapLen, i, recordType;
+               const uint8_t *         bitmapPtr;
+               
+               if( inMsgPtr )
+               {
+                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, rdataPtr, domainNameStr, &ptr );
+                       require_noerr( err, exit );
+               }
+               else
+               {
+                       err = DomainNameToString( rdataPtr, rdataEnd, domainNameStr, &ptr );
+                       require_noerr( err, exit );
+               }
+               
+               require_action_quiet( ptr < rdataEnd, exit, err = kMalformedErr );
+               
+               rdataStr = strdup( domainNameStr );
+               require_action( rdataStr, exit, err = kNoMemoryErr );
+               
+               for( ; ptr < rdataEnd; ptr += ( 2 + bitmapLen ) )
+               {
+                       require_action_quiet( ( ptr + 2 ) < rdataEnd, exit, err = kMalformedErr );
+                       
+                       windowBlock     =  ptr[ 0 ];
+                       bitmapLen       =  ptr[ 1 ];
+                       bitmapPtr       = &ptr[ 2 ];
+                       
+                       require_action_quiet( ( bitmapLen >= 1 ) && ( bitmapLen <= 32 ) , exit, err = kMalformedErr );
+                       require_action_quiet( ( bitmapPtr + bitmapLen ) <= rdataEnd, exit, err = kMalformedErr );
+                       
+                       for( i = 0; i < BitArray_MaxBits( bitmapLen ); ++i )
+                       {
+                               if( BitArray_GetBit( bitmapPtr, bitmapLen, i ) )
+                               {
+                                       recordType = ( windowBlock * 256 ) + i;
+                                       n = AppendPrintF( &rdataStr, " %s", RecordTypeToString( recordType ) );
+                                       require_action( n > 0, exit, err = kUnknownErr );
+                               }
+                       }
+               }
+       }
+       
+       // MX Record
+       
+       else if( inRDataType == kDNSServiceType_MX )
+       {
+               uint16_t                        preference;
+               const uint8_t *         exchange;
+               
+               require_action_quiet( ( rdataPtr + 2 ) < rdataEnd, exit, err = kMalformedErr );
+               
+               preference      = ReadBig16( rdataPtr );
+               exchange        = &rdataPtr[ 2 ];
+               
+               if( inMsgPtr )
+               {
+                       err = DNSMessageExtractDomainNameString( inMsgPtr, inMsgLen, exchange, domainNameStr, NULL );
+                       require_noerr( err, exit );
+               }
+               else
+               {
+                       err = DomainNameToString( exchange, rdataEnd, domainNameStr, NULL );
+                       require_noerr( err, exit );
+               }
+               
+               n = ASPrintF( &rdataStr, "%u %s", preference, domainNameStr );
+               require_action( n > 0, exit, err = kUnknownErr );
+       }
+       
+       // Unhandled record type
+       
+       else
+       {
+               err = kNotHandledErr;
+               goto exit;
+       }
+       
+       check( rdataStr );
+       *outString = rdataStr;
+       rdataStr = NULL;
+       err = kNoErr;
+       
+exit:
+       FreeNullSafe( rdataStr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     DNSMessageToText
+//===========================================================================================================================
+
+#define DNSFlagsOpCodeToString( X ) (                                  \
+       ( (X) == kDNSOpCode_Query )                     ? "Query"       :       \
+       ( (X) == kDNSOpCode_InverseQuery )      ? "IQuery"      :       \
+       ( (X) == kDNSOpCode_Status )            ? "Status"      :       \
+       ( (X) == kDNSOpCode_Notify )            ? "Notify"      :       \
+       ( (X) == kDNSOpCode_Update )            ? "Update"      :       \
+                                                                                 "Unassigned" )
+
+#define DNSFlagsRCodeToString( X ) (                                           \
+       ( (X) == kDNSRCode_NoError )            ? "NoError"             :       \
+       ( (X) == kDNSRCode_FormatError )        ? "FormErr"             :       \
+       ( (X) == kDNSRCode_ServerFailure )      ? "ServFail"    :       \
+       ( (X) == kDNSRCode_NXDomain )           ? "NXDomain"    :       \
+       ( (X) == kDNSRCode_NotImplemented )     ? "NotImp"              :       \
+       ( (X) == kDNSRCode_Refused )            ? "Refused"             :       \
+                                                                                 "???" )
+
+static OSStatus
+       DNSMessageToText(
+               const uint8_t * inMsgPtr,
+               size_t                  inMsgLen,
+               const Boolean   inMDNS,
+               const Boolean   inPrintRaw,
+               char **                 outText )
+{
+       OSStatus                                err;
+       DataBuffer                              dataBuf;
+       size_t                                  len;
+       const DNSHeader *               hdr;
+       const uint8_t *                 ptr;
+       unsigned int                    id, flags, opcode, rcode;
+       unsigned int                    questionCount, answerCount, authorityCount, additionalCount, i, totalRRCount;
+       uint8_t                                 name[ kDomainNameLengthMax ];
+       char                                    nameStr[ kDNSServiceMaxDomainName ];
+       
+       DataBuffer_Init( &dataBuf, NULL, 0, SIZE_MAX );
+       #define _Append( ... )          do { err = DataBuffer_AppendF( &dataBuf, __VA_ARGS__ ); require_noerr( err, exit ); } while( 0 )
+       
+       require_action_quiet( inMsgLen >= kDNSHeaderLength, exit, err = kSizeErr );
+       
+       hdr                             = (DNSHeader *) inMsgPtr;
+       id                              = DNSHeaderGetID( hdr );
+       flags                   = DNSHeaderGetFlags( hdr );
+       questionCount   = DNSHeaderGetQuestionCount( hdr );
+       answerCount             = DNSHeaderGetAnswerCount( hdr );
+       authorityCount  = DNSHeaderGetAuthorityCount( hdr );
+       additionalCount = DNSHeaderGetAdditionalCount( hdr );
+       opcode                  = DNSFlagsGetOpCode( flags );
+       rcode                   = DNSFlagsGetRCode( flags );
+       
+       _Append( "ID:               0x%04X (%u)\n", id, id );
+       _Append( "Flags:            0x%04X %c/%s %cAA%cTC%cRD%cRA%?s%?s %s\n",
+               flags,
+               ( flags & kDNSHeaderFlag_Response )                             ? 'R' : 'Q', DNSFlagsOpCodeToString( opcode ),
+               ( flags & kDNSHeaderFlag_AuthAnswer )                   ? ' ' : '!',
+               ( flags & kDNSHeaderFlag_Truncation )                   ? ' ' : '!',
+               ( flags & kDNSHeaderFlag_RecursionDesired )             ? ' ' : '!',
+               ( flags & kDNSHeaderFlag_RecursionAvailable )   ? ' ' : '!',
+               !inMDNS, ( flags & kDNSHeaderFlag_AuthenticData )               ? " AD" : "!AD",
+               !inMDNS, ( flags & kDNSHeaderFlag_CheckingDisabled )    ? " CD" : "!CD",
+               DNSFlagsRCodeToString( rcode ) );
+       _Append( "Question count:   %u\n", questionCount );
+       _Append( "Answer count:     %u\n", answerCount );
+       _Append( "Authority count:  %u\n", authorityCount );
+       _Append( "Additional count: %u\n", additionalCount );
+       
+       ptr = (const uint8_t *) &hdr[ 1 ];
+       for( i = 0; i < questionCount; ++i )
+       {
+               uint16_t                qtype, qclass;
+               Boolean                 isQU;
+               
+               err = DNSMessageExtractQuestion( inMsgPtr, inMsgLen, ptr, name, &qtype, &qclass, &ptr );
+               require_noerr( err, exit );
+               
+               err = DomainNameToString( name, NULL, nameStr, NULL );
+               require_noerr( err, exit );
+               
+               isQU = ( inMDNS && ( qclass & kQClassUnicastResponseBit ) ) ? true : false;
+               if( inMDNS ) qclass &= ~kQClassUnicastResponseBit;
+               
+               if( i == 0 ) _Append( "\nQUESTION SECTION\n" );
+               
+               _Append( "%-30s %2s %?2s%?2u %-5s\n",
+                       nameStr, inMDNS ? ( isQU ? "QU" : "QM" ) : "",
+                       ( qclass == kDNSServiceClass_IN ), "IN", ( qclass != kDNSServiceClass_IN ), qclass, RecordTypeToString( qtype ) );
+       }
+       
+       totalRRCount = answerCount + authorityCount + additionalCount;
+       for( i = 0; i < totalRRCount; ++i )
+       {
+               uint16_t                        type;
+               uint16_t                        class;
+               uint32_t                        ttl;
+               const uint8_t *         rdataPtr;
+               size_t                          rdataLen;
+               char *                          rdataStr;
+               Boolean                         cacheFlush;
+               
+               err = DNSMessageExtractRecord( inMsgPtr, inMsgLen, ptr, name, &type, &class, &ttl, &rdataPtr, &rdataLen, &ptr );
+               require_noerr( err, exit );
+               
+               err = DomainNameToString( name, NULL, nameStr, NULL );
+               require_noerr( err, exit );
+               
+               cacheFlush = ( inMDNS && ( class & kRRClassCacheFlushBit ) ) ? true : false;
+               if( inMDNS ) class &= ~kRRClassCacheFlushBit;
+               
+               rdataStr = NULL;
+               if( !inPrintRaw ) DNSRecordDataToString( rdataPtr, rdataLen, type, inMsgPtr, inMsgLen, &rdataStr );
+               if( !rdataStr )
+               {
+                       ASPrintF( &rdataStr, "%#H", rdataPtr, (int) rdataLen, (int) rdataLen );
+                       require_action( rdataStr, exit, err = kNoMemoryErr );
+               }
+               
+               if(      answerCount     && ( i ==   0                              ) ) _Append( "\nANSWER SECTION\n" );
+               else if( authorityCount  && ( i ==   answerCount                    ) ) _Append( "\nAUTHORITY SECTION\n" );
+               else if( additionalCount && ( i == ( answerCount + authorityCount ) ) ) _Append( "\nADDITIONAL SECTION\n" );
+               
+               _Append( "%-42s %6u %2s %?2s%?2u %-5s %s\n",
+                       nameStr, ttl, cacheFlush ? "CF" : "",
+                       ( class == kDNSServiceClass_IN ), "IN", ( class != kDNSServiceClass_IN ), class,
+                       RecordTypeToString( type ), rdataStr );
+               free( rdataStr );
+       }
+       _Append( "\n" );
+       
+       err = DataBuffer_Append( &dataBuf, "", 1 );
+       require_noerr( err, exit );
+       
+       err = DataBuffer_Detach( &dataBuf, (uint8_t **) outText, &len );
+       require_noerr( err, exit );
+       
+exit:
+       DataBuffer_Free( &dataBuf );
+       return( err );
+}
+
+//===========================================================================================================================
+//     WriteDNSQueryMessage
+//===========================================================================================================================
+
+static OSStatus
+       WriteDNSQueryMessage(
+               uint8_t                 inMsg[ kDNSQueryMessageMaxLen ],
+               uint16_t                inMsgID,
+               uint16_t                inFlags,
+               const char *    inQName,
+               uint16_t                inQType,
+               uint16_t                inQClass,
+               size_t *                outMsgLen )
+{
+       OSStatus                err;
+       uint8_t                 qname[ kDomainNameLengthMax ];
+       
+       err = DomainNameFromString( qname, inQName, NULL );
+       require_noerr_quiet( err, exit );
+       
+       err = DNSMessageWriteQuery( inMsgID, inFlags, qname, inQType, inQClass, inMsg, outMsgLen );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DispatchSignalSourceCreate
+//===========================================================================================================================
+
+static OSStatus
+       DispatchSignalSourceCreate(
+               int                                     inSignal,
+               DispatchHandler         inEventHandler,
+               void *                          inContext,
+               dispatch_source_t *     outSource )
+{
+       OSStatus                                err;
+       dispatch_source_t               source;
+       
+       source = dispatch_source_create( DISPATCH_SOURCE_TYPE_SIGNAL, (uintptr_t) inSignal, 0, dispatch_get_main_queue() );
+       require_action( source, exit, err = kUnknownErr );
+       
+       dispatch_set_context( source, inContext );
+       dispatch_source_set_event_handler_f( source, inEventHandler );
+       
+       *outSource = source;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DispatchSocketSourceCreate
+//===========================================================================================================================
+
+static OSStatus
+       DispatchSocketSourceCreate(
+               SocketRef                               inSock,
+               dispatch_source_type_t  inType,
+               dispatch_queue_t                inQueue,
+               DispatchHandler                 inEventHandler,
+               DispatchHandler                 inCancelHandler,
+               void *                                  inContext,
+               dispatch_source_t *             outSource )
+{
+       OSStatus                                err;
+       dispatch_source_t               source;
+       
+       source = dispatch_source_create( inType, (uintptr_t) inSock, 0, inQueue ? inQueue : dispatch_get_main_queue() );
+       require_action( source, exit, err = kUnknownErr );
+       
+       dispatch_set_context( source, inContext );
+       dispatch_source_set_event_handler_f( source, inEventHandler );
+       dispatch_source_set_cancel_handler_f( source, inCancelHandler );
+       
+       *outSource = source;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DispatchTimerCreate
+//===========================================================================================================================
+
+static OSStatus
+       DispatchTimerCreate(
+               dispatch_time_t         inStart,
+               uint64_t                        inIntervalNs,
+               uint64_t                        inLeewayNs,
+               dispatch_queue_t        inQueue,
+               DispatchHandler         inEventHandler,
+               DispatchHandler         inCancelHandler,
+               void *                          inContext,
+               dispatch_source_t *     outTimer )
+{
+       OSStatus                                err;
+       dispatch_source_t               timer;
+       
+       timer = dispatch_source_create( DISPATCH_SOURCE_TYPE_TIMER, 0, 0, inQueue ? inQueue : dispatch_get_main_queue() );
+       require_action( timer, exit, err = kUnknownErr );
+       
+       dispatch_source_set_timer( timer, inStart, inIntervalNs, inLeewayNs );
+       dispatch_set_context( timer, inContext );
+       dispatch_source_set_event_handler_f( timer, inEventHandler );
+       dispatch_source_set_cancel_handler_f( timer, inCancelHandler );
+       
+       *outTimer = timer;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     DispatchProcessMonitorCreate
+//===========================================================================================================================
+
+static OSStatus
+       DispatchProcessMonitorCreate(
+               pid_t                           inPID,
+               unsigned long           inFlags,
+               dispatch_queue_t        inQueue,
+               DispatchHandler         inEventHandler,
+               DispatchHandler         inCancelHandler,
+               void *                          inContext,
+               dispatch_source_t *     outMonitor )
+{
+       OSStatus                                err;
+       dispatch_source_t               monitor;
+       
+       monitor = dispatch_source_create( DISPATCH_SOURCE_TYPE_PROC, (uintptr_t) inPID, inFlags,
+               inQueue ? inQueue : dispatch_get_main_queue() );
+       require_action( monitor, exit, err = kUnknownErr );
+       
+       dispatch_set_context( monitor, inContext );
+       dispatch_source_set_event_handler_f( monitor, inEventHandler );
+       dispatch_source_set_cancel_handler_f( monitor, inCancelHandler );
+       
+       *outMonitor = monitor;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     ServiceTypeDescription
+//===========================================================================================================================
+
+typedef struct
+{
+       const char *            name;                   // Name of the service type in two-label "_service._proto" format.
+       const char *            description;    // Description of the service type.
+       
+}      ServiceType;
+
+// A Non-comprehensive table of DNS-SD service types
+
+static const ServiceType               kServiceTypes[] =
+{
+       { "_acp-sync._tcp",                     "AirPort Base Station Sync" },
+       { "_adisk._tcp",                        "Automatic Disk Discovery" },
+       { "_afpovertcp._tcp",           "Apple File Sharing" },
+       { "_airdrop._tcp",                      "AirDrop" },
+       { "_airplay._tcp",                      "AirPlay" },
+       { "_airport._tcp",                      "AirPort Base Station" },
+       { "_daap._tcp",                         "Digital Audio Access Protocol (iTunes)" },
+       { "_eppc._tcp",                         "Remote AppleEvents" },
+       { "_ftp._tcp",                          "File Transfer Protocol" },
+       { "_home-sharing._tcp",         "Home Sharing" },
+       { "_homekit._tcp",                      "HomeKit" },
+       { "_http._tcp",                         "World Wide Web HTML-over-HTTP" },
+       { "_https._tcp",                        "HTTP over SSL/TLS" },
+       { "_ipp._tcp",                          "Internet Printing Protocol" },
+       { "_ldap._tcp",                         "Lightweight Directory Access Protocol" },
+       { "_mediaremotetv._tcp",        "Media Remote" },
+       { "_net-assistant._tcp",        "Apple Remote Desktop" },
+       { "_od-master._tcp",            "OpenDirectory Master" },
+       { "_nfs._tcp",                          "Network File System" },
+       { "_presence._tcp",                     "Peer-to-peer messaging / Link-Local Messaging" },
+       { "_pdl-datastream._tcp",       "Printer Page Description Language Data Stream" },
+       { "_raop._tcp",                         "Remote Audio Output Protocol" },
+       { "_rfb._tcp",                          "Remote Frame Buffer" },
+       { "_scanner._tcp",                      "Bonjour Scanning" },
+       { "_smb._tcp",                          "Server Message Block over TCP/IP" },
+       { "_sftp-ssh._tcp",                     "Secure File Transfer Protocol over SSH" },
+       { "_sleep-proxy._udp",          "Sleep Proxy Server" },
+       { "_ssh._tcp",                          "SSH Remote Login Protocol" },
+       { "_teleport._tcp",                     "teleport" },
+       { "_tftp._tcp",                         "Trivial File Transfer Protocol" },
+       { "_workstation._tcp",          "Workgroup Manager" },
+       { "_webdav._tcp",                       "World Wide Web Distributed Authoring and Versioning (WebDAV)" },
+       { "_webdavs._tcp",                      "WebDAV over SSL/TLS" }
+};
+
+static const char *    ServiceTypeDescription( const char *inName )
+{
+       const ServiceType *                             serviceType;
+       const ServiceType * const               end = kServiceTypes + countof( kServiceTypes );
+       
+       for( serviceType = kServiceTypes; serviceType < end; ++serviceType )
+       {
+               if( ( stricmp_prefix( inName, serviceType->name ) == 0 ) )
+               {
+                       const char * const              ptr = &inName[ strlen( serviceType->name ) ];
+                       
+                       if( ( ptr[ 0 ] == '\0' ) || ( ( ptr[ 0 ] == '.' ) && ( ptr[ 1 ] == '\0' ) ) )
+                       {
+                               return( serviceType->description );
+                       }
+               }
+       }
+       return( NULL );
+}
+
+//===========================================================================================================================
+//     SocketContextCreate
+//===========================================================================================================================
+
+static OSStatus        SocketContextCreate( SocketRef inSock, void * inUserContext, SocketContext **outContext )
+{
+       OSStatus                        err;
+       SocketContext *         context;
+       
+       context = (SocketContext *) calloc( 1, sizeof( *context ) );
+       require_action( context, exit, err = kNoMemoryErr );
+       
+       context->refCount               = 1;
+       context->sock                   = inSock;
+       context->userContext    = inUserContext;
+       
+       *outContext = context;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     SocketContextRetain
+//===========================================================================================================================
+
+static SocketContext * SocketContextRetain( SocketContext *inContext )
+{
+       ++inContext->refCount;
+       return( inContext );
+}
+
+//===========================================================================================================================
+//     SocketContextRelease
+//===========================================================================================================================
+
+static void    SocketContextRelease( SocketContext *inContext )
+{
+       if( --inContext->refCount == 0 )
+       {
+               ForgetSocket( &inContext->sock );
+               free( inContext );
+       }
+}
+
+//===========================================================================================================================
+//     SocketContextCancelHandler
+//===========================================================================================================================
+
+static void    SocketContextCancelHandler( void *inContext )
+{
+       SocketContextRelease( (SocketContext *) inContext );
+}
+
+//===========================================================================================================================
+//     StringToInt32
+//===========================================================================================================================
+
+static OSStatus        StringToInt32( const char *inString, int32_t *outValue )
+{
+       OSStatus                err;
+       long                    value;
+       char *                  endPtr;
+       
+       value = strtol( inString, &endPtr, 0 );
+       require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
+       require_action_quiet( ( value >= INT32_MIN ) && ( value <= INT32_MAX ), exit, err = kRangeErr );
+       
+       *outValue = (int32_t) value;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     StringToUInt32
+//===========================================================================================================================
+
+static OSStatus        StringToUInt32( const char *inString, uint32_t *outValue )
+{
+       OSStatus                err;
+       uint32_t                value;
+       char *                  endPtr;
+       
+       value = (uint32_t) strtol( inString, &endPtr, 0 );
+       require_action_quiet( ( *endPtr == '\0' ) && ( endPtr != inString ), exit, err = kParamErr );
+       
+       *outValue = value;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+//     _StringToInt64
+//===========================================================================================================================
+
+static int64_t _StringToInt64( const char *inString, OSStatus *outError )
+{
+       OSStatus                err;
+       long long               val;
+       char *                  end;
+       int                             errnoVal;
+       
+       set_errno_compat( 0 );
+       val = strtoll( inString, &end, 0 );
+       errnoVal = errno_compat();
+       
+       require_action_quiet( ( *end == '\0' ) && ( end != inString ), exit, err = kMalformedErr );
+       require_action_quiet( ( ( val != LLONG_MIN ) && ( val != LLONG_MAX ) ) || ( errnoVal != ERANGE ), exit, err = kRangeErr );
+       require_action_quiet( ( val >= INT64_MIN ) && ( val <= INT64_MAX ), exit, err = kRangeErr );
+       err = kNoErr;
+       
+exit:
+       if( outError ) *outError = err;
+       return( (int64_t)val );
+}
+
+//===========================================================================================================================
+//     _StringToUInt64
+//===========================================================================================================================
+
+static uint64_t        _StringToUInt64( const char *inString, OSStatus *outError )
+{
+       OSStatus                                err;
+       unsigned long long              val;
+       char *                                  end;
+       int                                             errnoVal;
+       
+       set_errno_compat( 0 );
+       val = strtoull( inString, &end, 0 );
+       errnoVal = errno_compat();
+       
+       require_action_quiet( ( *end == '\0' ) && ( end != inString ), exit, err = kMalformedErr );
+       require_action_quiet( ( val != ULLONG_MAX ) || ( errnoVal != ERANGE ), exit, err = kRangeErr );
+       require_action_quiet( val <= UINT64_MAX, exit, err = kRangeErr );
+       err = kNoErr;
+       
+exit:
+       if( outError ) *outError = err;
+       return( (uint64_t)val );
+}
+
+//===========================================================================================================================
+//     _StringToPID
+//===========================================================================================================================
+
+static pid_t   _StringToPID( const char *inString, OSStatus *outError )
+{
+       OSStatus                err;
+       int64_t                 val;
+       
+       val = _StringToInt64( inString, &err );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( val == (pid_t) val, exit, err = kRangeErr );
+       err = kNoErr;
+       
+exit:
+       if( outError ) *outError = err;
+       return( (pid_t) val );
+}
+
+//===========================================================================================================================
+//     _ParseEscapedString
+//     
+//     Note: Similar to ParseEscapedString() from CoreUtils except that _ParseEscapedString() takes an optional C string
+//     containing delimiter characters instead of being limited to one delimiter character. Also, when the function returns
+//     due to a delimiter, the output pointer is set to the delimiter character instead of the character after the delimiter.
+//===========================================================================================================================
+
+static OSStatus
+       _ParseEscapedString(
+               const char *    inSrc,
+               const char *    inEnd,
+               const char *    inDelimiters,
+               char *                  inBufPtr,
+               size_t                  inBufLen,
+               size_t *                outCopiedLen,
+               size_t *                outActualLen,
+               const char **   outPtr )
+{
+       OSStatus                                err;
+       const char *                    ptr;
+       char *                                  dst = inBufPtr;
+       const char * const              lim = ( inBufLen > 0 ) ? &inBufPtr[ inBufLen - 1 ] : inBufPtr;
+       size_t                                  len;
+       
+       len = 0;
+       ptr = inSrc;
+       if( !inDelimiters ) inDelimiters = "";
+       while( ptr < inEnd )
+       {
+               int                                     c;
+               const char *            del;
+               
+               c = *ptr;
+               for( del = inDelimiters; ( *del != '\0' ) && ( c != *del ); ++del ) {}
+               if( *del != '\0' ) break;
+               ++ptr;
+               if( c == '\\' )
+               {
+                       require_action_quiet( ptr < inEnd, exit, err = kUnderrunErr );
+                       c = *ptr++;
+               }
+               ++len;
+               if( dst < lim ) *dst++ = (char) c;
+       }
+       if( inBufLen > 0 ) *dst = '\0';
+       
+       if( outCopiedLen )      *outCopiedLen   = (size_t)( dst - inBufPtr );
+       if( outActualLen )      *outActualLen   = len;
+       if( outPtr )            *outPtr                 = ptr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+#endif
+
+//===========================================================================================================================
+//     StringToARecordData
+//===========================================================================================================================
+
+static OSStatus        StringToARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+       OSStatus                        err;
+       uint32_t *                      addrPtr;
+       const size_t            addrLen = sizeof( *addrPtr );
+       const char *            end;
+       
+       addrPtr = (uint32_t *) malloc( addrLen );
+       require_action( addrPtr, exit, err = kNoMemoryErr );
+       
+       err = _StringToIPv4Address( inString, kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix, addrPtr,
+               NULL, NULL, NULL, &end );
+       if( !err && ( *end != '\0' ) ) err = kMalformedErr;
+       require_noerr_quiet( err, exit );
+       
+       *addrPtr = HostToBig32( *addrPtr );
+       
+       *outPtr = (uint8_t *) addrPtr;
+       addrPtr = NULL;
+       *outLen = addrLen;
+       
+exit:
+       FreeNullSafe( addrPtr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     StringToAAAARecordData
+//===========================================================================================================================
+
+static OSStatus        StringToAAAARecordData( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+       OSStatus                        err;
+       uint8_t *                       addrPtr;
+       const size_t            addrLen = 16;
+       const char *            end;
+       
+       addrPtr = (uint8_t *) malloc( addrLen );
+       require_action( addrPtr, exit, err = kNoMemoryErr );
+       
+       err = _StringToIPv6Address( inString,
+               kStringToIPAddressFlagsNoPort | kStringToIPAddressFlagsNoPrefix | kStringToIPAddressFlagsNoScope,
+               addrPtr, NULL, NULL, NULL, &end );
+       if( !err && ( *end != '\0' ) ) err = kMalformedErr;
+       require_noerr_quiet( err, exit );
+       
+       *outPtr = addrPtr;
+       addrPtr = NULL;
+       *outLen = addrLen;
+       
+exit:
+       FreeNullSafe( addrPtr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     StringToDomainName
+//===========================================================================================================================
+
+static OSStatus        StringToDomainName( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+       OSStatus                err;
+       uint8_t *               namePtr;
+       size_t                  nameLen;
+       uint8_t *               end;
+       uint8_t                 nameBuf[ kDomainNameLengthMax ];
+       
+       err = DomainNameFromString( nameBuf, inString, &end );
+       require_noerr_quiet( err, exit );
+       
+       nameLen = (size_t)( end - nameBuf );
+       namePtr = _memdup( nameBuf, nameLen );
+       require_action( namePtr, exit, err = kNoMemoryErr );
+       
+       *outPtr = namePtr;
+       namePtr = NULL;
+       if( outLen ) *outLen = nameLen;
+       
+exit:
+       return( err );
+}
+
+#if( TARGET_OS_DARWIN )
+//===========================================================================================================================
+//     GetDefaultDNSServer
+//===========================================================================================================================
+
+static OSStatus        GetDefaultDNSServer( sockaddr_ip *outAddr )
+{
+       OSStatus                                err;
+       dns_config_t *                  config;
+       struct sockaddr *               addr;
+       int32_t                                 i;
+       
+       config = dns_configuration_copy();
+       require_action( config, exit, err = kUnknownErr );
+       
+       addr = NULL;
+       for( i = 0; i < config->n_resolver; ++i )
+       {
+               const dns_resolver_t * const            resolver = config->resolver[ i ];
+               
+               if( !resolver->domain && ( resolver->n_nameserver > 0 ) )
+               {
+                       addr = resolver->nameserver[ 0 ];
+                       break;
+               }
+       }
+       require_action_quiet( addr, exit, err = kNotFoundErr );
+       
+       SockAddrCopy( addr, outAddr );
+       err = kNoErr;
+       
+exit:
+       if( config ) dns_configuration_free( config );
+       return( err );
+}
+#endif
+
+//===========================================================================================================================
+//     GetMDNSMulticastAddrV4
+//===========================================================================================================================
+
+static void    _MDNSMulticastAddrV4Init( void *inContext );
+
+static const struct sockaddr * GetMDNSMulticastAddrV4( void )
+{
+       static struct sockaddr_in               sMDNSMulticastAddrV4;
+       static dispatch_once_t                  sMDNSMulticastAddrV4InitOnce = 0;
+       
+       dispatch_once_f( &sMDNSMulticastAddrV4InitOnce, &sMDNSMulticastAddrV4, _MDNSMulticastAddrV4Init );
+       return( (const struct sockaddr *) &sMDNSMulticastAddrV4 );
+}
+
+static void    _MDNSMulticastAddrV4Init( void *inContext )
+{
+       struct sockaddr_in * const              addr = (struct sockaddr_in *) inContext;
+       
+       memset( addr, 0, sizeof( *addr ) );
+       SIN_LEN_SET( addr );
+       addr->sin_family                = AF_INET;
+       addr->sin_port                  = htons( kMDNSPort );
+       addr->sin_addr.s_addr   = htonl( 0xE00000FB );  // The mDNS IPv4 multicast address is 224.0.0.251
+}
+
+//===========================================================================================================================
+//     GetMDNSMulticastAddrV6
+//===========================================================================================================================
+
+static void    _MDNSMulticastAddrV6Init( void *inContext );
+
+static const struct sockaddr * GetMDNSMulticastAddrV6( void )
+{
+       static struct sockaddr_in6              sMDNSMulticastAddrV6;
+       static dispatch_once_t                  sMDNSMulticastAddrV6InitOnce = 0;
+       
+       dispatch_once_f( &sMDNSMulticastAddrV6InitOnce, &sMDNSMulticastAddrV6, _MDNSMulticastAddrV6Init );
+       return( (const struct sockaddr *) &sMDNSMulticastAddrV6 );
+}
+
+static void    _MDNSMulticastAddrV6Init( void *inContext )
+{
+       struct sockaddr_in6 * const             addr = (struct sockaddr_in6 *) inContext;
+       
+       memset( addr, 0, sizeof( *addr ) );
+       SIN6_LEN_SET( addr );
+       addr->sin6_family       = AF_INET6;
+       addr->sin6_port         = htons( kMDNSPort );
+       addr->sin6_addr.s6_addr[  0 ] = 0xFF;   // The mDNS IPv6 multicast address is FF02::FB.
+       addr->sin6_addr.s6_addr[  1 ] = 0x02;
+       addr->sin6_addr.s6_addr[ 15 ] = 0xFB;
+}
+
+//===========================================================================================================================
+//     CreateMulticastSocket
+//===========================================================================================================================
+
+static OSStatus
+       CreateMulticastSocket(
+               const struct sockaddr * inAddr,
+               int                                             inPort,
+               const char *                    inIfName,
+               uint32_t                                inIfIndex,
+               Boolean                                 inJoin,
+               int *                                   outPort,
+               SocketRef *                             outSock )
+{
+       OSStatus                err;
+       SocketRef               sock    = kInvalidSocketRef;
+       const int               family  = inAddr->sa_family;
+       int                             port;
+       
+       require_action_quiet( ( family == AF_INET ) ||( family == AF_INET6 ), exit, err = kUnsupportedErr );
+       
+       err = ServerSocketOpen( family, SOCK_DGRAM, IPPROTO_UDP, inPort, &port, kSocketBufferSize_DontSet, &sock );
+       require_noerr_quiet( err, exit );
+       
+       err = SocketSetMulticastInterface( sock, inIfName, inIfIndex );
+       require_noerr_quiet( err, exit );
+       
+       if( family == AF_INET )
+       {
+               err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &(uint8_t){ 1 }, (socklen_t) sizeof( uint8_t ) );
+               err = map_socket_noerr_errno( sock, err );
+               require_noerr_quiet( err, exit );
+       }
+       else
+       {
+               err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &(int){ 1 }, (socklen_t) sizeof( int ) );
+               err = map_socket_noerr_errno( sock, err );
+               require_noerr_quiet( err, exit );
+       }
+       
+       if( inJoin )
+       {
+               err = SocketJoinMulticast( sock, inAddr, inIfName, inIfIndex );
+               require_noerr_quiet( err, exit );
+       }
+       
+       if( outPort ) *outPort = port;
+       *outSock = sock;
+       sock = kInvalidSocketRef;
+       
+exit:
+       ForgetSocket( &sock );
+       return( err );
+}
+
+//===========================================================================================================================
+//     DecimalTextToUInt32
+//===========================================================================================================================
+
+static OSStatus        DecimalTextToUInt32( const char *inSrc, const char *inEnd, uint32_t *outValue, const char **outPtr )
+{
+       OSStatus                        err;
+       uint64_t                        value;
+       const char *            ptr = inSrc;
+       
+       require_action_quiet( ( ptr < inEnd ) && isdigit_safe( *ptr ), exit, err = kMalformedErr );
+       
+       value = (uint64_t)( *ptr++ - '0' );
+       if( value == 0 )
+       {
+               if( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
+               {
+                       err = kMalformedErr;
+                       goto exit;
+               }
+       }
+       else
+       {
+               while( ( ptr < inEnd ) && isdigit_safe( *ptr ) )
+               {
+                       value = ( value * 10 ) + (uint64_t)( *ptr++ - '0' );
+                       require_action_quiet( value <= UINT32_MAX, exit, err = kRangeErr );
+               }
+       }
+       
+       *outValue = (uint32_t) value;
+       if( outPtr ) *outPtr = ptr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     CheckIntegerArgument
+//===========================================================================================================================
+
+static OSStatus        CheckIntegerArgument( int inArgValue, const char *inArgName, int inMin, int inMax )
+{
+       if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
+       
+       FPrintF( stderr, "error: Invalid %s: %d. Valid range is [%d, %d].\n", inArgName, inArgValue, inMin, inMax );
+       return( kRangeErr );
+}
+
+//===========================================================================================================================
+//     CheckDoubleArgument
+//===========================================================================================================================
+
+static OSStatus        CheckDoubleArgument( double inArgValue, const char *inArgName, double inMin, double inMax )
+{
+       if( ( inArgValue >= inMin ) && ( inArgValue <= inMax ) ) return( kNoErr );
+       
+       FPrintF( stderr, "error: Invalid %s: %.1f. Valid range is [%.1f, %.1f].\n", inArgName, inArgValue, inMin, inMax );
+       return( kRangeErr );
+}
+
+//===========================================================================================================================
+//     CheckRootUser
+//===========================================================================================================================
+
+static OSStatus        CheckRootUser( void )
+{
+       if( geteuid() == 0 ) return( kNoErr );
+       
+       FPrintF( stderr, "error: This command must to be run as root.\n" );
+       return( kPermissionErr );
+}
+
+//===========================================================================================================================
+//     SpawnCommand
+//
+//     Note: Based on systemf() from CoreUtils framework.
+//===========================================================================================================================
+
+extern char **         environ;
+
+static OSStatus        SpawnCommand( pid_t *outPID, const char *inFormat, ... )
+{
+       OSStatus                err;
+       va_list                 args;
+       char *                  command;
+       char *                  argv[ 4 ];
+       pid_t                   pid;
+       
+       command = NULL;
+       va_start( args, inFormat );
+       VASPrintF( &command, inFormat, args );
+       va_end( args );
+       require_action( command, exit, err = kUnknownErr );
+       
+       argv[ 0 ] = "/bin/sh";
+       argv[ 1 ] = "-c";
+       argv[ 2 ] = command;
+       argv[ 3 ] = NULL;
+       err = posix_spawn( &pid, argv[ 0 ], NULL, NULL, argv, environ );
+       free( command );
+       require_noerr_quiet( err, exit );
+       
+       if( outPID ) *outPID = pid;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     OutputFormatFromArgString
+//===========================================================================================================================
+
+static OSStatus        OutputFormatFromArgString( const char *inArgString, OutputFormatType *outFormat )
+{
+       OSStatus                                err;
+       OutputFormatType                format;
+       
+       format = (OutputFormatType) CLIArgToValue( "format", inArgString, &err,
+               kOutputFormatStr_JSON,          kOutputFormatType_JSON,
+               kOutputFormatStr_XML,           kOutputFormatType_XML,
+               kOutputFormatStr_Binary,        kOutputFormatType_Binary,
+               NULL );
+       if( outFormat ) *outFormat = format;
+       return( err );
+}
+
+//===========================================================================================================================
+//     OutputPropertyList
+//===========================================================================================================================
+
+static OSStatus        OutputPropertyList( CFPropertyListRef inPList, OutputFormatType inType, const char *inOutputFilePath )
+{
+       OSStatus                err;
+       CFDataRef               results = NULL;
+       FILE *                  file    = NULL;
+       
+       // Convert plist to a specific format.
+       
+       switch( inType )
+       {
+               case kOutputFormatType_JSON:
+                       results = CFCreateJSONData( inPList, kJSONFlags_None, NULL );
+                       require_action( results, exit, err = kUnknownErr );
+                       break;
+               
+               case kOutputFormatType_XML:
+                       results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListXMLFormat_v1_0, 0, NULL );
+                       require_action( results, exit, err = kUnknownErr );
+                       break;
+               
+               case kOutputFormatType_Binary:
+                       results = CFPropertyListCreateData( NULL, inPList, kCFPropertyListBinaryFormat_v1_0, 0, NULL );
+                       require_action( results, exit, err = kUnknownErr );
+                       break;
+               
+               default:
+                       err = kTypeErr;
+                       goto exit;
+       }
+       
+       // Write formatted results to file or stdout.
+       
+       if( inOutputFilePath )
+       {
+               file = fopen( inOutputFilePath, "wb" );
+               err = map_global_value_errno( file, file );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               file = stdout;
+       }
+       
+       err = WriteANSIFile( file, CFDataGetBytePtr( results ), (size_t) CFDataGetLength( results ) );
+       require_noerr_quiet( err, exit );
+       
+       // Write a trailing newline for JSON-formatted results.
+       
+       if( inType == kOutputFormatType_JSON )
+       {
+               err = WriteANSIFile( file, "\n", 1 );
+               require_noerr_quiet( err, exit );
+       }
+       
+exit:
+       if( file && ( file != stdout ) ) fclose( file );
+       CFReleaseNullSafe( results );
+       return( err );
+}
+
+//===========================================================================================================================
+//     CreateSRVRecordDataFromString
+//===========================================================================================================================
+
+static OSStatus        CreateSRVRecordDataFromString( const char *inString, uint8_t **outPtr, size_t *outLen )
+{
+       OSStatus                        err;
+       DataBuffer                      dataBuf;
+       const char *            ptr;
+       int                                     i;
+       uint8_t *                       end;
+       uint8_t                         target[ kDomainNameLengthMax ];
+       
+       DataBuffer_Init( &dataBuf, NULL, 0, ( 3 * 2 ) + kDomainNameLengthMax );
+       
+       // Parse and set the priority, weight, and port values (all three are unsigned 16-bit values).
+       
+       ptr = inString;
+       for( i = 0; i < 3; ++i )
+       {
+               char *          next;
+               long            value;
+               uint8_t         buf[ 2 ];
+               
+               value = strtol( ptr, &next, 0 );
+               require_action_quiet( ( next != ptr ) && ( *next == ',' ), exit, err = kMalformedErr );
+               require_action_quiet( ( value >= 0 ) && ( value <= UINT16_MAX ), exit, err = kRangeErr );
+               ptr = next + 1;
+               
+               WriteBig16( buf, value );
+               
+               err = DataBuffer_Append( &dataBuf, buf, sizeof( buf ) );
+               require_noerr( err, exit );
+       }
+       
+       // Set the target domain name.
+       
+       err = DomainNameFromString( target, ptr, &end );
+    require_noerr_quiet( err, exit );
+       
+       err = DataBuffer_Append( &dataBuf, target, (size_t)( end - target ) );
+       require_noerr( err, exit );
+       
+       err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
+       require_noerr( err, exit );
+       
+exit:
+       DataBuffer_Free( &dataBuf );
+       return( err );
+}
+
+//===========================================================================================================================
+//     CreateTXTRecordDataFromString
+//===========================================================================================================================
+
+static OSStatus        CreateTXTRecordDataFromString(const char *inString, int inDelimiter, uint8_t **outPtr, size_t *outLen )
+{
+       OSStatus                        err;
+       DataBuffer                      dataBuf;
+       const char *            src;
+       uint8_t                         txtStr[ 256 ];  // Buffer for single TXT string: 1 length byte + up to 255 bytes of data.
+       
+       DataBuffer_Init( &dataBuf, NULL, 0, kDNSRecordDataLengthMax );
+       
+       src = inString;
+       for( ;; )
+       {
+               uint8_t *                                       dst = &txtStr[ 1 ];
+               const uint8_t * const           lim = &txtStr[ 256 ];
+               int                                                     c;
+               
+               while( *src && ( *src != inDelimiter ) )
+               {
+                       if( ( c = *src++ ) == '\\' )
+                       {
+                               require_action_quiet( *src != '\0', exit, err = kUnderrunErr );
+                               c = *src++;
+                       }
+                       require_action_quiet( dst < lim, exit, err = kOverrunErr );
+                       *dst++ = (uint8_t) c;
+               }
+               txtStr[ 0 ] = (uint8_t)( dst - &txtStr[ 1 ] );
+               err = DataBuffer_Append( &dataBuf, txtStr, 1 + txtStr[ 0 ] );
+               require_noerr( err, exit );
+               
+               if( *src == '\0' ) break;
+               ++src;
+       }
+       
+       err = DataBuffer_Detach( &dataBuf, outPtr, outLen );
+       require_noerr( err, exit );
+       
+exit:
+       DataBuffer_Free( &dataBuf );
+       return( err );
+}
+
+//===========================================================================================================================
+//     CreateNSECRecordData
+//===========================================================================================================================
+
+DECLARE_QSORT_NUMERIC_COMPARATOR( _QSortCmpUnsigned );
+DEFINE_QSORT_NUMERIC_COMPARATOR( unsigned int, _QSortCmpUnsigned )
+
+#define kNSECBitmapMaxLength           32      // 32 bytes (256 bits). See <https://tools.ietf.org/html/rfc4034#section-4.1.2>.
+
+static OSStatus
+       CreateNSECRecordData(
+               const uint8_t * inNextDomainName,
+               uint8_t **              outPtr,
+               size_t *                outLen,
+               unsigned int    inTypeCount,
+               ... )
+{
+       OSStatus                        err;
+       va_list                         args;
+       DataBuffer                      rdataDB;
+       unsigned int *          array   = NULL;
+       unsigned int            i, type, maxBit, currBlock, bitmapLen;
+       uint8_t                         fields[ 2 + kNSECBitmapMaxLength ];
+       uint8_t * const         bitmap  = &fields[ 2 ];
+       
+       va_start( args, inTypeCount );
+       DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
+       
+       // Append Next Domain Name.
+       
+       err = DataBuffer_Append( &rdataDB, inNextDomainName, DomainNameLength( inNextDomainName ) );
+       require_noerr( err, exit );
+       
+       // Append Type Bit Maps.
+       
+       maxBit = 0;
+       memset( bitmap, 0, kNSECBitmapMaxLength );
+       if( inTypeCount > 0 )
+       {
+               array = (unsigned int *) malloc( inTypeCount * sizeof_element( array ) );
+               require_action( array, exit, err = kNoMemoryErr );
+               
+               for( i = 0; i < inTypeCount; ++i )
+               {
+                       type = va_arg( args, unsigned int );
+                       require_action_quiet( type <= UINT16_MAX, exit, err = kRangeErr );
+                       array[ i ] = type;
+               }
+               qsort( array, inTypeCount, sizeof_element( array ), _QSortCmpUnsigned );
+               
+               currBlock = array[ 0 ] / 256;
+               for( i = 0; i < inTypeCount; ++i )
+               {
+                       const unsigned int              block   = array[ i ] / 256;
+                       const unsigned int              bit             = array[ i ] % 256;
+                       
+                       if( block != currBlock )
+                       {
+                               bitmapLen       = BitArray_MaxBytes( maxBit + 1 );
+                               fields[ 0 ] = (uint8_t) currBlock;
+                               fields[ 1 ] = (uint8_t) bitmapLen;
+                               
+                               err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
+                               require_noerr( err, exit );
+                               
+                               maxBit          = 0;
+                               currBlock       = block;
+                               memset( bitmap, 0, bitmapLen );
+                       }
+                       BitArray_SetBit( bitmap, bit );
+                       if( bit > maxBit ) maxBit = bit;
+               }
+       }
+       else
+       {
+               currBlock = 0;
+       }
+       
+       bitmapLen       = BitArray_MaxBytes( maxBit + 1 );
+       fields[ 0 ] = (uint8_t) currBlock;
+       fields[ 1 ] = (uint8_t) bitmapLen;
+       
+       err = DataBuffer_Append( &rdataDB, fields, 2 + bitmapLen );
+       require_noerr( err, exit );
+       
+       err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
+       require_noerr( err, exit );
+       
+exit:
+       va_end( args );
+       DataBuffer_Free( &rdataDB );
+       FreeNullSafe( array );
+       return( err );
+}
+
+//===========================================================================================================================
+//     AppendSOARecord
+//===========================================================================================================================
+
+static OSStatus
+       _AppendSOARecordData(
+               DataBuffer *    inDB,
+               const uint8_t * inMName,
+               const uint8_t * inRName,
+               uint32_t                inSerial,
+               uint32_t                inRefresh,
+               uint32_t                inRetry,
+               uint32_t                inExpire,
+               uint32_t                inMinimumTTL,
+               size_t *                outLen );
+
+static OSStatus
+       AppendSOARecord(
+               DataBuffer *    inDB,
+               const uint8_t * inNamePtr,
+               size_t                  inNameLen,
+               uint16_t                inType,
+               uint16_t                inClass,
+               uint32_t                inTTL,
+               const uint8_t * inMName,
+               const uint8_t * inRName,
+               uint32_t                inSerial,
+               uint32_t                inRefresh,
+               uint32_t                inRetry,
+               uint32_t                inExpire,
+               uint32_t                inMinimumTTL,
+               size_t *                outLen )
+{
+       OSStatus                err;
+       size_t                  rdataLen;
+       size_t                  rdlengthOffset = 0;
+       uint8_t *               rdlengthPtr;
+       
+       if( inDB )
+       {
+               err = _DataBuffer_AppendDNSRecord( inDB, inNamePtr, inNameLen, inType, inClass, inTTL, NULL, 0 );
+               require_noerr( err, exit );
+               
+               rdlengthOffset = DataBuffer_GetLen( inDB ) - 2;
+       }
+       
+       err = _AppendSOARecordData( inDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, &rdataLen );
+       require_noerr( err, exit );
+       
+       if( inDB )
+       {
+               rdlengthPtr = DataBuffer_GetPtr( inDB ) + rdlengthOffset;
+               WriteBig16( rdlengthPtr, rdataLen );
+       }
+       
+       if( outLen ) *outLen = inNameLen + sizeof( dns_fixed_fields_record ) + rdataLen;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+static OSStatus
+       _AppendSOARecordData(
+               DataBuffer *    inDB,
+               const uint8_t * inMName,
+               const uint8_t * inRName,
+               uint32_t                inSerial,
+               uint32_t                inRefresh,
+               uint32_t                inRetry,
+               uint32_t                inExpire,
+               uint32_t                inMinimumTTL,
+               size_t *                outLen )
+{
+       OSStatus                                        err;
+       dns_fixed_fields_soa            fields;
+       const size_t                            mnameLen = DomainNameLength( inMName );
+       const size_t                            rnameLen = DomainNameLength( inRName );
+       
+       if( inDB )
+       {
+               err = DataBuffer_Append( inDB, inMName, mnameLen );
+               require_noerr( err, exit );
+               
+               err = DataBuffer_Append( inDB, inRName, rnameLen );
+               require_noerr( err, exit );
+               
+               dns_fixed_fields_soa_init( &fields, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL );
+               err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+               require_noerr( err, exit );
+       }
+       if( outLen ) *outLen = mnameLen + rnameLen + sizeof( fields );
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     CreateSOARecordData
+//===========================================================================================================================
+
+static OSStatus
+       CreateSOARecordData(
+               const uint8_t * inMName,
+               const uint8_t * inRName,
+               uint32_t                inSerial,
+               uint32_t                inRefresh,
+               uint32_t                inRetry,
+               uint32_t                inExpire,
+               uint32_t                inMinimumTTL,
+               uint8_t **              outPtr,
+               size_t *                outLen )
+{
+       OSStatus                err;
+       DataBuffer              rdataDB;
+       
+       DataBuffer_Init( &rdataDB, NULL, 0, kDNSRecordDataLengthMax );
+       
+       err = _AppendSOARecordData( &rdataDB, inMName, inRName, inSerial, inRefresh, inRetry, inExpire, inMinimumTTL, NULL );
+       require_noerr( err, exit );
+       
+       err = DataBuffer_Detach( &rdataDB, outPtr, outLen );
+       require_noerr( err, exit );
+       
+exit:
+       DataBuffer_Free( &rdataDB );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _DataBuffer_AppendDNSQuestion
+//===========================================================================================================================
+
+static OSStatus
+       _DataBuffer_AppendDNSQuestion(
+               DataBuffer *    inDB,
+               const uint8_t * inNamePtr,
+               size_t                  inNameLen,
+               uint16_t                inType,
+               uint16_t                inClass )
+{
+       OSStatus                                                err;
+       dns_fixed_fields_question               fields;
+       
+       err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
+       require_noerr( err, exit );
+       
+       dns_fixed_fields_question_init( &fields, inType, inClass );
+       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+       require_noerr( err, exit );
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _DataBuffer_AppendDNSRecord
+//===========================================================================================================================
+
+static OSStatus
+       _DataBuffer_AppendDNSRecord(
+               DataBuffer *    inDB,
+               const uint8_t * inNamePtr,
+               size_t                  inNameLen,
+               uint16_t                inType,
+               uint16_t                inClass,
+               uint32_t                inTTL,
+               const uint8_t * inRDataPtr,
+               size_t                  inRDataLen )
+{
+       OSStatus                                        err;
+       dns_fixed_fields_record         fields;
+       
+       require_action_quiet( inRDataLen < kDNSRecordDataLengthMax, exit, err = kSizeErr );
+       
+       err = DataBuffer_Append( inDB, inNamePtr, inNameLen );
+       require_noerr( err, exit );
+       
+       dns_fixed_fields_record_init( &fields, inType, inClass, inTTL, (uint16_t) inRDataLen );
+       err = DataBuffer_Append( inDB, &fields, sizeof( fields ) );
+       require_noerr( err, exit );
+       
+       if( inRDataPtr )
+       {
+               err = DataBuffer_Append( inDB, inRDataPtr, inRDataLen );
+               require_noerr( err, exit );
+       }
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _NanoTime64ToTimestamp
+//===========================================================================================================================
+
+static char *  _NanoTime64ToTimestamp( NanoTime64 inTime, char *inBuf, size_t inMaxLen )
+{
+       struct  timeval         tv;
+       
+       NanoTimeToTimeVal( inTime, &tv );
+       return( MakeFractionalDateString( &tv, inBuf, inMaxLen ) );
+}
+
+//===========================================================================================================================
+//     _MDNSInterfaceListCreate
+//===========================================================================================================================
+
+static Boolean _MDNSInterfaceIsBlacklisted( SocketRef inInfoSock, const char *inIfName );
+
+static OSStatus        _MDNSInterfaceListCreate( MDNSInterfaceSubset inSubset, size_t inItemSize, MDNSInterfaceItem **outList )
+{
+       OSStatus                                        err;
+       struct ifaddrs *                        ifaList;
+       const struct ifaddrs *          ifa;
+       MDNSInterfaceItem *                     interfaceList;
+       MDNSInterfaceItem **            ptr;
+       SocketRef                                       infoSock;
+       
+       ifaList                 = NULL;
+       interfaceList   = NULL;
+       infoSock                = kInvalidSocketRef;
+       if( inItemSize == 0 ) inItemSize = sizeof( MDNSInterfaceItem );
+       require_action_quiet( inItemSize >= sizeof( MDNSInterfaceItem ), exit, err = kSizeErr );
+       
+       infoSock = socket( AF_INET, SOCK_DGRAM, 0 );
+       err = map_socket_creation_errno( infoSock );
+       require_noerr( err, exit );
+       
+       err = getifaddrs( &ifaList );
+       err = map_global_noerr_errno( err );
+       require_noerr( err, exit );
+       
+       ptr = &interfaceList;
+       for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
+       {
+               MDNSInterfaceItem *             item;
+               int                                             family;
+               const unsigned int              flagsMask       = IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT;
+               const unsigned int              flagsNeeded     = IFF_UP | IFF_MULTICAST;
+               
+               if( ( ifa->ifa_flags & flagsMask ) != flagsNeeded )             continue;
+               if( !ifa->ifa_addr || !ifa->ifa_name )                                  continue;
+               family = ifa->ifa_addr->sa_family;
+               if( ( family != AF_INET ) && ( family != AF_INET6 ) )   continue;
+               
+               for( item = interfaceList; item && ( strcmp( item->ifName, ifa->ifa_name ) != 0 ); item = item->next ) {}
+               if( !item )
+               {
+                       NetTransportType                type;
+                       uint32_t                                ifIndex;
+                       const char * const              ifName = ifa->ifa_name;
+                       
+                       if( _MDNSInterfaceIsBlacklisted( infoSock, ifName ) ) continue;
+                       err = SocketGetInterfaceInfo( infoSock, ifName, NULL, &ifIndex, NULL, NULL, NULL, NULL, NULL, &type );
+                       require_noerr( err, exit );
+                       
+                       if( ifIndex == 0 ) continue;
+                       if( type == kNetTransportType_AWDL )
+                       {
+                               if( inSubset == kMDNSInterfaceSubset_NonAWDL ) continue;
+                       }
+                       else
+                       {
+                               if( inSubset == kMDNSInterfaceSubset_AWDL ) continue;
+                       }
+                       item = (MDNSInterfaceItem *) calloc( 1, inItemSize );
+                       require_action( item, exit, err = kNoMemoryErr );
+                       
+                       *ptr =  item;
+                        ptr = &item->next;
+                       
+                       item->ifName = strdup( ifName );
+                       require_action( item->ifName, exit, err = kNoMemoryErr );
+                       
+                       item->ifIndex = ifIndex;
+                       if(      type == kNetTransportType_AWDL ) item->isAWDL = true;
+                       else if( type == kNetTransportType_WiFi ) item->isWiFi = true;
+               }
+               if( family == AF_INET ) item->hasIPv4 = true;
+               else                                    item->hasIPv6 = true;
+       }
+       require_action_quiet( interfaceList, exit, err = kNotFoundErr );
+       
+       if( outList )
+       {
+               *outList = interfaceList;
+               interfaceList = NULL;
+       }
+       
+exit:
+       if( ifaList ) freeifaddrs( ifaList );
+       _MDNSInterfaceListFree( interfaceList );
+       ForgetSocket( &infoSock );
+       return( err );
+}
+
+static Boolean _MDNSInterfaceIsBlacklisted( SocketRef inInfoSock, const char *inIfName )
+{
+       OSStatus                                                err;
+       int                                                             i;
+       static const char * const               kMDNSInterfacePrefixBlacklist[] = { "llw" };
+       struct ifreq                                    ifr;
+       
+       // Check if the interface name's prefix matches the prefix blacklist.
+       
+       for( i = 0; i < (int) countof( kMDNSInterfacePrefixBlacklist ); ++i )
+       {
+               const char * const              prefix  = kMDNSInterfacePrefixBlacklist[ i ];
+               
+        if( strcmp_prefix( inIfName, prefix ) == 0 )
+               {
+                       const char *            ptr = &inIfName[ strlen( prefix ) ];
+                       
+                       while( isdigit_safe( *ptr ) ) ++ptr;
+                       if( *ptr == '\0' ) return( true );
+               }
+       }
+       
+       // Check if the interface is used for inter-(co)processor networking.
+       
+       memset( &ifr, 0, sizeof( ifr ) );
+       strlcpy( ifr.ifr_name, inIfName, sizeof( ifr.ifr_name ) );
+       err = ioctl( inInfoSock, SIOCGIFFUNCTIONALTYPE, &ifr );
+       err = map_global_value_errno( err != -1, err );
+       if( !err && ( ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC ) ) return( true );
+       
+       return( false );
+}
+
+//===========================================================================================================================
+//     _MDNSInterfaceListFree
+//===========================================================================================================================
+
+static void    _MDNSInterfaceListFree( MDNSInterfaceItem *inList )
+{
+       MDNSInterfaceItem *             item;
+       
+       while( ( item = inList ) != NULL )
+       {
+               inList = item->next;
+               FreeNullSafe( item->ifName );
+               free( item );
+       }
+}
+
+//===========================================================================================================================
+//     _MDNSInterfaceGetAny
+//===========================================================================================================================
+
+static OSStatus        _MDNSInterfaceGetAny( MDNSInterfaceSubset inSubset, char inNameBuf[ IF_NAMESIZE + 1 ], uint32_t *outIndex )
+{
+       OSStatus                                                err;
+       MDNSInterfaceItem *                             list;
+       const MDNSInterfaceItem *               item;
+       
+       list = NULL;
+       err = _MDNSInterfaceListCreate( inSubset, 0, &list );
+       require_noerr_quiet( err, exit );
+       require_action_quiet( list, exit, err = kNotFoundErr );
+       
+       for( item = list; item; item = item->next )
+       {
+               if( item->hasIPv4 && item->hasIPv6 ) break;
+       }
+       if( !item ) item = list;
+       if( inNameBuf ) strlcpy( inNameBuf, item->ifName, IF_NAMESIZE + 1 );
+       if( outIndex ) *outIndex = item->ifIndex;
+       
+exit:
+       _MDNSInterfaceListFree( list );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SetComputerName
+//===========================================================================================================================
+
+static OSStatus        _SetComputerName( CFStringRef inComputerName, CFStringEncoding inEncoding )
+{
+       OSStatus                                err;
+       SCPreferencesRef                prefs;
+       Boolean                                 ok;
+       
+       prefs = SCPreferencesCreateWithAuthorization( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+       err = map_scerror( prefs );
+       require_noerr_quiet( err, exit );
+       
+       ok = SCPreferencesSetComputerName( prefs, inComputerName, inEncoding );
+       err = map_scerror( ok );
+       require_noerr_quiet( err, exit );
+       
+       ok = SCPreferencesCommitChanges( prefs );
+       err = map_scerror( ok );
+       require_noerr_quiet( err, exit );
+       
+       ok = SCPreferencesApplyChanges( prefs );
+       err = map_scerror( ok );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       CFReleaseNullSafe( prefs );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SetComputerNameWithUTF8CString
+//===========================================================================================================================
+
+static OSStatus        _SetComputerNameWithUTF8CString( const char *inComputerName )
+{
+       OSStatus                err;
+       CFStringRef             computerName;
+       
+       computerName = CFStringCreateWithCString( NULL, inComputerName, kCFStringEncodingUTF8 );
+       require_action( computerName, exit, err = kNoMemoryErr );
+       
+       err = _SetComputerName( computerName, kCFStringEncodingUTF8 );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       CFReleaseNullSafe( computerName );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SetLocalHostName
+//===========================================================================================================================
+
+static OSStatus        _SetLocalHostName( CFStringRef inLocalHostName )
+{
+       OSStatus                                err;
+       SCPreferencesRef                prefs;
+       Boolean                                 ok;
+       
+       prefs = SCPreferencesCreateWithAuthorization( NULL, CFSTR( kDNSSDUtilIdentifier ), NULL, NULL );
+       err = map_scerror( prefs );
+       require_noerr_quiet( err, exit );
+       
+       ok = SCPreferencesSetLocalHostName( prefs, inLocalHostName );
+       err = map_scerror( ok );
+       require_noerr_quiet( err, exit );
+       
+       ok = SCPreferencesCommitChanges( prefs );
+       err = map_scerror( ok );
+       require_noerr_quiet( err, exit );
+       
+       ok = SCPreferencesApplyChanges( prefs );
+       err = map_scerror( ok );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       CFReleaseNullSafe( prefs );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SetLocalHostNameWithUTF8CString
+//===========================================================================================================================
+
+static OSStatus        _SetLocalHostNameWithUTF8CString( const char *inLocalHostName )
+{
+       OSStatus                err;
+       CFStringRef             localHostName;
+       
+       localHostName = CFStringCreateWithCString( NULL, inLocalHostName, kCFStringEncodingUTF8 );
+       require_action( localHostName, exit, err = kNoMemoryErr );
+       
+       err = _SetLocalHostName( localHostName );
+       require_noerr_quiet( err, exit );
+       
+exit:
+       CFReleaseNullSafe( localHostName );
+       return( err );
+}
+
+//===========================================================================================================================
+//     MDNSColliderCreate
+//===========================================================================================================================
+
+typedef enum
+{
+       kMDNSColliderOpCode_Invalid                     = 0,
+       kMDNSColliderOpCode_Send                        = 1,
+       kMDNSColliderOpCode_Wait                        = 2,
+       kMDNSColliderOpCode_SetProbeActions     = 3,
+       kMDNSColliderOpCode_LoopPush            = 4,
+       kMDNSColliderOpCode_LoopPop                     = 5,
+       kMDNSColliderOpCode_Exit                        = 6
+       
+}      MDNSColliderOpCode;
+
+typedef struct
+{
+       MDNSColliderOpCode              opcode;
+       uint32_t                                operand;
+       
+}      MDNSCInstruction;
+
+#define kMaxLoopDepth          16
+
+struct MDNSColliderPrivate
+{
+       CFRuntimeBase                                   base;                                                   // CF object base.
+       dispatch_queue_t                                queue;                                                  // Queue for collider's events.
+       dispatch_source_t                               readSourceV4;                                   // Read dispatch source for IPv4 socket.
+       dispatch_source_t                               readSourceV6;                                   // Read dispatch source for IPv6 socket.
+       SocketRef                                               sockV4;                                                 // IPv4 UDP socket for mDNS.
+       SocketRef                                               sockV6;                                                 // IPv6 UDP socket for mDNS.
+       uint8_t *                                               target;                                                 // Record name being targeted. (malloced)
+       uint8_t *                                               responsePtr;                                    // Response message pointer. (malloced)
+       size_t                                                  responseLen;                                    // Response message length.
+       uint8_t *                                               probePtr;                                               // Probe query message pointer. (malloced)
+       size_t                                                  probeLen;                                               // Probe query message length.
+       unsigned int                                    probeCount;                                             // Count of probe queries received for collider's record.
+       uint32_t                                                probeActionMap;                                 // Bitmap of actions to take for 
+       MDNSCInstruction *                              program;                                                // Program to execute.
+       uint32_t                                                pc;                                                             // Program's program counter.
+       uint32_t                                                loopCounts[ kMaxLoopDepth ];    // Stack of loop counters.
+       uint32_t                                                loopDepth;                                              // Current loop depth.
+       dispatch_source_t                               waitTimer;                                              // Timer for program's wait commands.
+       uint32_t                                                interfaceIndex;                                 // Interface over which to send and receive mDNS msgs.
+       MDNSColliderStopHandler_f               stopHandler;                                    // User's stop handler.
+       void *                                                  stopContext;                                    // User's stop handler context.
+       MDNSColliderProtocols                   protocols;                                              // Protocols to use, i.e., IPv4, IPv6.
+       Boolean                                                 stopped;                                                // True if the collider has been stopped.
+       uint8_t                                                 msgBuf[ kMDNSMessageSizeMax ];  // mDNS message buffer.
+};
+
+static void            _MDNSColliderStop( MDNSColliderRef inCollider, OSStatus inError );
+static void            _MDNSColliderReadHandler( void *inContext );
+static void            _MDNSColliderExecuteProgram( void *inContext );
+static OSStatus        _MDNSColliderSendResponse( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
+static OSStatus        _MDNSColliderSendProbe( MDNSColliderRef inCollider, SocketRef inSock, const struct sockaddr *inDest );
+
+CF_CLASS_DEFINE( MDNSCollider );
+
+ulog_define_ex( kDNSSDUtilIdentifier, MDNSCollider, kLogLevelInfo, kLogFlags_None, "MDNSCollider", NULL );
+#define mc_ulog( LEVEL, ... )          ulog( &log_category_from_name( MDNSCollider ), (LEVEL), __VA_ARGS__ )
+
+static OSStatus        MDNSColliderCreate( dispatch_queue_t inQueue, MDNSColliderRef *outCollider )
+{
+       OSStatus                        err;
+       MDNSColliderRef         obj = NULL;
+       
+       CF_OBJECT_CREATE( MDNSCollider, obj, err, exit );
+       
+       ReplaceDispatchQueue( &obj->queue, inQueue );
+       obj->sockV4 = kInvalidSocketRef;
+       obj->sockV6 = kInvalidSocketRef;
+       
+       *outCollider = obj;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSColliderFinalize
+//===========================================================================================================================
+
+static void    _MDNSColliderFinalize( CFTypeRef inObj )
+{
+       MDNSColliderRef const           me = (MDNSColliderRef) inObj;
+       
+       check( !me->waitTimer );
+       check( !me->readSourceV4 );
+       check( !me->readSourceV6 );
+       check( !IsValidSocket( me->sockV4 ) );
+       check( !IsValidSocket( me->sockV6 ) );
+       ForgetMem( &me->target );
+       ForgetMem( &me->responsePtr );
+       ForgetMem( &me->probePtr );
+       ForgetMem( &me->program );
+       dispatch_forget( &me->queue );
+}
+
+//===========================================================================================================================
+//     MDNSColliderStart
+//===========================================================================================================================
+
+static void    _MDNSColliderStart( void *inContext );
+
+static OSStatus        MDNSColliderStart( MDNSColliderRef me )
+{
+       OSStatus                err;
+       
+       require_action_quiet( me->target,         exit, err = kNotPreparedErr );
+       require_action_quiet( me->responsePtr,    exit, err = kNotPreparedErr );
+       require_action_quiet( me->probePtr,       exit, err = kNotPreparedErr );
+       require_action_quiet( me->program,        exit, err = kNotPreparedErr );
+       require_action_quiet( me->interfaceIndex, exit, err = kNotPreparedErr );
+       require_action_quiet( me->protocols,      exit, err = kNotPreparedErr );
+       
+       CFRetain( me );
+       dispatch_async_f( me->queue, me, _MDNSColliderStart );
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+static void    _MDNSColliderStart( void *inContext )
+{
+       OSStatus                                        err;
+       MDNSColliderRef const           me              = (MDNSColliderRef) inContext;
+       SocketRef                                       sock    = kInvalidSocketRef;
+       SocketContext *                         sockCtx = NULL;
+       
+       if( me->protocols & kMDNSColliderProtocol_IPv4 )
+       {
+               err = CreateMulticastSocket( GetMDNSMulticastAddrV4(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
+               require_noerr( err, exit );
+               
+               err = SocketContextCreate( sock, me, &sockCtx );
+               require_noerr( err, exit );
+               sock = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
+                       sockCtx, &me->readSourceV4 );
+               require_noerr( err, exit );
+               me->sockV4 = sockCtx->sock;
+               sockCtx = NULL;
+               
+               dispatch_resume( me->readSourceV4 );
+       }
+       
+       if( me->protocols & kMDNSColliderProtocol_IPv6 )
+       {
+               err = CreateMulticastSocket( GetMDNSMulticastAddrV6(), kMDNSPort, NULL, me->interfaceIndex, true, NULL, &sock );
+               require_noerr( err, exit );
+               
+               err = SocketContextCreate( sock, me, &sockCtx );
+               require_noerr( err, exit );
+               sock = kInvalidSocketRef;
+               
+               err = DispatchReadSourceCreate( sockCtx->sock, me->queue, _MDNSColliderReadHandler, SocketContextCancelHandler,
+                       sockCtx, &me->readSourceV6 );
+               require_noerr( err, exit );
+               me->sockV6 = sockCtx->sock;
+               sockCtx = NULL;
+               
+               dispatch_resume( me->readSourceV6 );
+       }
+       
+       _MDNSColliderExecuteProgram( me );
+       err = kNoErr;
+       
+exit:
+       ForgetSocket( &sock );
+       ForgetSocketContext( &sockCtx );
+       if( err ) _MDNSColliderStop( me, err );
+}
+
+//===========================================================================================================================
+//     MDNSColliderStop
+//===========================================================================================================================
+
+static void    _MDNSColliderUserStop( void *inContext );
+
+static void    MDNSColliderStop( MDNSColliderRef me )
+{
+       CFRetain( me );
+       dispatch_async_f( me->queue, me, _MDNSColliderUserStop );
+}
+
+static void    _MDNSColliderUserStop( void *inContext )
+{
+       MDNSColliderRef const           me = (MDNSColliderRef) inContext;
+       
+       _MDNSColliderStop( me, kCanceledErr );
+       CFRelease( me );
+}
+
+//===========================================================================================================================
+//     MDNSColliderSetProtocols
+//===========================================================================================================================
+
+static void    MDNSColliderSetProtocols( MDNSColliderRef me, MDNSColliderProtocols inProtocols )
+{
+       me->protocols = inProtocols;
+}
+
+//===========================================================================================================================
+//     MDNSColliderSetInterfaceIndex
+//===========================================================================================================================
+
+static void    MDNSColliderSetInterfaceIndex( MDNSColliderRef me, uint32_t inInterfaceIndex )
+{
+       me->interfaceIndex = inInterfaceIndex;
+}
+
+//===========================================================================================================================
+//     MDNSColliderSetProgram
+//===========================================================================================================================
+
+#define kMDNSColliderProgCmd_Done              "done"
+#define kMDNSColliderProgCmd_Loop              "loop"
+#define kMDNSColliderProgCmd_Send              "send"
+#define kMDNSColliderProgCmd_Probes            "probes"
+#define kMDNSColliderProgCmd_Wait              "wait"
+
+typedef uint32_t               MDNSColliderProbeAction;
+
+#define kMDNSColliderProbeAction_None                                  0
+#define kMDNSColliderProbeAction_Respond                               1
+#define kMDNSColliderProbeAction_RespondUnicast                        2
+#define kMDNSColliderProbeAction_RespondMulticast              3
+#define kMDNSColliderProbeAction_Probe                                 4
+#define kMDNSColliderProbeAction_MaxValue                              kMDNSColliderProbeAction_Probe
+
+#define kMDNSColliderProbeActionBits_Count                     3
+#define kMDNSColliderProbeActionBits_Mask                      ( ( 1U << kMDNSColliderProbeActionBits_Count ) - 1 )
+#define kMDNSColliderProbeActionMaxProbeCount          ( 32 / kMDNSColliderProbeActionBits_Count )
+
+check_compile_time( kMDNSColliderProbeAction_MaxValue <= kMDNSColliderProbeActionBits_Mask );
+
+static OSStatus        _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap );
+
+static OSStatus        MDNSColliderSetProgram( MDNSColliderRef me, const char *inProgramStr )
+{
+       OSStatus                                err;
+       uint32_t                                insCount;
+       unsigned int                    loopDepth;
+       const char *                    cmd;
+       const char *                    end;
+       const char *                    next;
+       MDNSCInstruction *              program = NULL;
+       uint32_t                                loopStart[ kMaxLoopDepth ];
+       
+       insCount = 0;
+       for( cmd = inProgramStr; *cmd; cmd = next )
+       {
+               for( end = cmd; *end && ( *end != ';' ); ++end ) {}
+               require_action_quiet( end != cmd, exit, err = kMalformedErr );
+               next = ( *end == ';' ) ? ( end + 1 ) : end;
+               ++insCount;
+       }
+       
+       program = (MDNSCInstruction *) calloc( insCount + 1, sizeof( *program ) );
+       require_action( program, exit, err = kNoMemoryErr );
+       
+       insCount        = 0;
+       loopDepth       = 0;
+       for( cmd = inProgramStr; *cmd; cmd = next )
+       {
+               size_t                                                  cmdLen;
+               const char *                                    ptr;
+               const char *                                    arg;
+               size_t                                                  argLen;
+               uint32_t                                                value;
+               MDNSCInstruction * const                ins = &program[ insCount ];
+               
+               while( isspace_safe( *cmd ) ) ++cmd;
+               for( end = cmd; *end && ( *end != ';' ); ++end ) {}
+               next = ( *end == ';' ) ? ( end + 1 ) : end;
+               
+               for( ptr = cmd; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
+               cmdLen = (size_t)( ptr - cmd );
+               
+               // Done statement
+               
+               if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Done ) == 0 )
+               {
+                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
+                       
+                       require_action_quiet( loopDepth > 0, exit, err = kMalformedErr );
+                       
+                       ins->opcode             = kMDNSColliderOpCode_LoopPop;
+                       ins->operand    = loopStart[ --loopDepth ];
+               }
+               
+               // Loop command
+               
+               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Loop ) == 0 )
+               {
+                       for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
+                       err = DecimalTextToUInt32( arg, end, &value, &ptr );
+                       require_noerr_quiet( err, exit );
+                       require_action_quiet( value > 0, exit, err = kValueErr );
+                       
+                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
+                       
+                       ins->opcode     = kMDNSColliderOpCode_LoopPush;
+                       ins->operand    = value;
+                       
+                       require_action_quiet( loopDepth < kMaxLoopDepth, exit, err = kNoSpaceErr );
+                       loopStart[ loopDepth++ ] = insCount + 1;
+               }
+               
+               // Probes command
+               
+               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Probes ) == 0 )
+               {
+                       for( arg = ptr; ( arg < end ) &&  isspace_safe( *arg ); ++arg ) {}
+                       for( ptr = arg; ( ptr < end ) && !isspace_safe( *ptr ); ++ptr ) {}
+                       argLen = (size_t)( ptr - arg );
+                       if( argLen > 0 )
+                       {
+                               err = _MDNSColliderParseProbeActionString( arg, argLen, &value );
+                               require_noerr_quiet( err, exit );
+                       }
+                       else
+                       {
+                               value = 0;
+                       }
+                       
+                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
+                       
+                       ins->opcode     = kMDNSColliderOpCode_SetProbeActions;
+                       ins->operand    = value;
+               }
+               
+               // Send command
+               
+               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Send ) == 0 )
+               {
+                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
+                       
+                       ins->opcode = kMDNSColliderOpCode_Send;
+               }
+               
+               // Wait command
+               
+               else if( strnicmpx( cmd, cmdLen, kMDNSColliderProgCmd_Wait ) == 0 )
+               {
+                       for( arg = ptr; ( arg < end ) && isspace_safe( *arg ); ++arg ) {}
+                       err = DecimalTextToUInt32( arg, end, &value, &ptr );
+                       require_noerr_quiet( err, exit );
+                       
+                       while( ( ptr < end ) && isspace_safe( *ptr ) ) ++ptr;
+                       require_action_quiet( ptr == end, exit, err = kMalformedErr );
+                       
+                       ins->opcode             = kMDNSColliderOpCode_Wait;
+                       ins->operand    = value;
+               }
+               
+               // Unrecognized command
+               
+               else
+               {
+                       err = kCommandErr;
+                       goto exit;
+               }
+               ++insCount;
+       }
+       require_action_quiet( loopDepth == 0, exit, err = kMalformedErr );
+       
+       program[ insCount ].opcode = kMDNSColliderOpCode_Exit;
+       
+       FreeNullSafe( me->program );
+       me->program = program;
+       program = NULL;
+       err = kNoErr;
+       
+exit:
+       FreeNullSafe( program );
+       return( err );
+}
+
+static OSStatus        _MDNSColliderParseProbeActionString( const char *inString, size_t inLen, uint32_t *outBitmap )
+{
+       OSStatus                                err;
+       const char *                    ptr;
+       const char * const              end = &inString[ inLen ];
+       uint32_t                                bitmap;
+       int                                             index;
+       
+       bitmap  = 0;
+       index   = 0;
+       ptr             = inString;
+       while( ptr < end )
+       {
+               int                                                     c, count;
+               MDNSColliderProbeAction         action;
+               
+               c = *ptr++;
+               if( isdigit_safe( c ) )
+               {
+                       count = 0;
+                       do
+                       {
+                               count = ( count * 10 ) + ( c - '0' );
+                               require_action_quiet( count <= ( kMDNSColliderProbeActionMaxProbeCount - index ), exit, err = kCountErr );
+                               require_action_quiet( ptr < end, exit, err = kUnderrunErr );
+                               c = *ptr++;
+                               
+                       }       while( isdigit_safe( c ) );
+                       require_action_quiet( count > 0, exit, err = kCountErr );
+               }
+               else
+               {
+                       require_action_quiet( index < kMDNSColliderProbeActionMaxProbeCount, exit, err = kMalformedErr );
+                       count = 1;
+               }
+               
+               switch( c )
+               {
+                       case 'n':       action = kMDNSColliderProbeAction_None;                         break;
+                       case 'r':       action = kMDNSColliderProbeAction_Respond;                      break;
+                       case 'u':       action = kMDNSColliderProbeAction_RespondUnicast;       break;
+                       case 'm':       action = kMDNSColliderProbeAction_RespondMulticast;     break;
+                       case 'p':       action = kMDNSColliderProbeAction_Probe;                        break;
+                       default:        err = kMalformedErr;                                                            goto exit;
+               }
+               if( ptr < end )
+               {
+                       c = *ptr++;
+                       require_action_quiet( ( c == '-' ) && ( ptr < end ), exit, err = kMalformedErr );
+               }
+               while( count-- > 0 )
+               {
+                       bitmap |= ( action << ( index * kMDNSColliderProbeActionBits_Count ) );
+                       ++index;
+               }
+       }
+       
+       *outBitmap = bitmap;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     MDNSColliderSetStopHandler
+//===========================================================================================================================
+
+static void    MDNSColliderSetStopHandler( MDNSColliderRef me, MDNSColliderStopHandler_f inStopHandler, void *inStopContext )
+{
+       me->stopHandler = inStopHandler;
+       me->stopContext = inStopContext;
+}
+
+//===========================================================================================================================
+//     MDNSColliderSetRecord
+//===========================================================================================================================
+
+#define kMDNSColliderDummyStr                  "\x16" "mdnscollider-sent-this" "\x05" "local"
+#define kMDNSColliderDummyName                 ( (const uint8_t *) kMDNSColliderDummyStr )
+#define kMDNSColliderDummyNameLen              sizeof( kMDNSColliderDummyStr )
+
+static OSStatus
+       MDNSColliderSetRecord(
+               MDNSColliderRef me,
+               const uint8_t * inName,
+               uint16_t                inType,
+               const void *    inRDataPtr,
+               size_t                  inRDataLen )
+{
+       OSStatus                err;
+       DataBuffer              msgDB;
+       DNSHeader               header;
+       uint8_t *               targetPtr       = NULL;
+       size_t                  targetLen;
+       uint8_t *               responsePtr     = NULL;
+       size_t                  responseLen;
+       uint8_t *               probePtr        = NULL;
+       size_t                  probeLen;
+       
+       DataBuffer_Init( &msgDB, NULL, 0, kMDNSMessageSizeMax );
+       
+       err = DomainNameDup( inName, &targetPtr, &targetLen );
+       require_noerr_quiet( err, exit );
+       
+       // Create response message.
+       
+       memset( &header, 0, sizeof( header ) );
+       DNSHeaderSetFlags( &header, kDNSHeaderFlag_Response | kDNSHeaderFlag_AuthAnswer );
+       DNSHeaderSetAnswerCount( &header, 1 );
+       
+       err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
+       require_noerr( err, exit );
+       
+       err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN | kRRClassCacheFlushBit,
+               1976, inRDataPtr, inRDataLen );
+       require_noerr( err, exit );
+       
+       err = DataBuffer_Detach( &msgDB, &responsePtr, &responseLen );
+       require_noerr( err, exit );
+       
+       // Create probe message.
+       
+       memset( &header, 0, sizeof( header ) );
+       DNSHeaderSetQuestionCount( &header, 2 );
+       DNSHeaderSetAuthorityCount( &header, 1 );
+       
+       err = DataBuffer_Append( &msgDB, &header, sizeof( header ) );
+       require_noerr( err, exit );
+       
+       err = _DataBuffer_AppendDNSQuestion( &msgDB, targetPtr, targetLen, kDNSServiceType_ANY, kDNSServiceClass_IN );
+       require_noerr( err, exit );
+       
+       err = _DataBuffer_AppendDNSQuestion( &msgDB, kMDNSColliderDummyName, kMDNSColliderDummyNameLen,
+               kDNSServiceType_NULL, kDNSServiceClass_IN );
+       require_noerr( err, exit );
+       
+       err = _DataBuffer_AppendDNSRecord( &msgDB, targetPtr, targetLen, inType, kDNSServiceClass_IN,
+               1976, inRDataPtr, inRDataLen );
+       require_noerr( err, exit );
+       
+       err = DataBuffer_Detach( &msgDB, &probePtr, &probeLen );
+       require_noerr( err, exit );
+       
+       FreeNullSafe( me->target );
+       me->target = targetPtr;
+       targetPtr = NULL;
+       
+       FreeNullSafe( me->responsePtr );
+       me->responsePtr = responsePtr;
+       me->responseLen = responseLen;
+       responsePtr = NULL;
+       
+       FreeNullSafe( me->probePtr );
+       me->probePtr = probePtr;
+       me->probeLen = probeLen;
+       probePtr = NULL;
+       
+exit:
+       DataBuffer_Free( &msgDB );
+       FreeNullSafe( targetPtr );
+       FreeNullSafe( responsePtr );
+       FreeNullSafe( probePtr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSColliderStop
+//===========================================================================================================================
+
+static void    _MDNSColliderStop( MDNSColliderRef me, OSStatus inError )
+{
+       dispatch_source_forget( &me->waitTimer );
+       dispatch_source_forget( &me->readSourceV4 );
+       dispatch_source_forget( &me->readSourceV6 );
+       me->sockV4 = kInvalidSocketRef;
+       me->sockV6 = kInvalidSocketRef;
+       
+       if( !me->stopped )
+       {
+               me->stopped = true;
+               if( me->stopHandler ) me->stopHandler( me->stopContext, inError );
+               CFRelease( me );
+       }
+}
+
+//===========================================================================================================================
+//     _MDNSColliderReadHandler
+//===========================================================================================================================
+
+static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber );
+static const char *                            _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction );
+
+static void    _MDNSColliderReadHandler( void *inContext )
+{
+       OSStatus                                        err;
+       struct timeval                          now;
+       SocketContext * const           sockCtx = (SocketContext *) inContext;
+       MDNSColliderRef const           me              = (MDNSColliderRef) sockCtx->userContext;
+       size_t                                          msgLen;
+       sockaddr_ip                                     sender;
+       const DNSHeader *                       hdr;
+       const uint8_t *                         ptr;
+       const struct sockaddr *         dest;
+       int                                                     probeFound, probeIsQU;
+       unsigned int                            qCount, i;
+       MDNSColliderProbeAction         action;
+       
+       gettimeofday( &now, NULL );
+       
+       err = SocketRecvFrom( sockCtx->sock, me->msgBuf, sizeof( me->msgBuf ), &msgLen, &sender, sizeof( sender ),
+               NULL, NULL, NULL, NULL );
+       require_noerr( err, exit );
+       
+       require_quiet( msgLen >= kDNSHeaderLength, exit );
+       hdr = (const DNSHeader *) me->msgBuf;
+       
+       probeFound      = false;
+       probeIsQU       = false;
+       qCount = DNSHeaderGetQuestionCount( hdr );
+       ptr = (const uint8_t *) &hdr[ 1 ];
+       for( i = 0; i < qCount; ++i )
+       {
+               uint16_t                qtype, qclass;
+               uint8_t                 qname[ kDomainNameLengthMax ];
+               
+               err = DNSMessageExtractQuestion( me->msgBuf, msgLen, ptr, qname, &qtype, &qclass, &ptr );
+               require_noerr_quiet( err, exit );
+               
+               if( ( qtype == kDNSServiceType_NULL ) && ( qclass == kDNSServiceClass_IN ) &&
+                       DomainNameEqual( qname, kMDNSColliderDummyName ) )
+               {
+                       probeFound = false;
+                       break;
+               }
+               
+               if( qtype != kDNSServiceType_ANY ) continue;
+               if( ( qclass & ~kQClassUnicastResponseBit ) != kDNSServiceClass_IN ) continue;
+               if( !DomainNameEqual( qname, me->target ) ) continue;
+               
+               if( !probeFound )
+               {
+                       probeFound      = true;
+                       probeIsQU       = ( qclass & kQClassUnicastResponseBit ) ? true : false;
+               }
+       }
+       require_quiet( probeFound, exit );
+       
+       ++me->probeCount;
+       action = _MDNSColliderGetProbeAction( me->probeActionMap, me->probeCount );
+       
+       mc_ulog( kLogLevelInfo, "Received probe from %##a at %{du:time} (action: %s):\n\n%#1{du:dnsmsg}",
+               &sender, &now, _MDNSColliderProbeActionToString( action ), me->msgBuf, msgLen );
+       
+       if( ( action == kMDNSColliderProbeAction_Respond )                      ||
+               ( action == kMDNSColliderProbeAction_RespondUnicast )   ||
+               ( action == kMDNSColliderProbeAction_RespondMulticast ) )
+       {
+               if( ( ( action == kMDNSColliderProbeAction_Respond ) && probeIsQU ) ||
+                       (   action == kMDNSColliderProbeAction_RespondUnicast ) )
+               {
+                       dest = &sender.sa;
+               }
+               else if( ( ( action == kMDNSColliderProbeAction_Respond ) && !probeIsQU ) ||
+                                (   action == kMDNSColliderProbeAction_RespondMulticast ) )
+               {
+                       dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
+               }
+               
+               err = _MDNSColliderSendResponse( me, sockCtx->sock, dest );
+               require_noerr( err, exit );
+       }
+       else if( action == kMDNSColliderProbeAction_Probe )
+       {
+               dest = ( sender.sa.sa_family == AF_INET ) ? GetMDNSMulticastAddrV4() : GetMDNSMulticastAddrV6();
+               
+               err = _MDNSColliderSendProbe( me, sockCtx->sock, dest );
+               require_noerr( err, exit );
+       }
+       
+exit:
+       return;
+}
+
+static MDNSColliderProbeAction _MDNSColliderGetProbeAction( uint32_t inBitmap, unsigned int inProbeNumber )
+{
+       MDNSColliderProbeAction         action;
+       
+       if( ( inProbeNumber >= 1 ) && ( inProbeNumber <= kMDNSColliderProbeActionMaxProbeCount ) )
+       {
+               action = ( inBitmap >> ( ( inProbeNumber - 1 ) * kMDNSColliderProbeActionBits_Count ) ) &
+                       kMDNSColliderProbeActionBits_Mask;
+       }
+       else
+       {
+               action = kMDNSColliderProbeAction_None;
+       }
+       return( action );
+}
+
+static const char *    _MDNSColliderProbeActionToString( MDNSColliderProbeAction inAction )
+{
+       switch( inAction )
+       {
+               case kMDNSColliderProbeAction_None:                             return( "None" );
+               case kMDNSColliderProbeAction_Respond:                  return( "Respond" );
+               case kMDNSColliderProbeAction_RespondUnicast:   return( "Respond (unicast)" );
+               case kMDNSColliderProbeAction_RespondMulticast: return( "Respond (multicast)" );
+               case kMDNSColliderProbeAction_Probe:                    return( "Probe" );
+               default:                                                                                return( "???" );
+       }
+}
+
+//===========================================================================================================================
+//     _MDNSColliderExecuteProgram
+//===========================================================================================================================
+
+static void    _MDNSColliderExecuteProgram( void *inContext )
+{
+       OSStatus                                        err;
+       MDNSColliderRef const           me = (MDNSColliderRef) inContext;
+       int                                                     stop;
+       
+       dispatch_forget( &me->waitTimer );
+       
+       stop = false;
+       for( ;; )
+       {
+               const MDNSCInstruction * const          ins = &me->program[ me->pc++ ];
+               uint32_t                                                        waitMs;
+               
+               switch( ins->opcode )
+               {
+                       case kMDNSColliderOpCode_Send:
+                               if( IsValidSocket( me->sockV4 ) )
+                               {
+                                       err = _MDNSColliderSendResponse( me, me->sockV4, GetMDNSMulticastAddrV4() );
+                                       require_noerr( err, exit );
+                               }
+                               if( IsValidSocket( me->sockV6 ) )
+                               {
+                                       err = _MDNSColliderSendResponse( me, me->sockV6, GetMDNSMulticastAddrV6() );
+                                       require_noerr( err, exit );
+                               }
+                               break;
+                       
+                       case kMDNSColliderOpCode_Wait:
+                               waitMs = ins->operand;
+                               if( waitMs > 0 )
+                               {
+                                       err = DispatchTimerOneShotCreate( dispatch_time_milliseconds( waitMs ), 1, me->queue,
+                                               _MDNSColliderExecuteProgram, me, &me->waitTimer );
+                                       require_noerr( err, exit );
+                                       dispatch_resume( me->waitTimer );
+                                       goto exit;
+                               }
+                               break;
+                       
+                       case kMDNSColliderOpCode_SetProbeActions:
+                               me->probeCount          = 0;
+                               me->probeActionMap      = ins->operand;
+                               break;
+                       
+                       case kMDNSColliderOpCode_LoopPush:
+                               check( me->loopDepth < kMaxLoopDepth );
+                               me->loopCounts[ me->loopDepth++ ] = ins->operand;
+                               break;
+                       
+                       case kMDNSColliderOpCode_LoopPop:
+                               check( me->loopDepth > 0 );
+                               if( --me->loopCounts[ me->loopDepth - 1 ] > 0 )
+                               {
+                                       me->pc = ins->operand;
+                               }
+                               else
+                               {
+                                       --me->loopDepth;
+                               }
+                               break;
+                       
+                       case kMDNSColliderOpCode_Exit:
+                               stop = true;
+                               err     = kNoErr;
+                               goto exit;
+                       
+                       default:
+                               dlogassert( "Unhandled opcode %u\n", ins->opcode );
+                               err = kCommandErr;
+                               goto exit;
+               }
+       }
+       
+exit:
+       if( err || stop ) _MDNSColliderStop( me, err );
+}
+
+//===========================================================================================================================
+//     _MDNSColliderSendResponse
+//===========================================================================================================================
+
+static OSStatus        _MDNSColliderSendResponse( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
+{
+       OSStatus                err;
+       ssize_t                 n;
+       
+       n = sendto( inSock, (char *) me->responsePtr, me->responseLen, 0, inDest, SockAddrGetSize( inDest ) );
+       err = map_socket_value_errno( inSock, n == (ssize_t) me->responseLen, n );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _MDNSColliderSendProbe
+//===========================================================================================================================
+
+static OSStatus        _MDNSColliderSendProbe( MDNSColliderRef me, SocketRef inSock, const struct sockaddr *inDest )
+{
+       OSStatus                err;
+       ssize_t                 n;
+       
+       n = sendto( inSock, (char *) me->probePtr, me->probeLen, 0, inDest, SockAddrGetSize( inDest ) );
+       err = map_socket_value_errno( inSock, n == (ssize_t) me->probeLen, n );
+       return( err );
+}
+
+//===========================================================================================================================
+//     ServiceBrowserCreate
+//===========================================================================================================================
+
+typedef struct SBDomain                                        SBDomain;
+typedef struct SBServiceType                   SBServiceType;
+typedef struct SBServiceBrowse                 SBServiceBrowse;
+typedef struct SBServiceInstance               SBServiceInstance;
+typedef struct SBIPAddress                             SBIPAddress;
+
+struct ServiceBrowserPrivate
+{
+       CFRuntimeBase                                   base;                           // CF object base.
+       dispatch_queue_t                                queue;                          // Queue for service browser's events.
+       DNSServiceRef                                   connection;                     // Shared connection for DNS-SD ops.
+       DNSServiceRef                                   domainsQuery;           // Query for recommended browsing domains.
+       char *                                                  domain;                         // If non-null, then browsing is limited to this domain.
+       StringListItem *                                serviceTypeList;        // If non-null, then browsing is limited to these service types.
+       ServiceBrowserCallback_f                userCallback;           // User's callback. Called when browsing stops.
+       void *                                                  userContext;            // User's callback context.
+       SBDomain *                                              domainList;                     // List of domains and their browse results.
+       dispatch_source_t                               stopTimer;                      // Timer to stop browsing after browseTimeSecs.
+       uint32_t                                                ifIndex;                        // If non-zero, then browsing is limited to this interface.
+       unsigned int                                    browseTimeSecs;         // Amount of time to spend browsing in seconds.
+       Boolean                                                 includeAWDL;            // True if the IncludeAWDL flag should be used for DNS-SD ops that
+                                                                                                               // use the "any" interface.
+};
+
+struct SBDomain
+{
+       SBDomain *                              next;                   // Next domain object in list.
+       ServiceBrowserRef               browser;                // Pointer to parent service browser.
+       char *                                  name;                   // Name of the domain.
+       DNSServiceRef                   servicesQuery;  // Query for services (_services._dns-sd._udp.<domain> PTR record) in domain.
+       SBServiceType *                 typeList;               // List of service types to browse for in this domain.
+};
+
+struct SBServiceType
+{
+       SBServiceType *                 next;           // Next service type object in list.
+       char *                                  name;           // Name of the service type.
+       SBServiceBrowse *               browseList;     // List of browses for this service type.
+};
+
+struct SBServiceBrowse
+{
+       SBServiceBrowse *               next;                   // Next browse object in list.
+       ServiceBrowserRef               browser;                // Pointer to parent service browser.
+       DNSServiceRef                   browse;                 // Reference to DNSServiceBrowse op.
+       SBServiceInstance *             instanceList;   // List of service instances that were discovered by this browse.
+       uint64_t                                startTicks;             // Value of UpTicks() when the browse op began.
+       uint32_t                                ifIndex;                // If non-zero, then the browse is limited to this interface.
+};
+
+struct SBServiceInstance
+{
+       SBServiceInstance *             next;                           // Next service instance object in list.
+       ServiceBrowserRef               browser;                        // Pointer to parent service browser.
+       char *                                  name;                           // Name of the service instance.
+       char *                                  fqdn;                           // Fully qualified domain name of service instance (for logging/debugging).
+       uint32_t                                ifIndex;                        // Index of interface over which this service instance was discovered.
+       uint64_t                                discoverTimeUs;         // Time it took to discover this service instance in microseconds.
+       DNSServiceRef                   resolve;                        // Reference to DNSServiceResolve op for this service instance.
+       uint64_t                                resolveStartTicks;      // Value of UpTicks() when the DNSServiceResolve op began.
+       uint64_t                                resolveTimeUs;          // Time it took to resolve this service instance.
+       char *                                  hostname;                       // Service instance's hostname. Result of DNSServiceResolve.
+       uint16_t                                port;                           // Service instance's port number. Result of DNSServiceResolve.
+       uint8_t *                               txtPtr;                         // Service instance's TXT record data. Result of DNSServiceResolve.
+       size_t                                  txtLen;                         // Length of service instance's TXT record data.
+       DNSServiceRef                   getAddrInfo;            // Reference to DNSServiceGetAddrInfo op for service instance's hostname.
+       uint64_t                                gaiStartTicks;          // Value of UpTicks() when the DNSServiceGetAddrInfo op began.
+       SBIPAddress *                   ipaddrList;                     // List of IP addresses that the hostname resolved to.
+};
+
+struct SBIPAddress
+{
+       SBIPAddress *           next;                   // Next IP address object in list.
+       sockaddr_ip                     sip;                    // IPv4 or IPv6 address.
+       uint64_t                        resolveTimeUs;  // Time it took to resolve this IP address in microseconds.
+};
+
+typedef struct
+{
+       SBRDomain *             domainList;     // List of domains in which services were found.
+       int32_t                 refCount;       // This object's reference count.
+       
+}      ServiceBrowserResultsPrivate;
+
+static void            _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError );
+static OSStatus        _ServiceBrowserAddDomain( ServiceBrowserRef inBrowser, const char *inDomain );
+static OSStatus        _ServiceBrowserRemoveDomain( ServiceBrowserRef inBrowser, const char *inName );
+static void            _ServiceBrowserTimerHandler( void *inContext );
+static void DNSSD_API
+       _ServiceBrowserDomainsQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static void DNSSD_API
+       _ServiceBrowserServicesQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static void DNSSD_API
+       _ServiceBrowserBrowseCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inRegType,
+               const char *            inDomain,
+               void *                          inContext );
+static void DNSSD_API
+       _ServiceBrowserResolveCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               uint16_t                                inTXTLen,
+               const unsigned char *   inTXTPtr,
+               void *                                  inContext );
+static void DNSSD_API
+       _ServiceBrowserGAICallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext );
+static OSStatus
+       _ServiceBrowserAddServiceType(
+               ServiceBrowserRef       inBrowser,
+               SBDomain *                      inDomain,
+               const char *            inName,
+               uint32_t                        inIfIndex );
+static OSStatus
+       _ServiceBrowserRemoveServiceType(
+               ServiceBrowserRef       inBrowser,
+               SBDomain *                      inDomain,
+               const char *            inName,
+               uint32_t                        inIfIndex );
+static OSStatus
+       _ServiceBrowserAddServiceInstance(
+               ServiceBrowserRef       inBrowser,
+               SBServiceBrowse *       inBrowse,
+               uint32_t                        inIfIndex,
+               const char *            inName,
+               const char *            inRegType,
+               const char *            inDomain,
+               uint64_t                        inDiscoverTimeUs );
+static OSStatus
+       _ServiceBrowserRemoveServiceInstance(
+               ServiceBrowserRef       inBrowser,
+               SBServiceBrowse *       inBrowse,
+               const char *            inName,
+               uint32_t                        inIfIndex );
+static OSStatus
+       _ServiceBrowserAddIPAddress(
+               ServiceBrowserRef               inBrowser,
+               SBServiceInstance *             inInstance,
+               const struct sockaddr * inSockAddr,
+               uint64_t                                inResolveTimeUs );
+static OSStatus
+       _ServiceBrowserRemoveIPAddress(
+               ServiceBrowserRef               inBrowser,
+               SBServiceInstance *             inInstance,
+               const struct sockaddr * inSockAddr );
+static OSStatus        _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults );
+static OSStatus        _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain );
+static void            _SBDomainFree( SBDomain *inDomain );
+static OSStatus        _SBServiceTypeCreate( const char *inName, SBServiceType **outType );
+static void            _SBServiceTypeFree( SBServiceType *inType );
+static OSStatus        _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse );
+static void            _SBServiceBrowseFree( SBServiceBrowse *inBrowse );
+static OSStatus
+       _SBServiceInstanceCreate(
+               const char *                    inName,
+               const char *                    inType,
+               const char *                    inDomain,
+               uint32_t                                inIfIndex,
+               uint64_t                                inDiscoverTimeUs,
+               ServiceBrowserRef               inBrowser,
+               SBServiceInstance **    outInstance );
+static void            _SBServiceInstanceFree( SBServiceInstance *inInstance );
+static OSStatus
+       _SBIPAddressCreate(
+               const struct sockaddr * inSockAddr,
+               uint64_t                                inResolveTimeUs,
+               SBIPAddress **                  outIPAddress );
+static void            _SBIPAddressFree( SBIPAddress *inIPAddress );
+static void            _SBIPAddressFreeList( SBIPAddress *inList );
+static OSStatus        _SBRDomainCreate( const char *inName, SBRDomain **outDomain );
+static void            _SBRDomainFree( SBRDomain *inDomain );
+static OSStatus        _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType );
+static void            _SBRServiceTypeFree( SBRServiceType *inType );
+static OSStatus
+       _SBRServiceInstanceCreate(
+               const char *                    inName,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               const uint8_t *                 inTXTPtr,
+               size_t                                  inTXTLen,
+               uint64_t                                inDiscoverTimeUs,
+               uint64_t                                inResolveTimeUs,
+               SBRServiceInstance **   outInstance );
+static void            _SBRServiceInstanceFree( SBRServiceInstance *inInstance );
+static OSStatus
+       _SBRIPAddressCreate(
+               const struct sockaddr * inSockAddr,
+               uint64_t                                inResolveTimeUs,
+               SBRIPAddress **                 outIPAddress );
+static void            _SBRIPAddressFree( SBRIPAddress *inIPAddress );
+
+#define ForgetSBIPAddressList( X )             ForgetCustom( X, _SBIPAddressFreeList )
+
+CF_CLASS_DEFINE( ServiceBrowser );
+
+ulog_define_ex( kDNSSDUtilIdentifier, ServiceBrowser, kLogLevelTrace, kLogFlags_None, "ServiceBrowser", NULL );
+#define sb_ulog( LEVEL, ... )          ulog( &log_category_from_name( ServiceBrowser ), (LEVEL), __VA_ARGS__ )
+
+static OSStatus
+       ServiceBrowserCreate(
+               dispatch_queue_t        inQueue,
+               uint32_t                        inInterfaceIndex,
+               const char *            inDomain,
+               unsigned int            inBrowseTimeSecs,
+               Boolean                         inIncludeAWDL,
+               ServiceBrowserRef *     outBrowser )
+{
+       OSStatus                                err;
+       ServiceBrowserRef               obj;
+       
+       CF_OBJECT_CREATE( ServiceBrowser, obj, err, exit );
+       
+       ReplaceDispatchQueue( &obj->queue, inQueue );
+       obj->ifIndex            = inInterfaceIndex;
+       if( inDomain )
+       {
+               obj->domain = strdup( inDomain );
+               require_action( obj->domain, exit, err = kNoMemoryErr );
+       }
+       obj->browseTimeSecs     = inBrowseTimeSecs;
+       obj->includeAWDL        = inIncludeAWDL;
+       
+       *outBrowser = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       CFReleaseNullSafe( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserFinalize
+//===========================================================================================================================
+
+static void    _ServiceBrowserFinalize( CFTypeRef inObj )
+{
+       ServiceBrowserRef const         me = (ServiceBrowserRef) inObj;
+       StringListItem *                        serviceType;
+       
+       dispatch_forget( &me->queue );
+       check( !me->connection );
+       check( !me->domainsQuery );
+       ForgetMem( &me->domain );
+       while( ( serviceType = me->serviceTypeList ) != NULL )
+       {
+               me->serviceTypeList = serviceType->next;
+               ForgetMem( &serviceType->str );
+               free( serviceType );
+       }
+       check( !me->domainList );
+       check( !me->stopTimer );
+}
+
+//===========================================================================================================================
+//     ServiceBrowserStart
+//===========================================================================================================================
+
+static void    _ServiceBrowserStart( void *inContext );
+
+static void    ServiceBrowserStart( ServiceBrowserRef me )
+{
+       CFRetain( me );
+       dispatch_async_f( me->queue, me, _ServiceBrowserStart );
+}
+
+static void    _ServiceBrowserStart( void *inContext )
+{
+       OSStatus                                        err;
+       ServiceBrowserRef const         me = (ServiceBrowserRef) inContext;
+       
+       err = DNSServiceCreateConnection( &me->connection );
+       require_noerr( err, exit );
+       
+       err = DNSServiceSetDispatchQueue( me->connection, me->queue );
+       require_noerr( err, exit );
+       
+       if( me->domain )
+       {
+               err = _ServiceBrowserAddDomain( me, me->domain );
+               require_noerr( err, exit );
+       }
+       else
+       {
+               DNSServiceRef                   sdRef;
+               const char * const              recordName      = "b._dns-sd._udp.local.";
+               const uint32_t                  ifIndex         = kDNSServiceInterfaceIndexLocalOnly;
+               
+               // Perform PTR meta-query for "b._dns-sd._udp.local." to enumerate recommended browsing domains.
+               // See <https://tools.ietf.org/html/rfc6763#section-11>.
+               
+               sb_ulog( kLogLevelTrace, "Starting PTR QueryRecord on interface %d for %s", (int32_t) ifIndex, recordName );
+               
+               sdRef = me->connection;
+               err = DNSServiceQueryRecord( &sdRef, kDNSServiceFlagsShareConnection, ifIndex, recordName,
+                       kDNSServiceType_PTR, kDNSServiceClass_IN, _ServiceBrowserDomainsQueryCallback, me );
+               require_noerr( err, exit );
+               
+               me->domainsQuery = sdRef;
+       }
+       
+       err = DispatchTimerCreate( dispatch_time_seconds( me->browseTimeSecs ), DISPATCH_TIME_FOREVER,
+               100 * kNanosecondsPerMillisecond, me->queue, _ServiceBrowserTimerHandler, NULL, me, &me->stopTimer );
+       require_noerr( err, exit );
+       dispatch_resume( me->stopTimer );
+       
+exit:
+       if( err ) _ServiceBrowserStop( me, err );
+}
+
+//===========================================================================================================================
+//     ServiceBrowserAddServiceType
+//===========================================================================================================================
+
+static OSStatus        ServiceBrowserAddServiceType( ServiceBrowserRef me, const char *inServiceType )
+{
+       OSStatus                                err;
+       StringListItem *                item;
+       StringListItem **               itemPtr;
+       StringListItem *                newItem = NULL;
+       
+       for( itemPtr = &me->serviceTypeList; ( item = *itemPtr ) != NULL; itemPtr = &item->next )
+       {
+               if( strcmp( item->str, inServiceType ) == 0 ) break;
+       }
+       if( !item )
+       {
+               newItem = (StringListItem *) calloc( 1, sizeof( *newItem ) );
+               require_action( newItem, exit, err = kNoMemoryErr );
+               
+               newItem->str = strdup( inServiceType );
+               require_action( newItem->str, exit, err = kNoMemoryErr );
+               
+               *itemPtr = newItem;
+               newItem = NULL;
+       }
+       err = kNoErr;
+       
+exit:
+       FreeNullSafe( newItem );
+       return( err );
+}
+
+//===========================================================================================================================
+//     ServiceBrowserSetCallback
+//===========================================================================================================================
+
+static void    ServiceBrowserSetCallback( ServiceBrowserRef me, ServiceBrowserCallback_f inCallback, void *inContext )
+{
+       me->userCallback        = inCallback;
+       me->userContext         = inContext;
+}
+
+//===========================================================================================================================
+//     ServiceBrowserResultsRetain
+//===========================================================================================================================
+
+static void    ServiceBrowserResultsRetain( ServiceBrowserResults *inResults )
+{
+       ServiceBrowserResultsPrivate * const            results = (ServiceBrowserResultsPrivate *) inResults;
+       
+       atomic_add_32( &results->refCount, 1 );
+}
+
+//===========================================================================================================================
+//     ServiceBrowserResultsRelease
+//===========================================================================================================================
+
+static void    ServiceBrowserResultsRelease( ServiceBrowserResults *inResults )
+{
+       ServiceBrowserResultsPrivate * const            results = (ServiceBrowserResultsPrivate *) inResults;
+       SBRDomain *                                                                     domain;
+       
+       if( atomic_add_and_fetch_32( &results->refCount, -1 ) == 0 )
+       {
+               while( ( domain = inResults->domainList ) != NULL )
+               {
+                       inResults->domainList = domain->next;
+                       _SBRDomainFree( domain );
+               }
+               free( inResults );
+       }
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserStop
+//===========================================================================================================================
+
+static void    _ServiceBrowserStop( ServiceBrowserRef me, OSStatus inError )
+{
+       OSStatus                                err;
+       SBDomain *                              d;
+       SBServiceType *                 t;
+       SBServiceBrowse *               b;
+       SBServiceInstance *             i;
+       
+       dispatch_source_forget( &me->stopTimer );
+       DNSServiceForget( &me->domainsQuery );
+       for( d = me->domainList; d; d = d->next )
+       {
+               DNSServiceForget( &d->servicesQuery );
+               for( t = d->typeList; t; t = t->next )
+               {
+                       for( b = t->browseList; b; b = b->next )
+                       {
+                               DNSServiceForget( &b->browse );
+                               for( i = b->instanceList; i; i = i->next )
+                               {
+                                       DNSServiceForget( &i->resolve );
+                                       DNSServiceForget( &i->getAddrInfo );
+                               }
+                       }
+               }
+       }
+       DNSServiceForget( &me->connection );
+       
+       if( me->userCallback )
+       {
+               ServiceBrowserResults *         results = NULL;
+               
+               err = _ServiceBrowserCreateResults( me, &results );
+               if( !err ) err = inError;
+               
+               me->userCallback( results, err, me->userContext );
+               me->userCallback        = NULL;
+               me->userContext         = NULL;
+               if( results ) ServiceBrowserResultsRelease( results );
+       }
+       
+       while( ( d = me->domainList ) != NULL )
+       {
+               me->domainList = d->next;
+               _SBDomainFree( d );
+       }
+       CFRelease( me );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserAddDomain
+//===========================================================================================================================
+
+static OSStatus        _ServiceBrowserAddDomain( ServiceBrowserRef me, const char *inDomain )
+{
+       OSStatus                err;
+       SBDomain *              domain;
+       SBDomain **             domainPtr;
+       SBDomain *              newDomain = NULL;
+       
+       for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
+       {
+               if( strcasecmp( domain->name, inDomain ) == 0 ) break;
+       }
+       require_action_quiet( !domain, exit, err = kDuplicateErr );
+       
+       err = _SBDomainCreate( inDomain, me, &newDomain );
+       require_noerr_quiet( err, exit );
+       
+       if( me->serviceTypeList )
+       {
+               const StringListItem *          item;
+               
+               for( item = me->serviceTypeList; item; item = item->next )
+               {
+                       err = _ServiceBrowserAddServiceType( me, newDomain, item->str, me->ifIndex );
+                       if( err == kDuplicateErr ) err = kNoErr;
+                       require_noerr( err, exit );
+               }
+       }
+       else
+       {
+               char *                          recordName;
+               DNSServiceRef           sdRef;
+               DNSServiceFlags         flags;
+               
+               // Perform PTR meta-query for _services._dns-sd._udp.<domain> to enumerate service types in domain.
+               // See <https://tools.ietf.org/html/rfc6763#section-9>.
+               
+               ASPrintF( &recordName, "_services._dns-sd._udp.%s", newDomain->name );
+               require_action( recordName, exit, err = kNoMemoryErr );
+               
+               flags = kDNSServiceFlagsShareConnection;
+               if( ( me->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+               
+               sb_ulog( kLogLevelTrace, "Starting PTR QueryRecord on interface %d for %s", (int32_t) me->ifIndex, recordName );
+               
+               sdRef = newDomain->browser->connection;
+               err = DNSServiceQueryRecord( &sdRef, flags, me->ifIndex, recordName, kDNSServiceType_PTR, kDNSServiceClass_IN,
+                       _ServiceBrowserServicesQueryCallback, newDomain );
+               free( recordName );
+               require_noerr( err, exit );
+               
+               newDomain->servicesQuery = sdRef;
+       }
+       
+       *domainPtr      = newDomain;
+       newDomain       = NULL;
+       err = kNoErr;
+       
+exit:
+       if( newDomain ) _SBDomainFree( newDomain );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserRemoveDomain
+//===========================================================================================================================
+
+static OSStatus        _ServiceBrowserRemoveDomain( ServiceBrowserRef me, const char *inName )
+{
+       OSStatus                err;
+       SBDomain *              domain;
+       SBDomain **             domainPtr;
+       
+       for( domainPtr = &me->domainList; ( domain = *domainPtr ) != NULL; domainPtr = &domain->next )
+       {
+               if( strcasecmp( domain->name, inName ) == 0 ) break;
+       }
+       
+       if( domain )
+       {
+               *domainPtr = domain->next;
+               _SBDomainFree( domain );
+               err = kNoErr;
+       }
+       else
+       {
+               err = kNotFoundErr;
+       }
+       
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserTimerHandler
+//===========================================================================================================================
+
+static void    _ServiceBrowserTimerHandler( void *inContext )
+{
+       ServiceBrowserRef const         me = (ServiceBrowserRef) inContext;
+       
+       _ServiceBrowserStop( me, kNoErr );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserDomainsQueryCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _ServiceBrowserDomainsQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       ServiceBrowserRef const         me = (ServiceBrowserRef) inContext;
+       OSStatus                                        err;
+       char                                            domainStr[ kDNSServiceMaxDomainName ];
+       
+       Unused( inSDRef );
+       Unused( inClass );
+       Unused( inTTL );
+       
+       sb_ulog( kLogLevelTrace, "QueryRecord result: %s on interface %d for %s -> %{du:rdata}%?{end} (error: %#m)",
+               DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, inFullName, inType, inRDataPtr, inRDataLen,
+               !inError, inError );
+       
+       require_noerr( inError, exit );
+       
+       err = DomainNameToString( inRDataPtr, ( (const uint8_t *) inRDataPtr ) + inRDataLen, domainStr, NULL );
+       require_noerr( err, exit );
+       
+       if( inFlags & kDNSServiceFlagsAdd )
+       {
+               err = _ServiceBrowserAddDomain( me, domainStr );
+               if( err == kDuplicateErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       else
+       {
+               err = _ServiceBrowserRemoveDomain( me, domainStr );
+               if( err == kNotFoundErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserServicesQueryCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _ServiceBrowserServicesQueryCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               uint16_t                                inType,
+               uint16_t                                inClass,
+               uint16_t                                inRDataLen,
+               const void *                    inRDataPtr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                                        err;
+       SBDomain * const                        domain  = (SBDomain *) inContext;
+       ServiceBrowserRef const         me              = domain->browser;
+       const uint8_t *                         src;
+       const uint8_t *                         end;
+       uint8_t *                                       dst;
+       int                                                     i;
+       uint8_t                                         serviceType[ 2 * ( 1 + kDomainLabelLengthMax ) + 1 ];
+       char                                            serviceTypeStr[ kDNSServiceMaxDomainName ];
+       
+       Unused( inSDRef );
+       Unused( inTTL );
+       Unused( inClass );
+       
+       sb_ulog( kLogLevelTrace, "QueryRecord result: %s on interface %d for %s -> %{du:rdata}%?{end} (error: %#m)",
+               DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, inFullName, inType, inRDataPtr, inRDataLen,
+               !inError, inError );
+       
+       require_noerr( inError, exit );
+       
+       check( inType  == kDNSServiceType_PTR );
+       check( inClass == kDNSServiceClass_IN );
+       
+       // The first two labels of the domain name in the RDATA describe a service type.
+       // See <https://tools.ietf.org/html/rfc6763#section-9>.
+       
+       src = (const uint8_t *) inRDataPtr;
+       end = src + inRDataLen;
+       dst = serviceType;
+       for( i = 0; i < 2; ++i )
+       {
+               size_t          labelLen;
+               
+               require_action_quiet( ( end - src ) > 0, exit, err = kUnderrunErr );
+               
+               labelLen = *src;
+               require_action_quiet( ( labelLen > 0 ) && ( labelLen <= kDomainLabelLengthMax ), exit, err = kMalformedErr );
+               require_action_quiet( ( (size_t)( end - src ) ) >= ( 1 + labelLen ), exit, err = kUnderrunErr );
+               
+               memcpy( dst, src, 1 + labelLen );
+               src += 1 + labelLen;
+               dst += 1 + labelLen;
+       }
+       *dst = 0;
+       
+       err = DomainNameToString( serviceType, NULL, serviceTypeStr, NULL );
+       require_noerr( err, exit );
+       
+       if( inFlags & kDNSServiceFlagsAdd )
+       {
+               err = _ServiceBrowserAddServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
+               if( err == kDuplicateErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       else
+       {
+               err = _ServiceBrowserRemoveServiceType( me, domain, serviceTypeStr, inInterfaceIndex );
+               if( err == kNotFoundErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserBrowseCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _ServiceBrowserBrowseCallback(
+               DNSServiceRef           inSDRef,
+               DNSServiceFlags         inFlags,
+               uint32_t                        inInterfaceIndex,
+               DNSServiceErrorType     inError,
+               const char *            inName,
+               const char *            inRegType,
+               const char *            inDomain,
+               void *                          inContext )
+{
+       OSStatus                                        err;
+       const uint64_t                          nowTicks        = UpTicks();
+       SBServiceBrowse * const         browse          = (SBServiceBrowse *) inContext;
+       ServiceBrowserRef const         me                      = (ServiceBrowserRef) browse->browser;
+       
+       Unused( inSDRef );
+       
+       sb_ulog( kLogLevelTrace, "Browse result: %s on interface %d for %s.%s%s%?{end} (error: %#m)",
+               DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, inName, inRegType, inDomain, !inError, inError );
+       
+       require_noerr( inError, exit );
+       
+       if( inFlags & kDNSServiceFlagsAdd )
+       {
+               err = _ServiceBrowserAddServiceInstance( me, browse, inInterfaceIndex, inName, inRegType, inDomain,
+                       UpTicksToMicroseconds( nowTicks - browse->startTicks ) );
+               if( err == kDuplicateErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       else
+       {
+               err = _ServiceBrowserRemoveServiceInstance( me, browse, inName, inInterfaceIndex );
+               if( err == kNotFoundErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserResolveCallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _ServiceBrowserResolveCallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inFullName,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               uint16_t                                inTXTLen,
+               const unsigned char *   inTXTPtr,
+               void *                                  inContext )
+{
+       OSStatus                                                err;
+       const uint64_t                                  nowTicks        = UpTicks();
+       SBServiceInstance * const               instance        = (SBServiceInstance *) inContext;
+       ServiceBrowserRef const                 me                      = (ServiceBrowserRef) instance->browser;
+       
+       Unused( inSDRef );
+       Unused( inFlags );
+       
+       sb_ulog( kLogLevelTrace, "Resolve result on interface %d for %s -> %s:%u %#{txt}%?{end} (error %#m)",
+               (int32_t) inInterfaceIndex, inFullName, inHostname, inPort, inTXTPtr, (size_t) inTXTLen, !inError, inError );
+       
+       require_noerr( inError, exit );
+       
+       if( !MemEqual( instance->txtPtr, instance->txtLen, inTXTPtr, inTXTLen ) )
+       {
+               FreeNullSafe( instance->txtPtr );
+               instance->txtPtr = _memdup( inTXTPtr, inTXTLen );
+               require_action( instance->txtPtr, exit, err = kNoMemoryErr );
+               
+               instance->txtLen = inTXTLen;
+       }
+       
+       instance->port = ntohs( inPort );
+       
+       if( !instance->hostname || ( strcasecmp( instance->hostname, inHostname ) != 0 ) )
+       {
+               DNSServiceRef           sdRef;
+               
+               if( !instance->hostname ) instance->resolveTimeUs = UpTicksToMicroseconds( nowTicks - instance->resolveStartTicks );
+               
+               err = ReplaceString( &instance->hostname, NULL, inHostname, kSizeCString );
+               require_noerr( err, exit );
+               
+               DNSServiceForget( &instance->getAddrInfo );
+               ForgetSBIPAddressList( &instance->ipaddrList );
+               
+               sb_ulog( kLogLevelTrace, "Starting GetAddrInfo on interface %d for %s",
+                       (int32_t) instance->ifIndex, instance->hostname );
+               
+               sdRef = me->connection;
+               instance->gaiStartTicks = UpTicks();
+               err = DNSServiceGetAddrInfo( &sdRef, kDNSServiceFlagsShareConnection, instance->ifIndex,
+                       kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6, instance->hostname, _ServiceBrowserGAICallback, instance );
+               require_noerr( err, exit );
+               
+               instance->getAddrInfo = sdRef;
+       }
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserGAICallback
+//===========================================================================================================================
+
+static void DNSSD_API
+       _ServiceBrowserGAICallback(
+               DNSServiceRef                   inSDRef,
+               DNSServiceFlags                 inFlags,
+               uint32_t                                inInterfaceIndex,
+               DNSServiceErrorType             inError,
+               const char *                    inHostname,
+               const struct sockaddr * inSockAddr,
+               uint32_t                                inTTL,
+               void *                                  inContext )
+{
+       OSStatus                                                err;
+       const uint64_t                                  nowTicks        = UpTicks();
+       SBServiceInstance * const               instance        = (SBServiceInstance *) inContext;
+       ServiceBrowserRef const                 me                      = (ServiceBrowserRef) instance->browser;
+       
+       Unused( inSDRef );
+       Unused( inTTL );
+       
+       sb_ulog( kLogLevelTrace, "GetAddrInfo result: %s on interface %d for (%s ->) %s -> %##a%?{end} (error: %#m)",
+               DNSServiceFlagsToAddRmvStr( inFlags ), (int32_t) inInterfaceIndex, instance->fqdn, inHostname, inSockAddr,
+               !inError, inError );
+       
+       require_noerr( inError, exit );
+       
+       if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+       {
+               dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+               goto exit;
+       }
+       
+       if( inFlags & kDNSServiceFlagsAdd )
+       {
+               err = _ServiceBrowserAddIPAddress( me, instance, inSockAddr,
+                       UpTicksToMicroseconds( nowTicks - instance->gaiStartTicks ) );
+               if( err == kDuplicateErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       else
+       {
+               err = _ServiceBrowserRemoveIPAddress( me, instance, inSockAddr );
+               if( err == kNotFoundErr ) err = kNoErr;
+               require_noerr( err, exit );
+       }
+       
+exit:
+       return;
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserAddServiceType
+//===========================================================================================================================
+
+static OSStatus
+       _ServiceBrowserAddServiceType(
+               ServiceBrowserRef       me,
+               SBDomain *                      inDomain,
+               const char *            inName,
+               uint32_t                        inIfIndex )
+{
+       OSStatus                                err;
+       SBServiceType *                 type;
+       SBServiceType **                typePtr;
+       SBServiceType *                 newType         = NULL;
+       SBServiceBrowse *               browse;
+       SBServiceBrowse **              browsePtr;
+       SBServiceBrowse *               newBrowse       = NULL;
+       DNSServiceRef                   sdRef;
+       DNSServiceFlags                 flags;
+       
+       for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
+       {
+               if( strcasecmp( type->name, inName ) == 0 ) break;
+       }
+       if( !type )
+       {
+               err = _SBServiceTypeCreate( inName, &newType );
+               require_noerr_quiet( err, exit );
+               
+               type = newType;
+       }
+       
+       for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
+       {
+               if( browse->ifIndex == inIfIndex ) break;
+       }
+       require_action_quiet( !browse, exit, err = kDuplicateErr );
+       
+       err = _SBServiceBrowseCreate( inIfIndex, me, &newBrowse );
+       require_noerr_quiet( err, exit );
+       
+       flags = kDNSServiceFlagsShareConnection;
+       if( ( newBrowse->ifIndex == kDNSServiceInterfaceIndexAny ) && me->includeAWDL ) flags |= kDNSServiceFlagsIncludeAWDL;
+       
+       sb_ulog( kLogLevelTrace, "Starting Browse on interface %d for %s%s",
+               (int32_t) newBrowse->ifIndex, type->name, inDomain->name );
+       
+       sdRef = me->connection;
+       newBrowse->startTicks = UpTicks();
+       err = DNSServiceBrowse( &sdRef, flags, newBrowse->ifIndex, type->name, inDomain->name, _ServiceBrowserBrowseCallback,
+               newBrowse );
+       require_noerr( err, exit );
+       
+       newBrowse->browse = sdRef;
+       *browsePtr      = newBrowse;
+       newBrowse       = NULL;
+       
+       if( newType )
+       {
+               *typePtr        = newType;
+               newType         = NULL;
+       }
+       
+exit:
+       if( newBrowse ) _SBServiceBrowseFree( newBrowse );
+       if( newType )   _SBServiceTypeFree( newType );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserRemoveServiceType
+//===========================================================================================================================
+
+static OSStatus
+       _ServiceBrowserRemoveServiceType(
+               ServiceBrowserRef       me,
+               SBDomain *                      inDomain,
+               const char *            inName,
+               uint32_t                        inIfIndex )
+{
+       OSStatus                                err;
+       SBServiceType *                 type;
+       SBServiceType **                typePtr;
+       SBServiceBrowse *               browse;
+       SBServiceBrowse **              browsePtr;
+       
+       Unused( me );
+       
+       for( typePtr = &inDomain->typeList; ( type = *typePtr ) != NULL; typePtr = &type->next )
+       {
+               if( strcasecmp( type->name, inName ) == 0 ) break;
+       }
+       require_action_quiet( type, exit, err = kNotFoundErr );
+       
+       for( browsePtr = &type->browseList; ( browse = *browsePtr ) != NULL; browsePtr = &browse->next )
+       {
+               if( browse->ifIndex == inIfIndex ) break;
+       }
+       require_action_quiet( browse, exit, err = kNotFoundErr );
+       
+       *browsePtr = browse->next;
+       _SBServiceBrowseFree( browse );
+       if( !type->browseList )
+       {
+               *typePtr = type->next;
+               _SBServiceTypeFree( type );
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserAddServiceInstance
+//===========================================================================================================================
+
+static OSStatus
+       _ServiceBrowserAddServiceInstance(
+               ServiceBrowserRef       me,
+               SBServiceBrowse *       inBrowse,
+               uint32_t                        inIfIndex,
+               const char *            inName,
+               const char *            inRegType,
+               const char *            inDomain,
+               uint64_t                        inDiscoverTimeUs )
+{
+       OSStatus                                        err;
+       DNSServiceRef                           sdRef;
+       SBServiceInstance *                     instance;
+       SBServiceInstance **            instancePtr;
+       SBServiceInstance *                     newInstance     = NULL;
+       
+       for( instancePtr = &inBrowse->instanceList; ( instance = *instancePtr ) != NULL; instancePtr = &instance->next )
+       {
+               if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
+       }
+       require_action_quiet( !instance, exit, err = kDuplicateErr );
+       
+       err = _SBServiceInstanceCreate( inName, inRegType, inDomain, inIfIndex, inDiscoverTimeUs, me, &newInstance );
+       require_noerr_quiet( err, exit );
+       
+       sb_ulog( kLogLevelTrace, "Starting Resolve on interface %d for %s.%s%s",
+               (int32_t) newInstance->ifIndex, inName, inRegType, inDomain );
+       
+       sdRef = me->connection;
+       newInstance->resolveStartTicks = UpTicks();
+       err = DNSServiceResolve( &sdRef, kDNSServiceFlagsShareConnection, newInstance->ifIndex, inName, inRegType, inDomain,
+               _ServiceBrowserResolveCallback, newInstance );
+       require_noerr( err, exit );
+       
+       newInstance->resolve = sdRef;
+       *instancePtr    = newInstance;
+       newInstance             = NULL;
+       
+exit:
+       if( newInstance ) _SBServiceInstanceFree( newInstance );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserRemoveServiceInstance
+//===========================================================================================================================
+
+static OSStatus
+       _ServiceBrowserRemoveServiceInstance(
+               ServiceBrowserRef       me,
+               SBServiceBrowse *       inBrowse,
+               const char *            inName,
+               uint32_t                        inIfIndex )
+{
+       OSStatus                                        err;
+       SBServiceInstance *                     instance;
+       SBServiceInstance **            ptr;
+       
+       Unused( me );
+       
+       for( ptr = &inBrowse->instanceList; ( instance = *ptr ) != NULL; ptr = &instance->next )
+       {
+               if( ( instance->ifIndex == inIfIndex ) && ( strcasecmp( instance->name, inName ) == 0 ) ) break;
+       }
+       require_action_quiet( instance, exit, err = kNotFoundErr );
+       
+       *ptr = instance->next;
+       _SBServiceInstanceFree( instance );
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserAddIPAddress
+//===========================================================================================================================
+
+static OSStatus
+       _ServiceBrowserAddIPAddress(
+               ServiceBrowserRef               me,
+               SBServiceInstance *             inInstance,
+               const struct sockaddr * inSockAddr,
+               uint64_t                                inResolveTimeUs )
+{
+       OSStatus                        err;
+       SBIPAddress *           ipaddr;
+       SBIPAddress **          ipaddrPtr;
+       SBIPAddress *           newIPAddr = NULL;
+       
+       Unused( me );
+       
+       if( ( inSockAddr->sa_family != AF_INET ) && ( inSockAddr->sa_family != AF_INET6 ) )
+       {
+               dlogassert( "Unexpected address family: %d", inSockAddr->sa_family );
+               err = kTypeErr;
+               goto exit;
+       }
+       
+       for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
+       {
+               if( SockAddrCompareAddr( &ipaddr->sip, inSockAddr ) == 0 ) break;
+       }
+       require_action_quiet( !ipaddr, exit, err = kDuplicateErr );
+       
+       err = _SBIPAddressCreate( inSockAddr, inResolveTimeUs, &newIPAddr );
+       require_noerr_quiet( err, exit );
+       
+       *ipaddrPtr = newIPAddr;
+       newIPAddr = NULL;
+       err = kNoErr;
+       
+exit:
+       if( newIPAddr ) _SBIPAddressFree( newIPAddr );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserRemoveIPAddress
+//===========================================================================================================================
+
+static OSStatus
+       _ServiceBrowserRemoveIPAddress(
+               ServiceBrowserRef               me,
+               SBServiceInstance *             inInstance,
+               const struct sockaddr * inSockAddr )
+{
+       OSStatus                        err;
+       SBIPAddress *           ipaddr;
+       SBIPAddress **          ipaddrPtr;
+       
+       Unused( me );
+       
+       for( ipaddrPtr = &inInstance->ipaddrList; ( ipaddr = *ipaddrPtr ) != NULL; ipaddrPtr = &ipaddr->next )
+       {
+               if( SockAddrCompareAddr( &ipaddr->sip.sa, inSockAddr ) == 0 ) break;
+       }
+       require_action_quiet( ipaddr, exit, err = kNotFoundErr );
+       
+       *ipaddrPtr = ipaddr->next;
+       _SBIPAddressFree( ipaddr );
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ServiceBrowserCreateResults
+//===========================================================================================================================
+
+static OSStatus        _ServiceBrowserCreateResults( ServiceBrowserRef me, ServiceBrowserResults **outResults )
+{
+       OSStatus                                                        err;
+       SBDomain *                                                      d;
+       SBServiceType *                                         t;
+       SBServiceBrowse *                                       b;
+       SBServiceInstance *                                     i;
+       SBIPAddress *                                           a;
+       ServiceBrowserResultsPrivate *          results;
+       SBRDomain **                                            domainPtr;
+       
+       results = (ServiceBrowserResultsPrivate *) calloc( 1, sizeof( *results ) );
+       require_action( results, exit, err = kNoMemoryErr );
+       
+       results->refCount = 1;
+       
+       domainPtr = &results->domainList;
+       for( d = me->domainList; d; d = d->next )
+       {
+               SBRDomain *                             domain;
+               SBRServiceType **               typePtr;
+               
+               err = _SBRDomainCreate( d->name, &domain );
+               require_noerr_quiet( err, exit );
+               *domainPtr = domain;
+                domainPtr = &domain->next;
+               
+               typePtr = &domain->typeList;
+               for( t = d->typeList; t; t = t->next )
+               {
+                       SBRServiceType *                        type;
+                       SBRServiceInstance **           instancePtr;
+                       
+                       err = _SBRServiceTypeCreate( t->name, &type );
+                       require_noerr_quiet( err, exit );
+                       *typePtr = type;
+                        typePtr = &type->next;
+                       
+                       instancePtr = &type->instanceList;
+                       for( b = t->browseList; b; b = b->next )
+                       {
+                               for( i = b->instanceList; i; i = i->next )
+                               {
+                                       SBRServiceInstance *            instance;
+                                       SBRIPAddress **                         ipaddrPtr;
+                                       
+                                       err = _SBRServiceInstanceCreate( i->name, i->ifIndex, i->hostname, i->port, i->txtPtr, i->txtLen,
+                                               i->discoverTimeUs, i->resolveTimeUs, &instance );
+                                       require_noerr_quiet( err, exit );
+                                       *instancePtr = instance;
+                                        instancePtr = &instance->next;
+                                       
+                                       ipaddrPtr = &instance->ipaddrList;
+                                       for( a = i->ipaddrList; a; a = a->next )
+                                       {
+                                               SBRIPAddress *          ipaddr;
+                                               
+                                               err = _SBRIPAddressCreate( &a->sip.sa, a->resolveTimeUs, &ipaddr );
+                                               require_noerr_quiet( err, exit );
+                                               
+                                               *ipaddrPtr = ipaddr;
+                                                ipaddrPtr = &ipaddr->next;
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       *outResults = (ServiceBrowserResults *) results;
+       results = NULL;
+       err = kNoErr;
+       
+exit:
+       if( results ) ServiceBrowserResultsRelease( (ServiceBrowserResults *) results );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBDomainCreate
+//===========================================================================================================================
+
+static OSStatus        _SBDomainCreate( const char *inName, ServiceBrowserRef inBrowser, SBDomain **outDomain )
+{
+       OSStatus                err;
+       SBDomain *              obj;
+       
+       obj = (SBDomain *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name = strdup( inName );
+       require_action( obj->name, exit, err = kNoMemoryErr );
+       
+       obj->browser = inBrowser;
+       
+       *outDomain = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _SBDomainFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBDomainFree
+//===========================================================================================================================
+
+static void    _SBDomainFree( SBDomain *inDomain )
+{
+       SBServiceType *         type;
+       
+       ForgetMem( &inDomain->name );
+       DNSServiceForget( &inDomain->servicesQuery );
+       while( ( type = inDomain->typeList ) != NULL )
+       {
+               inDomain->typeList = type->next;
+               _SBServiceTypeFree( type );
+       }
+       free( inDomain );
+}
+
+//===========================================================================================================================
+//     _SBServiceTypeCreate
+//===========================================================================================================================
+
+static OSStatus        _SBServiceTypeCreate( const char *inName, SBServiceType **outType )
+{
+       OSStatus                        err;
+       SBServiceType *         obj;
+       
+       obj = (SBServiceType *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name = strdup( inName );
+       require_action( obj->name, exit, err = kNoMemoryErr );
+       
+       *outType = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _SBServiceTypeFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBServiceTypeFree
+//===========================================================================================================================
+
+static void    _SBServiceTypeFree( SBServiceType *inType )
+{
+       SBServiceBrowse *               browse;
+       
+       ForgetMem( &inType->name );
+       while( ( browse = inType->browseList ) != NULL )
+       {
+               inType->browseList = browse->next;
+               _SBServiceBrowseFree( browse );
+       }
+       free( inType );
+}
+
+//===========================================================================================================================
+//     _SBServiceBrowseCreate
+//===========================================================================================================================
+
+static OSStatus        _SBServiceBrowseCreate( uint32_t inIfIndex, ServiceBrowserRef inBrowser, SBServiceBrowse **outBrowse )
+{
+       OSStatus                                err;
+       SBServiceBrowse *               obj;
+       
+       obj = (SBServiceBrowse *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->ifIndex = inIfIndex;
+       obj->browser = inBrowser;
+       *outBrowse = obj;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBServiceBrowseFree
+//===========================================================================================================================
+
+static void    _SBServiceBrowseFree( SBServiceBrowse *inBrowse )
+{
+       SBServiceInstance *             instance;
+       
+       DNSServiceForget( &inBrowse->browse );
+       while( ( instance = inBrowse->instanceList ) != NULL )
+       {
+               inBrowse->instanceList = instance->next;
+               _SBServiceInstanceFree( instance );
+       }
+       free( inBrowse );
+}
+
+//===========================================================================================================================
+//     _SBServiceInstanceCreate
+//===========================================================================================================================
+
+static OSStatus
+       _SBServiceInstanceCreate(
+               const char *                    inName,
+               const char *                    inType,
+               const char *                    inDomain,
+               uint32_t                                inIfIndex,
+               uint64_t                                inDiscoverTimeUs,
+               ServiceBrowserRef               inBrowser,
+               SBServiceInstance **    outInstance )
+{
+       OSStatus                                err;
+       SBServiceInstance *             obj;
+       
+       obj = (SBServiceInstance *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name = strdup( inName );
+       require_action( obj->name, exit, err = kNoMemoryErr );
+       
+       ASPrintF( &obj->fqdn, "%s.%s%s", obj->name, inType, inDomain );
+       require_action( obj->fqdn, exit, err = kNoMemoryErr );
+       
+       obj->ifIndex            = inIfIndex;
+       obj->discoverTimeUs     = inDiscoverTimeUs;
+       obj->browser            = inBrowser;
+       
+       *outInstance = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _SBServiceInstanceFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBServiceInstanceFree
+//===========================================================================================================================
+
+static void    _SBServiceInstanceFree( SBServiceInstance *inInstance )
+{
+       ForgetMem( &inInstance->name );
+       ForgetMem( &inInstance->fqdn );
+       DNSServiceForget( &inInstance->resolve );
+       ForgetMem( &inInstance->hostname );
+       ForgetMem( &inInstance->txtPtr );
+       DNSServiceForget( &inInstance->getAddrInfo );
+       ForgetSBIPAddressList( &inInstance->ipaddrList );
+       free( inInstance );
+}
+
+//===========================================================================================================================
+//     _SBIPAddressCreate
+//===========================================================================================================================
+
+static OSStatus        _SBIPAddressCreate( const struct sockaddr *inSockAddr, uint64_t inResolveTimeUs, SBIPAddress **outIPAddress )
+{
+       OSStatus                        err;
+       SBIPAddress *           obj;
+       
+       obj = (SBIPAddress *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       SockAddrCopy( inSockAddr, &obj->sip );
+       obj->resolveTimeUs = inResolveTimeUs;
+       
+       *outIPAddress = obj;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBIPAddressFree
+//===========================================================================================================================
+
+static void _SBIPAddressFree( SBIPAddress *inIPAddress )
+{
+       free( inIPAddress );
+}
+
+//===========================================================================================================================
+//     _SBIPAddressFreeList
+//===========================================================================================================================
+
+static void    _SBIPAddressFreeList( SBIPAddress *inList )
+{
+       SBIPAddress *           ipaddr;
+       
+       while( ( ipaddr = inList ) != NULL )
+       {
+               inList = ipaddr->next;
+               _SBIPAddressFree( ipaddr );
+       }
+}
+
+//===========================================================================================================================
+//     _SBRDomainCreate
+//===========================================================================================================================
+
+static OSStatus        _SBRDomainCreate( const char *inName, SBRDomain **outDomain )
+{
+       OSStatus                err;
+       SBRDomain *             obj;
+       
+       obj = (SBRDomain *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name = strdup( inName );
+       require_action( obj->name, exit, err = kNoMemoryErr );
+       
+       *outDomain = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _SBRDomainFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBRDomainFree
+//===========================================================================================================================
+
+static void    _SBRDomainFree( SBRDomain *inDomain )
+{
+       SBRServiceType *                type;
+       
+       ForgetMem( &inDomain->name );
+       while( ( type = inDomain->typeList ) != NULL )
+       {
+               inDomain->typeList = type->next;
+               _SBRServiceTypeFree( type );
+       }
+       free( inDomain );
+}
+
+//===========================================================================================================================
+//     _SBRServiceTypeCreate
+//===========================================================================================================================
+
+static OSStatus        _SBRServiceTypeCreate( const char *inName, SBRServiceType **outType )
+{
+       OSStatus                                err;
+       SBRServiceType *                obj;
+       
+       obj = (SBRServiceType *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name = strdup( inName );
+       require_action( obj->name, exit, err = kNoMemoryErr );
+       
+       *outType = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _SBRServiceTypeFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBRServiceTypeFree
+//===========================================================================================================================
+
+static void    _SBRServiceTypeFree( SBRServiceType *inType )
+{
+       SBRServiceInstance *            instance;
+       
+       ForgetMem( &inType->name );
+       while( ( instance = inType->instanceList ) != NULL )
+       {
+               inType->instanceList = instance->next;
+               _SBRServiceInstanceFree( instance );
+       }
+       free( inType );
+}
+
+//===========================================================================================================================
+//     _SBRServiceInstanceCreate
+//===========================================================================================================================
+
+static OSStatus
+       _SBRServiceInstanceCreate(
+               const char *                    inName,
+               uint32_t                                inInterfaceIndex,
+               const char *                    inHostname,
+               uint16_t                                inPort,
+               const uint8_t *                 inTXTPtr,
+               size_t                                  inTXTLen,
+               uint64_t                                inDiscoverTimeUs,
+               uint64_t                                inResolveTimeUs,
+               SBRServiceInstance **   outInstance )
+{
+       OSStatus                                        err;
+       SBRServiceInstance *            obj;
+       
+       obj = (SBRServiceInstance *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       obj->name = strdup( inName );
+       require_action( obj->name, exit, err = kNoMemoryErr );
+       
+       if( inHostname )
+       {
+               obj->hostname = strdup( inHostname );
+               require_action( obj->hostname, exit, err = kNoMemoryErr );
+       }
+       if( inTXTLen > 0 )
+       {
+               obj->txtPtr = (uint8_t *) _memdup( inTXTPtr, inTXTLen );
+               require_action( obj->txtPtr, exit, err = kNoMemoryErr );
+               obj->txtLen = inTXTLen;
+       }
+       obj->discoverTimeUs     = inDiscoverTimeUs;
+       obj->resolveTimeUs      = inResolveTimeUs;
+       obj->ifIndex            = inInterfaceIndex;
+       obj->port                       = inPort;
+       
+       *outInstance = obj;
+       obj = NULL;
+       err = kNoErr;
+       
+exit:
+       if( obj ) _SBRServiceInstanceFree( obj );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBRServiceInstanceFree
+//===========================================================================================================================
+
+static void    _SBRServiceInstanceFree( SBRServiceInstance *inInstance )
+{
+       SBRIPAddress *          ipaddr;
+       
+       ForgetMem( &inInstance->name );
+       ForgetMem( &inInstance->hostname );
+       ForgetMem( &inInstance->txtPtr );
+       while( ( ipaddr = inInstance->ipaddrList ) != NULL )
+       {
+               inInstance->ipaddrList = ipaddr->next;
+               _SBRIPAddressFree( ipaddr );
+       }
+       free( inInstance );
+}
+
+//===========================================================================================================================
+//     _SBRIPAddressCreate
+//===========================================================================================================================
+
+static OSStatus
+       _SBRIPAddressCreate(
+               const struct sockaddr * inSockAddr,
+               uint64_t                                inResolveTimeUs,
+               SBRIPAddress **                 outIPAddress )
+{
+       OSStatus                        err;
+       SBRIPAddress *          obj;
+       
+       obj = (SBRIPAddress *) calloc( 1, sizeof( *obj ) );
+       require_action( obj, exit, err = kNoMemoryErr );
+       
+       SockAddrCopy( inSockAddr, &obj->sip );
+       obj->resolveTimeUs = inResolveTimeUs;
+       
+       *outIPAddress = obj;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _SBRIPAddressFree
+//===========================================================================================================================
+
+static void    _SBRIPAddressFree( SBRIPAddress *inIPAddress )
+{
+       free( inIPAddress );
+}
+
+//===========================================================================================================================
+//     _SocketWriteAll
+//
+//     Note: This was copied from CoreUtils because the SocketWriteAll function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus        _SocketWriteAll( SocketRef inSock, const void *inData, size_t inSize, int32_t inTimeoutSecs )
+{
+       OSStatus                        err;
+       const uint8_t *         src;
+       const uint8_t *         end;
+       fd_set                          writeSet;
+       struct timeval          timeout;
+       ssize_t                         n;
+       
+       FD_ZERO( &writeSet );
+       src = (const uint8_t *) inData;
+       end = src + inSize;
+       while( src < end )
+       {
+               FD_SET( inSock, &writeSet );
+               timeout.tv_sec  = inTimeoutSecs;
+               timeout.tv_usec = 0;
+               n = select( (int)( inSock + 1 ), NULL, &writeSet, NULL, &timeout );
+               if( n == 0 ) { err = kTimeoutErr; goto exit; }
+               err = map_socket_value_errno( inSock, n > 0, n );
+               require_noerr( err, exit );
+               
+               n = send( inSock, (char *) src, (size_t)( end - src ), 0 );
+               err = map_socket_value_errno( inSock, n >= 0, n );
+               if( err == EINTR ) continue;
+               require_noerr( err, exit );
+               
+               src += n;
+       }
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ParseIPv4Address
+//
+//     Warning: "inBuffer" may be modified even in error cases.
+//
+//     Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus        _ParseIPv4Address( const char *inStr, uint8_t inBuffer[ 4 ], const char **outStr )
+{
+       OSStatus                err;
+       uint8_t *               dst;
+       int                             segments;
+       int                             sawDigit;
+       int                             c;
+       int                             v;
+       
+       check( inBuffer );
+       check( outStr );
+       
+       dst              = inBuffer;
+       *dst     = 0;
+       sawDigit = 0;
+       segments = 0;
+       for( ; ( c = *inStr ) != '\0'; ++inStr )
+       {
+               if( isdigit_safe( c ) )
+               {
+                       v = ( *dst * 10 ) + ( c - '0' );
+                       require_action_quiet( v <= 255, exit, err = kRangeErr );
+                       *dst = (uint8_t) v;
+                       if( !sawDigit )
+                       {
+                               ++segments;
+                               require_action_quiet( segments <= 4, exit, err = kOverrunErr );
+                               sawDigit = 1;
+                       }
+               }
+               else if( ( c == '.' ) && sawDigit )
+               {
+                       require_action_quiet( segments < 4, exit, err = kMalformedErr );
+                       *++dst = 0;
+                       sawDigit = 0;
+               }
+               else
+               {
+                       break;
+               }
+       }
+       require_action_quiet( segments == 4, exit, err = kUnderrunErr );
+       
+       *outStr = inStr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _StringToIPv4Address
+//
+//     Note: This was copied from CoreUtils because the StringToIPv4Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus
+       _StringToIPv4Address( 
+               const char *                    inStr, 
+               StringToIPAddressFlags  inFlags, 
+               uint32_t *                              outIP, 
+               int *                                   outPort, 
+               uint32_t *                              outSubnet, 
+               uint32_t *                              outRouter, 
+               const char **                   outStr )
+{
+       OSStatus                        err;
+       uint8_t                         buf[ 4 ];
+       int                                     c;
+       uint32_t                        ip;
+       int                                     hasPort;
+       int                                     port;
+       int                                     hasPrefix;
+       int                                     prefix;
+       uint32_t                        subnetMask;
+       uint32_t                        router;
+       
+       require_action( inStr, exit, err = kParamErr );
+       
+       // Parse the address-only part of the address (e.g. "1.2.3.4").
+       
+       err = _ParseIPv4Address( inStr, buf, &inStr );
+       require_noerr_quiet( err, exit );
+       ip = (uint32_t)( ( buf[ 0 ] << 24 ) | ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ] );
+       c = *inStr;
+       
+       // Parse the port (if any).
+       
+       hasPort = 0;
+       port    = 0;
+       if( c == ':' )
+       {
+               require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
+               while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
+               require_action_quiet( port <= 65535, exit, err = kRangeErr );
+               hasPort = 1;
+       }
+       
+       // Parse the prefix length (if any).
+       
+       hasPrefix  = 0;
+       prefix     = 0;
+       subnetMask = 0;
+       router     = 0;
+       if( c == '/' )
+       {
+               require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
+               while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
+               require_action_quiet( ( prefix >= 0 ) && ( prefix <= 32 ), exit, err = kRangeErr );
+               hasPrefix = 1;
+               
+               subnetMask = ( prefix > 0 ) ? ( UINT32_C( 0xFFFFFFFF ) << ( 32 - prefix ) ) : 0;
+               router     = ( ip & subnetMask ) | 1;
+       }
+       
+       // Return the results. Only fill in port/prefix/router results if the info was found to allow for defaults.
+       
+       if( outIP )                                      *outIP         = ip;
+       if( outPort   && hasPort )       *outPort       = port;
+       if( outSubnet && hasPrefix ) *outSubnet = subnetMask;
+       if( outRouter && hasPrefix ) *outRouter = router;
+       if( outStr )                             *outStr        = inStr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ParseIPv6Address
+//
+//     Note: Parsed according to the rules specified in RFC 3513.
+//     Warning: "inBuffer" may be modified even in error cases.
+//
+//     Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus        _ParseIPv6Address( const char *inStr, int inAllowV4Mapped, uint8_t inBuffer[ 16 ], const char **outStr )
+{
+                                                                                                       // Table to map uppercase hex characters - '0' to their numeric values.
+                                                                                                       // 0  1  2  3  4  5  6  7  8  9  :  ;  <  =  >  ?  @  A   B   C   D   E   F
+       static const uint8_t            kASCIItoHexTable[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15 };
+       OSStatus                                        err;
+       const char *                            ptr;
+       uint8_t *                                       dst;
+       uint8_t *                                       lim;
+       uint8_t *                                       colonPtr;
+       int                                                     c;
+       int                                                     sawDigit;
+       unsigned int                            v;
+       int                                                     i;
+       int                                                     n;
+       
+       // Pre-zero the address to simplify handling of compressed addresses (e.g. "::1").
+       
+       for( i = 0; i < 16; ++i ) inBuffer[ i ] = 0;
+       
+       // Special case leading :: (e.g. "::1") to simplify processing later.
+       
+       if( *inStr == ':' )
+       {
+               ++inStr;
+               require_action_quiet( *inStr == ':', exit, err = kMalformedErr );
+       }
+       
+       // Parse the address.
+       
+       ptr              = inStr;
+       dst              = inBuffer;
+       lim              = dst + 16;
+       colonPtr = NULL;
+       sawDigit = 0;
+       v                = 0;
+       while( ( ( c = *inStr++ ) != '\0' ) && ( c != '%' ) && ( c != '/' ) && ( c != ']' ) )
+       {
+               if(   ( c >= 'a' ) && ( c <= 'f' ) ) c -= ( 'a' - 'A' );
+               if( ( ( c >= '0' ) && ( c <= '9' ) ) || ( ( c >= 'A' ) && ( c <= 'F' ) ) )
+               {
+                       c -= '0';
+                       check( c < (int) countof( kASCIItoHexTable ) );
+                       v = ( v << 4 ) | kASCIItoHexTable[ c ];
+                       require_action_quiet( v <= 0xFFFF, exit, err = kRangeErr );
+                       sawDigit = 1;
+                       continue;
+               }
+               if( c == ':' )
+               {
+                       ptr = inStr;
+                       if( !sawDigit )
+                       {
+                               require_action_quiet( !colonPtr, exit, err = kMalformedErr );
+                               colonPtr = dst;
+                               continue;
+                       }
+                       require_action_quiet( *inStr != '\0', exit, err = kUnderrunErr );
+                       require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
+                       *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
+                       *dst++ = (uint8_t)(   v        & 0xFF );
+                       sawDigit = 0;
+                       v = 0;
+                       continue;
+               }
+               
+               // Handle IPv4-mapped/compatible addresses (e.g. ::FFFF:1.2.3.4).
+               
+               if( inAllowV4Mapped && ( c == '.' ) && ( ( dst + 4 ) <= lim ) )
+               {
+                       err = _ParseIPv4Address( ptr, dst, &inStr );
+                       require_noerr_quiet( err, exit );
+                       dst += 4;
+                       sawDigit = 0;
+                       ++inStr; // Increment because the code below expects the end to be at "inStr - 1".
+               }
+               break;
+       }
+       if( sawDigit )
+       {
+               require_action_quiet( ( dst + 2 ) <= lim, exit, err = kOverrunErr );
+               *dst++ = (uint8_t)( ( v >> 8 ) & 0xFF );
+               *dst++ = (uint8_t)(   v        & 0xFF );
+       }
+       check( dst <= lim );
+       if( colonPtr )
+       {
+               require_action_quiet( dst < lim, exit, err = kOverrunErr );
+               n = (int)( dst - colonPtr );
+               for( i = 1; i <= n; ++i )
+               {
+                       lim[ -i ] = colonPtr[ n - i ];
+                       colonPtr[ n - i ] = 0;
+               }
+               dst = lim;
+       }
+       require_action_quiet( dst == lim, exit, err = kUnderrunErr );
+       
+       *outStr = inStr - 1;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _ParseIPv6Scope
+//
+//     Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus        _ParseIPv6Scope( const char *inStr, uint32_t *outScope, const char **outStr )
+{
+#if( TARGET_OS_POSIX )
+       OSStatus                        err;
+       char                            scopeStr[ 64 ];
+       char *                          dst;
+       char *                          lim;
+       int                                     c;
+       uint32_t                        scope;
+       const char *            ptr;
+       
+       // Copy into a local NULL-terminated string since that is what if_nametoindex expects.
+       
+       dst = scopeStr;
+       lim = dst + ( countof( scopeStr ) - 1 );
+       while( ( ( c = *inStr ) != '\0' ) && ( c != ':' ) && ( c != '/' ) && ( c != ']' ) && ( dst < lim ) )
+       {
+               *dst++ = *inStr++;
+       }
+       *dst = '\0';
+       check( dst <= lim );
+       
+       // First try to map as a name and if that fails, treat it as a numeric scope.
+       
+       scope = if_nametoindex( scopeStr );
+       if( scope == 0 )
+       {
+               for( ptr = scopeStr; ( ( c = *ptr ) >= '0' ) && ( c <= '9' ); ++ptr )
+               {
+                       scope = ( scope * 10 ) + ( ( (uint8_t) c ) - '0' );
+               }
+               require_action_quiet( c == '\0', exit, err = kMalformedErr );
+               require_action_quiet( ( ptr != scopeStr ) && ( ( (int)( ptr - scopeStr ) ) <= 10 ), exit, err = kMalformedErr );
+       }
+       
+       *outScope = scope;
+       *outStr   = inStr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+#else
+       OSStatus                        err;
+       uint32_t                        scope;
+       const char *            start;
+       int                                     c;
+       
+       scope = 0;
+       for( start = inStr; ( ( c = *inStr ) >= '0' ) && ( c <= '9' ); ++inStr )
+       {
+               scope = ( scope * 10 ) + ( c - '0' );
+       }
+       require_action_quiet( ( inStr != start ) && ( ( (int)( inStr - start ) ) <= 10 ), exit, err = kMalformedErr );
+       
+       *outScope = scope;
+       *outStr   = inStr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+#endif
+}
+
+//===========================================================================================================================
+//     _StringToIPv6Address
+//
+//     Note: This was copied from CoreUtils because the StringToIPv6Address function is currently not exported in the framework.
+//===========================================================================================================================
+
+static OSStatus
+       _StringToIPv6Address( 
+               const char *                    inStr, 
+               StringToIPAddressFlags  inFlags, 
+               uint8_t                                 outIPv6[ 16 ], 
+               uint32_t *                              outScope, 
+               int *                                   outPort, 
+               int *                                   outPrefix, 
+               const char **                   outStr )
+{
+       OSStatus                err;
+       uint8_t                 ipv6[ 16 ];
+       int                             c;
+       int                             hasScope;
+       uint32_t                scope;
+       int                             hasPort;
+       int                             port;
+       int                             hasPrefix;
+       int                             prefix;
+       int                             hasBracket;
+       int                             i;
+       
+       require_action( inStr, exit, err = kParamErr );
+       
+       if( *inStr == '[' ) ++inStr; // Skip a leading bracket for []-wrapped addresses (e.g. "[::1]:80").
+       
+       // Parse the address-only part of the address (e.g. "1::1").
+       
+       err = _ParseIPv6Address( inStr, !( inFlags & kStringToIPAddressFlagsNoIPv4Mapped ), ipv6, &inStr );
+       require_noerr_quiet( err, exit );
+       c = *inStr;
+       
+       // Parse the scope, port, or prefix length.
+       
+       hasScope        = 0;
+       scope           = 0;
+       hasPort         = 0;
+       port            = 0;
+       hasPrefix       = 0;
+       prefix          = 0;
+       hasBracket      = 0;
+       for( ;; )
+       {
+               if( c == '%' )          // Scope (e.g. "%en0" or "%5")
+               {
+                       require_action_quiet( !hasScope, exit, err = kMalformedErr );
+                       require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoScope ), exit, err = kUnexpectedErr );
+                       ++inStr;
+                       err = _ParseIPv6Scope( inStr, &scope, &inStr );
+                       require_noerr_quiet( err, exit );
+                       hasScope = 1;
+                       c = *inStr;
+               }
+               else if( c == ':' )     // Port (e.g. ":80")
+               {
+                       require_action_quiet( !hasPort, exit, err = kMalformedErr );
+                       require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPort ), exit, err = kUnexpectedErr );
+                       while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) port = ( port * 10 ) + ( c - '0' );
+                       require_action_quiet( port <= 65535, exit, err = kRangeErr );
+                       hasPort = 1;
+               }
+               else if( c == '/' )     // Prefix Length (e.g. "/64")
+               {
+                       require_action_quiet( !hasPrefix, exit, err = kMalformedErr );
+                       require_action_quiet( !( inFlags & kStringToIPAddressFlagsNoPrefix ), exit, err = kUnexpectedErr );
+                       while( ( ( c = *( ++inStr ) ) != '\0' ) && ( ( c >= '0' ) && ( c <= '9' ) ) ) prefix = ( prefix * 10 ) + ( c - '0' );
+                       require_action_quiet( ( prefix >= 0 ) && ( prefix <= 128 ), exit, err = kRangeErr );
+                       hasPrefix = 1;
+               }
+               else if( c == ']' )
+               {
+                       require_action_quiet( !hasBracket, exit, err = kMalformedErr );
+                       hasBracket = 1;
+                       c = *( ++inStr );
+               }
+               else
+               {
+                       break;
+               }
+       }
+       
+       // Return the results. Only fill in scope/port/prefix results if the info was found to allow for defaults.
+       
+       if( outIPv6 )                            for( i = 0; i < 16; ++i ) outIPv6[ i ] = ipv6[ i ];
+       if( outScope  && hasScope )  *outScope  = scope;
+       if( outPort   && hasPort )   *outPort   = port;
+       if( outPrefix && hasPrefix ) *outPrefix = prefix;
+       if( outStr )                             *outStr        = inStr;
+       err = kNoErr;
+       
+exit:
+       return( err );
+}
+
+//===========================================================================================================================
+//     _StringArray_Free
+//
+//     Note: This was copied from CoreUtils because the StringArray_Free function is currently not exported in the framework.
+//===========================================================================================================================
+
+static void    _StringArray_Free( char **inArray, size_t inCount )
+{
+       size_t          i;
+       
+       for( i = 0; i < inCount; ++i )
+       {
+               free( inArray[ i ] );
+       }
+       if( inCount > 0 ) free( inArray );
+}
+
+//===========================================================================================================================
+//     _ParseQuotedEscapedString
+//
+//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static Boolean
+       _ParseQuotedEscapedString( 
+               const char *    inSrc, 
+               const char *    inEnd, 
+               const char *    inDelimiters, 
+               char *                  inBuf, 
+               size_t                  inMaxLen, 
+               size_t *                outCopiedLen, 
+               size_t *                outTotalLen, 
+               const char **   outSrc )
+{
+       const unsigned char *           src;
+       const unsigned char *           end;
+       unsigned char *                         dst;
+       unsigned char *                         lim;
+       unsigned char                           c;
+       unsigned char                           c2;
+       size_t                                          totalLen;
+       Boolean                                         singleQuote;
+       Boolean                                         doubleQuote;
+       
+       if( inEnd == NULL ) inEnd = inSrc + strlen( inSrc );
+       src = (const unsigned char *) inSrc;
+       end = (const unsigned char *) inEnd;
+       dst = (unsigned char *) inBuf;
+       lim = dst + inMaxLen;
+       while( ( src < end ) && isspace_safe( *src ) ) ++src; // Skip leading spaces.
+       if( src >= end ) return( false );
+       
+       // Parse each argument from the string.
+       //
+       // See <http://resources.mpi-inf.mpg.de/departments/rg1/teaching/unixffb-ss98/quoting-guide.html> for details.
+       
+       totalLen = 0;
+       singleQuote = false;
+       doubleQuote = false;
+       while( src < end )
+       {
+               c = *src++;
+               if( singleQuote )
+               {
+                       // Single quotes protect everything (even backslashes, newlines, etc.) except single quotes.
+                       
+                       if( c == '\'' )
+                       {
+                               singleQuote = false;
+                               continue;
+                       }
+               }
+               else if( doubleQuote )
+               {
+                       // Double quotes protect everything except double quotes and backslashes. A backslash can be 
+                       // used to protect " or \ within double quotes. A backslash-newline pair disappears completely.
+                       // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
+                       // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
+                       // A backslash that does not precede ", \, x, X, or a newline is taken literally.
+                       
+                       if( c == '"' )
+                       {
+                               doubleQuote = false;
+                               continue;
+                       }
+                       else if( c == '\\' )
+                       {
+                               if( src < end )
+                               {
+                                       c2 = *src;
+                                       if( ( c2 == '"' ) || ( c2 == '\\' ) )
+                                       {
+                                               ++src;
+                                               c = c2;
+                                       }
+                                       else if( c2 == '\n' )
+                                       {
+                                               ++src;
+                                               continue;
+                                       }
+                                       else if( ( c2 == 'x' ) || ( c2 == 'X' ) )
+                                       {
+                                               ++src;
+                                               c = c2;
+                                               if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
+                                               {
+                                                       c = HexPairToByte( src );
+                                                       src += 2;
+                                               }
+                                       }
+                                       else if( isoctal_safe( c2 ) )
+                                       {
+                                               if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
+                                               {
+                                                       c = OctalTripleToByte( src );
+                                                       src += 3;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               else if( strchr( inDelimiters, c ) )
+               {
+                       break;
+               }
+               else if( c == '\\' )
+               {
+                       // A backslash protects the next character, except a newline, x, X and 2 hex bytes or 3 octal bytes. 
+                       // A backslash followed by a newline disappears completely.
+                       // A backslash followed by x or X and 2 hex digits (e.g. "\x1f") is stored as that hex byte.
+                       // A backslash followed by 3 octal digits (e.g. "\377") is stored as that octal byte.
+                       
+                       if( src < end )
+                       {
+                               c = *src;
+                               if( c == '\n' )
+                               {
+                                       ++src;
+                                       continue;
+                               }
+                               else if( ( c == 'x' ) || ( c == 'X' ) )
+                               {
+                                       ++src;
+                                       if( ( ( end - src ) >= 2 ) && IsHexPair( src ) )
+                                       {
+                                               c = HexPairToByte( src );
+                                               src += 2;
+                                       }
+                               }
+                               else if( isoctal_safe( c ) )
+                               {
+                                       if( ( ( end - src ) >= 3 ) && IsOctalTriple( src ) )
+                                       {
+                                               c = OctalTripleToByte( src );
+                                               src += 3;
+                                       }
+                                       else
+                                       {
+                                               ++src;
+                                       }
+                               }
+                               else
+                               {
+                                       ++src;
+                               }
+                       }
+               }
+               else if( c == '\'' )
+               {
+                       singleQuote = true;
+                       continue;
+               }
+               else if( c == '"' )
+               {
+                       doubleQuote = true;
+                       continue;
+               }
+               
+               if( dst < lim )
+               {
+                       if( inBuf ) *dst = c;
+                       ++dst;
+               }
+               ++totalLen;
+       }
+       
+       if( outCopiedLen )      *outCopiedLen   = (size_t)( dst - ( (unsigned char *) inBuf ) );
+       if( outTotalLen )       *outTotalLen    = totalLen;
+       if( outSrc )            *outSrc                 = (const char *) src;
+       return( true );
+}
+
+//===========================================================================================================================
+//     _ServerSocketOpenEx2
+//
+//     Note: Based on ServerSocketOpenEx() from CoreUtils. Added parameter to not use SO_REUSEPORT.
+//===========================================================================================================================
+
+static OSStatus
+       _ServerSocketOpenEx2( 
+               int                             inFamily, 
+               int                             inType, 
+               int                             inProtocol, 
+               const void *    inAddr, 
+               int                             inPort, 
+               int *                   outPort, 
+               int                             inRcvBufSize, 
+               Boolean                 inNoPortReuse,
+               SocketRef *             outSock )
+{
+       OSStatus                err;
+       int                             port;
+       SocketRef               sock;
+       int                             name;
+       int                             option;
+       sockaddr_ip             sip;
+       socklen_t               len;
+       
+       port = ( inPort < 0 ) ? -inPort : inPort; // Negated port number means "try this port, but allow dynamic".
+       
+       sock = socket( inFamily, inType, inProtocol );
+       err = map_socket_creation_errno( sock );
+       require_noerr_quiet( err, exit );
+       
+#if( defined( SO_NOSIGPIPE ) )
+       setsockopt( sock, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, (socklen_t) sizeof( int ) );
+#endif
+       
+       err = SocketMakeNonBlocking( sock );
+       require_noerr( err, exit );
+       
+       // Set receive buffer size. This has to be done on the listening socket *before* listen is called because
+       // accept does not return until after the window scale option is exchanged during the 3-way handshake. 
+       // Since accept returns a new socket, the only way to use a larger window scale option is to set the buffer
+       // size on the listening socket since SO_RCVBUF is inherited by the accepted socket. See UNPv1e3 Section 7.5.
+       
+       err = SocketSetBufferSize( sock, SO_RCVBUF, inRcvBufSize );
+       check_noerr( err );
+       
+       // Allow port or address reuse because we may bind separate IPv4 and IPv6 sockets to the same port.
+       
+       if( ( inType != SOCK_DGRAM ) || !inNoPortReuse )
+       {
+               option = 1;
+               name = ( inType == SOCK_DGRAM ) ? SO_REUSEPORT : SO_REUSEADDR;
+               err = setsockopt( sock, SOL_SOCKET, name, (char *) &option, (socklen_t) sizeof( option ) );
+               err = map_socket_noerr_errno( sock, err );
+               require_noerr( err, exit );
+       }
+       
+       if( inFamily == AF_INET )
+       {
+               // Bind to the port. If it fails, retry with a dynamic port.
+               
+               memset( &sip.v4, 0, sizeof( sip.v4 ) );
+               SIN_LEN_SET( &sip.v4 );
+               sip.v4.sin_family               = AF_INET;
+               sip.v4.sin_port                 = htons( (uint16_t) port );
+               sip.v4.sin_addr.s_addr  = inAddr ? *( (const uint32_t *) inAddr ) : htonl( INADDR_ANY );
+               err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
+               err = map_socket_noerr_errno( sock, err );
+               if( err && ( inPort < 0 ) )
+               {
+                       sip.v4.sin_port = 0;
+                       err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v4 ) );
+                       err = map_socket_noerr_errno( sock, err );
+               }
+               require_noerr( err, exit );
+       }
+#if( defined( AF_INET6 ) )
+       else if( inFamily == AF_INET6 )
+       {
+               // Restrict this socket to IPv6 only because we're going to use a separate socket for IPv4.
+               
+               option = 1;
+               err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, (socklen_t) sizeof( option ) );
+               err = map_socket_noerr_errno( sock, err );
+               require_noerr( err, exit );
+               
+               // Bind to the port. If it fails, retry with a dynamic port.
+               
+               memset( &sip.v6, 0, sizeof( sip.v6 ) );
+               SIN6_LEN_SET( &sip.v6 );
+               sip.v6.sin6_family      = AF_INET6;
+               sip.v6.sin6_port        = htons( (uint16_t) port );
+               sip.v6.sin6_addr        = inAddr ? *( (const struct in6_addr *) inAddr ) : in6addr_any; 
+               err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
+               err = map_socket_noerr_errno( sock, err );
+               if( err && ( inPort < 0 ) )
+               {
+                       sip.v6.sin6_port = 0;
+                       err = bind( sock, &sip.sa, (socklen_t) sizeof( sip.v6 ) );
+                       err = map_socket_noerr_errno( sock, err );
+               }
+               require_noerr( err, exit );
+       }
+#endif
+       else
+       {
+               dlogassert( "Unsupported family: %d", inFamily );
+               err = kUnsupportedErr;
+               goto exit;
+       }
+       
+       if( inType == SOCK_STREAM )
+       {
+               err = listen( sock, SOMAXCONN );
+               err = map_socket_noerr_errno( sock, err );
+               if( err )
+               {
+                       err = listen( sock, 5 );
+                       err = map_socket_noerr_errno( sock, err );
+                       require_noerr( err, exit );
+               }
+       }
+       
+       if( outPort )
+       {
+               len = (socklen_t) sizeof( sip );
+               err = getsockname( sock, &sip.sa, &len );
+               err = map_socket_noerr_errno( sock, err );
+               require_noerr( err, exit );
+               
+               *outPort = SockAddrGetPort( &sip );
+       }
+       *outSock = sock;
+       sock = kInvalidSocketRef;
+       
+exit:
+       ForgetSocket( &sock );
+       return( err );
+}
+
+//===========================================================================================================================
+//     _memdup
+//
+//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static void *  _memdup( const void *inPtr, size_t inLen )
+{
+       void *          mem;
+       
+       mem = malloc( ( inLen > 0 ) ? inLen : 1 ); // If inLen is 0, use 1 since malloc( 0 ) is not well defined.
+       require( mem, exit );
+       if( inLen > 0 ) memcpy( mem, inPtr, inLen );
+       
+exit:
+       return( mem );
+}
+
+//===========================================================================================================================
+//     _memicmp
+//
+//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static int     _memicmp( const void *inP1, const void *inP2, size_t inLen )
+{
+       const unsigned char *           p1;
+       const unsigned char *           e1;
+       const unsigned char *           p2;
+       int                                                     c1;
+       int                                                     c2;
+       
+       p1 = (const unsigned char *) inP1;
+       e1 = p1 + inLen;
+       p2 = (const unsigned char *) inP2;
+       while( p1 < e1 )
+       {
+               c1 = *p1++;
+               c2 = *p2++;
+               c1 = tolower( c1 );
+               c2 = tolower( c2 );
+               if( c1 < c2 ) return( -1 );
+               if( c1 > c2 ) return(  1 );
+       }
+       return( 0 );
+}
+
+//===========================================================================================================================
+//     _FNV1
+//
+//     Note: This was copied from CoreUtils because it's currently not exported in the framework.
+//===========================================================================================================================
+
+static uint32_t        _FNV1( const void *inData, size_t inSize )
+{
+       const uint8_t *                         src = (const uint8_t *) inData;
+       const uint8_t * const           end = src + inSize;
+       uint32_t                                        hash;
+       
+       hash = 0x811c9dc5U;
+       while( src != end )
+       {
+               hash *= 0x01000193;
+               hash ^= *src++;
+       }
+       return( hash );
+}
diff --git a/DSO/dso-transport.c b/DSO/dso-transport.c
new file mode 100644 (file)
index 0000000..ab0be62
--- /dev/null
@@ -0,0 +1,1267 @@
+/* dso-transport.c
+ *
+ * Copyright (c) 2018-2019 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.
+ *
+ */
+
+//*************************************************************************************************************
+// Headers
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include <netdb.h>           // For gethostbyname()
+#include <sys/socket.h>      // For AF_INET, AF_INET6, etc.
+#include <net/if.h>          // For IF_NAMESIZE
+#include <netinet/in.h>      // For INADDR_NONE
+#include <netinet/tcp.h>     // For SOL_TCP, TCP_NOTSENT_LOWAT
+#include <arpa/inet.h>       // For inet_addr()
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "dns_sd.h"
+#include "DNSCommon.h"
+#include "mDNSEmbeddedAPI.h"
+#include "dso.h"
+#include "dso-transport.h"
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+// Network Framework only works on MacOS X at the moment, and we need the locking primitives for
+// MacOSX.
+#include "mDNSMacOSX.h"
+#endif
+
+extern mDNS mDNSStorage;
+
+static dso_connect_state_t *dso_connect_states; // DSO connect states that exist.
+static dso_transport_t *dso_transport_states; // DSO transport states that exist.
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static uint32_t dso_transport_serial; // Serial number of next dso_transport_state_t or dso_connect_state_t.
+static dispatch_queue_t dso_dispatch_queue;
+#else
+static void dso_read_callback(TCPSocket *sock, void *context, mDNSBool connection_established,
+                       mStatus err);
+#endif
+
+void
+dso_transport_init(void)
+{
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    // It's conceivable that we might want a separate queue, but we don't know yet, so for
+    // now we just use the main dispatch queue, which should be on the main dispatch thread,
+    // which is _NOT_ the kevent thread.   So whenever we are doing anything on the dispatch
+    // queue (any completion functions for NW framework) we need to acquire the lock before
+    // we even look at any variables that could be changed by the other thread.
+    dso_dispatch_queue = dispatch_get_main_queue();
+#endif
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static dso_connect_state_t *
+dso_connect_state_find(uint32_t serial)
+{
+    dso_connect_state_t *csp;
+    for (csp = dso_connect_states; csp; csp = csp->next) {
+        if (csp->serial ==  serial) {
+            return csp;
+        }
+    }
+    return NULL;
+}
+#endif
+
+static void
+dso_transport_finalize(dso_transport_t *transport)
+{
+    dso_transport_t **tp = &dso_transport_states;
+    if (transport->connection != NULL) {
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+        nw_connection_cancel(transport->connection);
+        nw_release(transport->connection);
+#else
+        mDNSPlatformTCPCloseConnection(transport->connection);
+#endif
+        transport->connection = NULL;
+    }
+    while (*tp) {
+        if (*tp == transport) {
+            *tp = transport->next;
+        } else {
+            tp = &transport->next;
+        }
+    }
+    free(transport);
+}    
+
+// We do all of the finalization for the dso state object and any objects it depends on here in the
+// dso_idle function because it avoids the possibility that some code on the way out to the event loop
+// _after_ the DSO connection has been dropped might still write to the DSO structure or one of the
+// dependent structures and corrupt the heap, or indeed in the unlikely event that this memory was
+// freed and then reallocated before the exit to the event loop, there could be a bad pointer
+// dereference.
+//
+// If there is a finalize function, that function MUST either free its own state that references the
+// DSO state, or else must NULL out the pointer to the DSO state.
+int64_t dso_transport_idle(void *context, int64_t now_in, int64_t next_timer_event)
+{
+    dso_connect_state_t *cs, *cnext;
+    mDNS *m = context;
+    mDNSs32 now = (mDNSs32)now_in;
+    mDNSs32 next_event = (mDNSs32)next_timer_event;
+
+    // Notice if a DSO connection state is active but hasn't seen activity in a while.
+    for (cs = dso_connect_states; cs != NULL; cs = cnext) {
+        cnext = cs->next;
+        if (!cs->connecting && cs->last_event != 0) {
+            mDNSs32 expiry = cs->last_event + 90 * mDNSPlatformOneSecond;
+            if (now - expiry > 0) {
+                cs->last_event = 0;
+                cs->callback(cs->context, NULL, NULL, kDSOEventType_ConnectFailed);
+                if (cs->lookup != NULL) {
+                    DNSServiceRef ref = cs->lookup;
+                    cs->lookup = NULL;
+                    mDNS_DropLockBeforeCallback();
+                    DNSServiceRefDeallocate(ref);
+                    mDNS_ReclaimLockAfterCallback();    // Decrement mDNS_reentrancy to block mDNS API calls again
+                }
+            } else {
+                if (next_timer_event - expiry > 0) {
+                    next_timer_event = expiry;
+                }
+            }
+        } else if (!cs->connecting && cs->reconnect_time && now - cs->reconnect_time > 0) {
+            cs->reconnect_time = 0; // Don't try to immediately reconnect if it fails.
+            // If cs->dso->transport is non-null, we're already connected.
+            if (cs->dso && cs->dso->transport == NULL) {
+                cs->callback(cs->context, NULL, NULL, kDSOEventType_ShouldReconnect);
+            }
+        }
+        if (cs->reconnect_time != 0 && next_event - cs->reconnect_time > 0) {
+            next_event = cs->reconnect_time;
+        }
+    }
+            
+    return next_event;
+}
+
+// Call to schedule a reconnect at a later time.
+void dso_schedule_reconnect(mDNS *m, dso_connect_state_t *cs, mDNSs32 when)
+{
+    cs->reconnect_time = when * mDNSPlatformOneSecond + m->timenow;
+}
+
+// If a DSO was created by an incoming connection, the creator of the listener can use this function
+// to supply context and a callback for future events.
+void dso_set_callback(dso_state_t *dso, void *context, dso_event_callback_t cb)
+{
+    dso->cb = cb;
+    dso->context = context;
+}
+
+// This is called before writing a DSO message to the output buffer.  length is the length of the message.
+// Returns true if we have successfully selected for write (which means that we're under TCP_NOTSENT_LOWAT).
+// Otherwise returns false.   It is valid to write even if it returns false, but there is a risk that
+// the write will return EWOULDBLOCK, at which point we'd have to blow away the connection.   It is also
+// valid to give up at this point and not write a message; as long as dso_write_finish isn't called, a later
+// call to dso_write_start will overwrite the length that was stored by the previous invocation.
+//
+// The circumstance in which this would occur is that we have filled the kernel's TCP output buffer for this
+// connection all the way up to TCP_NOTSENT_LOWAT, and then we get a query from the Discovery Proxy to which we
+// need to respond.  Because TCP_NOTSENT_LOWAT is fairly low, there should be a lot of room in the TCP output
+// buffer for small responses; it would need to be the case that we are getting requests from the proxy at a
+// high rate for us to fill the output buffer to the point where a write of a 12-byte response returns
+// EWOULDBLOCK; in that case, things are so dysfunctional that killing the connection isn't any worse than
+// allowing it to continue.
+
+// An additional note about the motivation for this code: the idea originally was that we'd do scatter/gather
+// I/O here: this lets us write everything out in a single sendmsg() call.   This isn't used with the mDNSPlatformTCP
+// code because it doesn't support scatter/gather.   Network Framework does, however, and in principle we could
+// write to the descriptor directly if that were really needed.
+
+bool dso_write_start(dso_transport_t *transport, size_t length)
+{
+    // The transport doesn't support messages outside of this range.
+    if (length < 12 || length > 65535) {
+        return false;
+    }
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    uint8_t lenbuf[2];
+
+    if (transport->to_write != NULL) {
+        nw_release(transport->to_write);
+        transport->to_write = NULL;
+    }
+    lenbuf[0] = length >> 8;
+    lenbuf[1] = length & 255;
+    transport->to_write = dispatch_data_create(lenbuf, 2, dso_dispatch_queue,
+                                               DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+    if (transport->to_write == NULL) {
+        transport->write_failed = true;
+        return false;
+    }
+    transport->bytes_to_write = length + 2;
+
+    // We don't have access to TCP_NOTSENT_LOWAT, so for now we track how many bytes we've written
+    // versus how many bytes that we've written have completed, and if that creeps above MAX_UNSENT_BYTES,
+    // we return false here to indicate that there is congestion.
+    if (transport->unsent_bytes > MAX_UNSENT_BYTES) {
+        return false;
+    } else {
+        return true;
+    }
+#else
+    transport->lenbuf[0] = length >> 8;
+    transport->lenbuf[1] = length & 255;
+
+    transport->to_write[0] = transport->lenbuf;
+    transport->write_lengths[0] = 2;
+    transport->num_to_write = 1;
+
+    return mDNSPlatformTCPWritable(transport->connection);
+#endif // DSO_USES_NETWORK_FRAMEWORK
+}
+
+// Called to finish a write (dso_write_start .. dso_write .. [ dso_write ... ] dso_write_finish).  The
+// write must completely finish--if we get a partial write, this means that the connection is stalled, and
+// so we drop it.  Since this can call dso_drop, the caller must not reference the DSO state object
+// after this call if the return value is false.
+bool dso_write_finish(dso_transport_t *transport)
+{
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    uint32_t serial = transport->dso->serial;
+    int bytes_to_write = transport->bytes_to_write;
+    transport->bytes_to_write = 0;
+    if (transport->write_failed) {
+        dso_drop(transport->dso);
+        return false;
+    }
+    transport->unsent_bytes += bytes_to_write;
+    nw_connection_send(transport->connection, transport->to_write, NW_CONNECTION_DEFAULT_STREAM_CONTEXT, true,
+                       ^(nw_error_t  _Nullable error) {
+                           dso_state_t *dso;
+                           KQueueLock();
+                           dso = dso_find_by_serial(serial);
+                           if (error != NULL) {
+                               LogMsg("dso_write_finish: write failed: %s", strerror(nw_error_get_error_code(error)));
+                               if (dso != NULL) {
+                                   dso_drop(dso);
+                               }
+                           } else {
+                               dso->transport->unsent_bytes -= bytes_to_write;
+                               LogMsg("dso_write_finish completion routine: %d bytes written, %d bytes outstanding",
+                                      bytes_to_write, dso->transport->unsent_bytes);
+                           }
+                           KQueueUnlock("dso_write_finish completion routine");
+                       });
+    nw_release(transport->to_write);
+    transport->to_write = NULL;
+    return true;
+#else
+    ssize_t result, total = 0;
+    int i;
+
+   if (transport->num_to_write > MAX_WRITE_HUNKS) {
+        LogMsg("dso_write_finish: fatal internal programming error: called %d times (more than limit of %d)", 
+               transport->num_to_write, MAX_WRITE_HUNKS);
+        dso_drop(transport->dso);
+        return false;
+    }
+
+    // This is our ersatz scatter/gather I/O.
+    for (i = 0; i < transport->num_to_write; i++) {
+        result = mDNSPlatformWriteTCP(transport->connection, (const char *)transport->to_write[i], transport->write_lengths[i]);
+        if (result != transport->write_lengths[i]) {
+            if (result < 0) {
+                LogMsg("dso_write_finish: fatal: mDNSPlatformWrite on %s returned %d", transport->dso->remote_name, errno);
+            } else {
+                LogMsg("dso_write_finish: fatal: mDNSPlatformWrite: short write on %s: %ld < %ld",
+                       transport->dso->remote_name, (long)result, (long)total);
+            }
+            dso_drop(transport->dso);
+            return false;
+        }
+    }
+#endif
+    return true;
+}
+
+// This function may only be called after a previous call to dso_write_start; it records the length of and
+// pointer to the write buffer.  These buffers must remain valid until dso_write_finish() is called.  The
+// caller is responsible for managing the memory they contain.  The expected control flow for writing is:
+// dso_write_start(); dso_write(); dso_write(); dso_write(); dso_write_finished(); There should be one or
+// more calls to dso_write; these will ideally be translated into a single scatter/gather sendmsg call (or
+// equivalent) to the kernel.
+void dso_write(dso_transport_t *transport, const uint8_t *buf, size_t length)
+{
+    if (length == 0) {
+        return;
+    }
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    if (transport->write_failed) {
+        return;
+    }
+    dispatch_data_t dpd = dispatch_data_create(buf, length, dso_dispatch_queue,
+                                               DISPATCH_DATA_DESTRUCTOR_DEFAULT);
+    if (dpd == NULL) {
+        transport->write_failed = true;
+        return;
+    }
+    if (transport->to_write != NULL) {
+        dispatch_data_t dpc = dispatch_data_create_concat(transport->to_write, dpd);
+        dispatch_release(dpd);
+        dispatch_release(transport->to_write);
+        if (dpc == NULL) {
+            transport->to_write = NULL;
+            transport->write_failed = true;
+            return;
+        }
+        transport->to_write = dpc;
+    }
+#else
+    // We'll report this in dso_write_finish();
+    if (transport->num_to_write >= MAX_WRITE_HUNKS) {
+        transport->num_to_write++;
+        return;
+    }
+
+    transport->to_write[transport->num_to_write] = buf;
+    transport->write_lengths[transport->num_to_write] = length;
+    transport->num_to_write++;
+#endif
+}
+
+// Write a DSO message
+int dso_message_write(dso_state_t *dso, dso_message_t *msg, bool disregard_low_water)
+{
+    dso_transport_t *transport = dso->transport;
+    if (transport->connection != NULL) {
+        if (dso_write_start(transport, dso_message_length(msg)) || disregard_low_water) {
+            dso_write(transport, msg->buf, msg->no_copy_bytes_offset);
+            dso_write(transport, msg->no_copy_bytes, msg->no_copy_bytes_len);
+            dso_write(transport, &msg->buf[msg->no_copy_bytes_offset], msg->cur - msg->no_copy_bytes_offset);
+            return dso_write_finish(transport);
+        }
+    }
+    return mStatus_NoMemoryErr;
+}
+
+// Replies to some message we were sent with a response code and no data.
+// This is a convenience function for replies that do not require that a new
+// packet be constructed.   It takes advantage of the fact that the message
+// to which this is a reply is still in the input buffer, and modifies that
+// message in place to turn it into a response.
+
+bool dso_send_simple_response(dso_state_t *dso, int rcode, const DNSMessageHeader *header, const char *pres)
+{
+    dso_transport_t *transport = dso->transport;
+    (void)pres; // might want this later.
+    DNSMessageHeader response = *header;
+    
+    // Just return the message, with no questions, answers, etc.
+    response.flags.b[1] = (response.flags.b[1] & ~kDNSFlag1_RC_Mask) | rcode;
+    response.flags.b[0] |= kDNSFlag0_QR_Response;
+    response.numQuestions = 0;
+    response.numAnswers = 0;
+    response.numAuthorities = 0;
+    response.numAdditionals = 0;
+
+    // Buffered write back to discovery proxy
+    (void)dso_write_start(transport, 12);
+    dso_write(transport, (uint8_t *)&response, 12);
+    if (!dso_write_finish(transport)) {
+        return false;
+    }
+    return true;
+}
+
+// DSO Message we received has a primary TLV that's not implemented.
+// XXX is this what we're supposed to do here? check draft.
+bool dso_send_not_implemented(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    return dso_send_simple_response(dso, kDNSFlag1_RC_DSOTypeNI, header, "DSOTYPENI");
+}
+
+// Non-DSO message we received is refused.
+bool dso_send_refused(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    return dso_send_simple_response(dso, kDNSFlag1_RC_Refused, header, "REFUSED");
+}
+
+bool dso_send_formerr(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    return dso_send_simple_response(dso, kDNSFlag1_RC_FormErr, header, "FORMERR");
+}
+
+bool dso_send_servfail(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    return dso_send_simple_response(dso, kDNSFlag1_RC_ServFail, header, "SERVFAIL");
+}
+
+bool dso_send_name_error(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    return dso_send_simple_response(dso, kDNSFlag1_RC_NXDomain, header, "NXDOMAIN");
+}
+
+bool dso_send_no_error(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    return dso_send_simple_response(dso, kDNSFlag1_RC_NoErr, header, "NOERROR");
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static void dso_read_message(dso_transport_t *transport, size_t length);
+
+static void dso_read_message_length(dso_transport_t *transport)
+{
+    const uint32_t serial = transport->dso->serial;
+    if (transport->connection == NULL) {
+        LogMsg("dso_read_message_length called with null connection.");
+        return;
+    }
+    nw_connection_receive(transport->connection, 2, 2,
+                          ^(dispatch_data_t content, nw_content_context_t __unused context,
+                            bool __unused is_complete, nw_error_t error) {
+                              dso_state_t *dso;
+                              // Don't touch anything or look at anything until we have the lock.
+                              KQueueLock();
+                              dso = dso_find_by_serial(serial);
+                              if (error != NULL) {
+                                  LogMsg("dso_read_message_length: read failed: %s",
+                                         strerror(nw_error_get_error_code(error)));
+                              fail:
+                                  if (dso != NULL) {
+                                      mDNS_Lock(&mDNSStorage);
+                                      dso_drop(dso);
+                                      mDNS_Unlock(&mDNSStorage);
+                                  }
+                              } else if (content == NULL) {
+                                  LogMsg("dso_read_message_length: remote end closed connection.");
+                                  goto fail;
+                              } else {
+                                  size_t length;
+                                  const uint8_t *lenbuf;
+                                  dispatch_data_t map = dispatch_data_create_map(content, (const void **)&lenbuf, &length);
+                                  if (map == NULL) {
+                                      LogMsg("dso_read_message_length: map create failed");
+                                      goto fail;
+                                  } else if (length != 2) {
+                                      LogMsg("dso_read_message_length: invalid length = %d", length);
+                                      goto fail;
+                                  }
+                                  length = ((unsigned)(lenbuf[0]) << 8) | ((unsigned)lenbuf[1]);
+                                  dso_read_message(transport, length);
+                              }
+                              KQueueUnlock("dso_read_message_length completion routine");
+                          });
+}
+
+void dso_read_message(dso_transport_t *transport, size_t length)
+{
+    const uint32_t serial = transport->dso->serial;
+    if (transport->connection == NULL) {
+        LogMsg("dso_read_message called with null connection.");
+        return;
+    }
+    nw_connection_receive(transport->connection, length, length,
+                          ^(dispatch_data_t content, nw_content_context_t __unused context,
+                            bool __unused is_complete, nw_error_t error) {
+                              dso_state_t *dso;
+                              // Don't touch anything or look at anything until we have the lock.
+                              KQueueLock();
+                              dso = dso_find_by_serial(serial);
+                              if (error != NULL) {
+                                  LogMsg("dso_read_message: read failed: %s", strerror(nw_error_get_error_code(error)));
+                              fail:
+                                  if (dso != NULL) {
+                                      mDNS_Lock(&mDNSStorage);
+                                      dso_drop(dso);
+                                      mDNS_Unlock(&mDNSStorage);
+                                  }
+                              } else if (content == NULL) {
+                                  LogMsg("dso_read_message: remote end closed connection");
+                                  goto fail;
+                              } else {
+                                  size_t bytes_read;
+                                  const uint8_t *message;
+                                  dispatch_data_t map = dispatch_data_create_map(content, (const void **)&message, &bytes_read);
+                                  if (map == NULL) {
+                                      LogMsg("dso_read_message_length: map create failed");
+                                      goto fail;
+                                  } else if (bytes_read != length) {
+                                      LogMsg("dso_read_message_length: only %d of %d bytes read", bytes_read, length);
+                                      goto fail;
+                                  }
+                                  // Process the message.
+                                  mDNS_Lock(&mDNSStorage);
+                                  dns_message_received(dso, message, length);
+                                  mDNS_Unlock(&mDNSStorage);
+
+                                  // Now read the next message length.
+                                  dso_read_message_length(transport);
+                              }
+                              KQueueUnlock("dso_read_message completion routine");
+                          });
+}
+#else
+// Called whenever there's data available on a DSO connection
+void dso_read_callback(TCPSocket *sock, void *context, mDNSBool connection_established, int err)
+{
+    dso_transport_t *transport = context;
+    dso_state_t *dso;
+    mDNSBool closed = mDNSfalse;
+
+    mDNS_Lock(&mDNSStorage);
+    dso = transport->dso;
+
+    // This shouldn't ever happen.
+    if (err) {
+        LogMsg("dso_read_callback: error %d", err);
+        dso_drop(dso);
+        goto out;
+    }
+
+    // Connection is already established by the time we set this up.
+    if (connection_established) {
+        goto out;
+    }
+    
+    // This will be true either if we have never read a message or
+    // if the last thing we did was to finish reading a message and
+    // process it.
+    if (transport->message_length == 0) {
+        transport->need_length = true;
+        transport->inbufp = transport->inbuf;
+        transport->bytes_needed = 2;
+    }
+    
+    // Read up to bytes_needed bytes.
+    ssize_t count = mDNSPlatformReadTCP(sock, transport->inbufp, transport->bytes_needed, &closed);
+    // LogMsg("read(%d, %p:%p, %d) -> %d", fd, dso->inbuf, dso->inbufp, dso->bytes_needed, count);
+    if (count < 0) {
+        LogMsg("dso_read_callback: read from %s returned %d", dso->remote_name, errno);
+        dso_drop(dso);
+        goto out;
+    }
+
+    // If we get selected for read and there's nothing to read, the remote end has closed the
+    // connection.
+    if (closed) {
+        LogMsg("dso_read_callback: remote %s closed", dso->remote_name);
+        dso_drop(dso);
+        goto out;
+    }
+    
+    transport->inbufp += count;
+    transport->bytes_needed -= count;
+
+    // If we read all the bytes we wanted, do what's next.
+    if (transport->bytes_needed == 0) {
+        // We just finished reading the complete length of a DNS-over-TCP message.
+        if (transport->need_length) {
+            // Get the number of bytes in this DNS message
+            transport->bytes_needed = (((int)transport->inbuf[0]) << 8) | transport->inbuf[1];
+
+            // Under no circumstances can length be zero.
+            if (transport->bytes_needed == 0) {
+                LogMsg("dso_read_callback: %s sent zero-length message.", dso->remote_name);
+                dso_drop(dso);
+                goto out;
+            }
+
+            // The input buffer size is AbsoluteMaxDNSMessageData, which is around 9000 bytes on
+            // big platforms and around 1500 bytes on smaller ones.   If the remote end has sent
+            // something larger than that, it's an error from which we can't recover.
+            if (transport->bytes_needed > transport->inbuf_size - 2) {
+                LogMsg("dso_read_callback: fatal: Proxy at %s sent a too-long (%ld bytes) message",
+                       dso->remote_name, (long)transport->bytes_needed);
+                dso_drop(dso);
+                goto out;
+            }
+
+            transport->message_length = transport->bytes_needed;
+            transport->inbufp = transport->inbuf + 2;
+            transport->need_length = false;
+
+        // We just finished reading a complete DNS-over-TCP message.
+        } else {
+            dns_message_received(dso, &transport->inbuf[2], transport->message_length);
+            transport->message_length = 0;
+        }
+    }
+out:
+    mDNS_Unlock(&mDNSStorage);
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static dso_transport_t *dso_transport_create(nw_connection_t connection, bool is_server, void *context,
+                                             int max_outstanding_queries, size_t outbuf_size_in, const char *remote_name,
+                                             dso_event_callback_t cb, dso_state_t *dso)
+{
+    dso_transport_t *transport;
+    uint8_t *transp;
+    const size_t outbuf_size = outbuf_size_in + 256; // Space for additional TLVs
+
+    // We allocate everything in a single hunk so that we can free it together as well.
+    transp = mallocL("dso_transport_create", (sizeof *transport) + outbuf_size);
+    if (transp == NULL) {
+        transport = NULL;
+        goto out;
+    }
+    // Don't clear the buffers.
+    mDNSPlatformMemZero(transp, sizeof (*transport));
+
+    transport = (dso_transport_t *)transp;
+    transp += sizeof *transport;
+
+    transport->outbuf = transp;
+    transport->outbuf_size = outbuf_size;
+
+    if (dso == NULL) {
+        transport->dso = dso_create(is_server, max_outstanding_queries, remote_name, cb, context, transport);
+        if (transport->dso == NULL) {
+            mDNSPlatformMemFree(transport);
+            transport = NULL;
+            goto out;
+        }
+    } else {
+        transport->dso = dso;
+    }
+    transport->connection = connection;
+    nw_retain(transport->connection);
+    transport->serial = dso_transport_serial++;
+
+    transport->dso->transport = transport;
+    transport->dso->transport_finalize = dso_transport_finalize;
+    transport->next = dso_transport_states;
+    dso_transport_states = transport;
+
+    // Start looking for messages...
+    dso_read_message_length(transport);
+out:
+    return transport;
+}
+#else
+// Create a dso_transport_t structure
+static dso_transport_t *dso_transport_create(TCPSocket *sock, bool is_server, void *context, int max_outstanding_queries,
+                                             size_t inbuf_size_in, size_t outbuf_size_in, const char *remote_name,
+                                             dso_event_callback_t cb, dso_state_t *dso)
+{
+    dso_transport_t *transport;
+    size_t outbuf_size;
+    size_t inbuf_size;
+    uint8_t *transp;
+    int status;
+
+    // There's no point in a DSO that doesn't have a callback.
+    if (!cb) {
+        return NULL;
+    }
+
+    outbuf_size = outbuf_size_in + 256; // Space for additional TLVs
+    inbuf_size = inbuf_size_in + 2;   // Space for length
+
+    // We allocate everything in a single hunk so that we can free it together as well.
+    transp = mallocL("dso_transport_create", (sizeof *transport) + inbuf_size + outbuf_size);
+    if (transp == NULL) {
+        transport = NULL;
+        goto out;
+    }
+    // Don't clear the buffers.
+    mDNSPlatformMemZero(transp, sizeof (*transport));
+
+    transport = (dso_transport_t *)transp;
+    transp += sizeof *transport;
+
+    transport->inbuf = transp;
+    transport->inbuf_size = inbuf_size;
+    transp += inbuf_size;
+
+    transport->outbuf = transp;
+    transport->outbuf_size = outbuf_size;
+
+    if (dso == NULL) {
+        transport->dso = dso_create(is_server, max_outstanding_queries, remote_name, cb, context, transport);
+        if (transport->dso == NULL) {
+            mDNSPlatformMemFree(transport);
+            transport = NULL;
+            goto out;
+        }
+    } else {
+        transport->dso = dso;
+    }
+    transport->connection = sock;
+
+    status = mDNSPlatformTCPSocketSetCallback(sock, dso_read_callback, transport);
+    if (status != mStatus_NoError) {
+        LogMsg("dso_create: unable to set callback: %d", status);
+        dso_drop(transport->dso);
+        goto out;
+    }
+
+    transport->dso->transport = transport;
+    transport->dso->transport_finalize = dso_transport_finalize;
+    transport->next = dso_transport_states;
+    dso_transport_states = transport;
+out:
+    return transport;
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+// This should all be replaced with Network Framework connection setup.
+dso_connect_state_t *dso_connect_state_create(const char *hostname, mDNSAddr *addr, mDNSIPPort port,
+                                              int max_outstanding_queries, size_t inbuf_size, size_t outbuf_size,
+                                              dso_event_callback_t callback, dso_state_t *dso, void *context, const char *detail)
+{
+    int detlen = strlen(detail) + 1;
+    int hostlen = hostname == NULL ? 0 : strlen(hostname) + 1;
+    int len;
+    dso_connect_state_t *cs;
+    char *csp;
+    char nbuf[INET6_ADDRSTRLEN + 1];
+    dso_connect_state_t **states;
+
+    // Enforce Some Minimums (Xxx these are a bit arbitrary, maybe not worth doing?)
+    if (inbuf_size < MaximumRDSize || outbuf_size < 128 || max_outstanding_queries < 1) {
+        return 0;
+    }
+
+    // If we didn't get a hostname, make a presentation form of the IP address to use instead.
+    if (!hostlen) {
+        if (addr != NULL) {
+            if (addr->type == mDNSAddrType_IPv4) {
+                hostname = inet_ntop(AF_INET, &addr->ip.v4, nbuf, sizeof nbuf);
+            } else {
+                hostname = inet_ntop(AF_INET6, &addr->ip.v6, nbuf, sizeof nbuf);
+            }
+            if (hostname != NULL) {
+                hostlen = strlen(nbuf);
+            }
+        }
+    }
+    // If we don't have a printable name, we won't proceed, because this means we don't know
+    // what to connect to.
+    if (!hostlen) {
+        return 0;
+    }
+
+    len = (sizeof *cs) + detlen + hostlen;
+    csp = malloc(len);
+    if (!csp) {
+        return NULL;
+    }
+    cs = (dso_connect_state_t *)csp;
+    memset(cs, 0, sizeof *cs);
+    csp += sizeof *cs;
+
+    cs->detail = csp;
+    memcpy(cs->detail, detail, detlen);
+    csp += detlen;
+    cs->hostname = csp;
+    memcpy(cs->hostname, hostname, hostlen);
+
+    cs->config_port = port;
+    cs->max_outstanding_queries = max_outstanding_queries;
+    cs->outbuf_size = outbuf_size;
+    if (context) {
+        cs->context = context;
+    } // else cs->context = NULL because of memset call above.
+    cs->callback = callback;
+    cs->connect_port.NotAnInteger = 0;
+    cs->dso = dso;
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    cs->serial = dso_transport_serial++;
+#else
+    cs->inbuf_size = inbuf_size;
+#endif
+
+    if (addr) {
+        cs->num_addrs = 1;
+        cs->addresses[0] = *addr;
+        cs->ports[0] = port;
+    }
+    for (states = &dso_connect_states; *states != NULL; states = &(*states)->next)
+        ;
+    *states = cs;
+    return cs;
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+void dso_connect_state_use_tls(dso_connect_state_t *cs)
+{
+    cs->tls_enabled = true;
+}
+#endif
+
+void dso_connect_state_drop(dso_connect_state_t *cs)
+{
+    dso_connect_state_t **states;
+
+    for (states = &dso_connect_states; *states != NULL && *states != cs; states = &(*states)->next)
+        ;
+    if (*states) {
+        *states = cs->next;;
+    } else {
+        LogMsg("dso_connect_state_drop: dropping a connect state that isn't recognized.");
+    }
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    if (cs->connection != NULL) {
+        nw_connection_cancel(cs->connection);
+        nw_release(cs->connection);
+        cs->connection = NULL;
+    }
+#endif
+    mDNSPlatformMemFree(cs);
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+static void
+dso_connection_succeeded(dso_connect_state_t *cs)
+{
+    // We got a connection.
+    dso_transport_t *transport =
+        dso_transport_create(cs->connection, false, cs->context, cs->max_outstanding_queries,
+                             cs->outbuf_size, cs->hostname, cs->callback, cs->dso);
+    nw_release(cs->connection);
+    cs->connection = NULL;
+    if (transport == NULL) {
+        // If dso_transport_create fails, there's no point in continuing to try to connect to new
+        // addresses
+        LogMsg("dso_connection_succeeded: dso_create failed");
+        // XXX we didn't retain the connection, so we're done when it goes out of scope, right?
+    } else {
+        // Call the "we're connected" callback, which will start things up.
+        transport->dso->cb(cs->context, NULL, transport->dso, kDSOEventType_Connected);
+    }
+    
+    cs->last_event = 0;
+
+    // When the connection has succeeded, stop asking questions.
+    if (cs->lookup != NULL) {
+        mDNS *m = &mDNSStorage;
+        DNSServiceRef ref = cs->lookup;
+        cs->lookup = NULL;
+        mDNS_DropLockBeforeCallback();
+        DNSServiceRefDeallocate(ref);
+        mDNS_ReclaimLockAfterCallback();
+    }
+    return;
+}
+
+
+static void dso_connect_internal(dso_connect_state_t *cs)
+{
+    uint32_t serial = cs->serial;
+
+    cs->last_event = mDNSStorage.timenow;
+
+    if (cs->num_addrs <= cs->cur_addr) {
+        if (cs->lookup == NULL) {
+            LogMsg("dso_connect_internal: %s: no more addresses to try", cs->hostname);
+            cs->last_event = 0;
+            cs->callback(cs->context, NULL, NULL, kDSOEventType_ConnectFailed);
+        }
+        // Otherwise, we will get more callbacks when outstanding queries either fail or succeed.
+        return;
+    }            
+        
+    char addrbuf[INET6_ADDRSTRLEN + 1];
+    char portbuf[6];
+
+    inet_ntop(cs->addresses[cs->cur_addr].type == mDNSAddrType_IPv4 ? AF_INET : AF_INET6,
+              cs->addresses[cs->cur_addr].type == mDNSAddrType_IPv4
+              ? (void *)cs->addresses[cs->cur_addr].ip.v4.b
+              : (void *)cs->addresses[cs->cur_addr].ip.v6.b, addrbuf, sizeof addrbuf);
+    snprintf(portbuf, sizeof portbuf, "%u", ntohs(cs->ports[cs->cur_addr].NotAnInteger));
+    cs->cur_addr++;
+
+    nw_endpoint_t endpoint = nw_endpoint_create_host(addrbuf, portbuf);
+    if (endpoint == NULL) {
+    nomem:
+        LogMsg("dso_connect_internal: no memory creating connection.");
+        return;
+    }
+    nw_parameters_t parameters = NULL;
+    nw_parameters_configure_protocol_block_t configure_tls = NW_PARAMETERS_DISABLE_PROTOCOL;
+    if (cs->tls_enabled) {
+        // This sets up a block that's called when we get a TLS connection and want to verify
+        // the cert.   Right now we only support opportunistic security, which means we have
+        // no way to validate the cert.   Future work: add support for validating the cert
+        // using a TLSA record if one is present.
+        configure_tls = ^(nw_protocol_options_t tls_options) {
+            sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(tls_options);
+            sec_protocol_options_set_verify_block(sec_options, 
+                                                  ^(sec_protocol_metadata_t __unused metadata,
+                                                    sec_trust_t __unused trust_ref,
+                                                    sec_protocol_verify_complete_t complete) {
+                                                      complete(true);
+                                                  }, dso_dispatch_queue);
+        };
+    }
+    parameters = nw_parameters_create_secure_tcp(configure_tls, NW_PARAMETERS_DEFAULT_CONFIGURATION);
+    if (parameters == NULL) {
+        goto nomem;
+    }
+    nw_connection_t connection = nw_connection_create(endpoint, parameters);
+    if (connection == NULL) {
+        goto nomem;
+    }
+    cs->connection = connection;
+
+    LogMsg("dso_connect_internal: Attempting to connect to %s%%%s", addrbuf, portbuf);
+    nw_connection_set_queue(connection, dso_dispatch_queue);
+    nw_connection_set_state_changed_handler(
+        connection, ^(nw_connection_state_t state, nw_error_t error) {
+            dso_connect_state_t *ncs;
+            KQueueLock();
+            ncs = dso_connect_state_find(serial); // Might have been freed.
+            if (ncs == NULL) {
+                LogMsg("forgotten connection is %s.",
+                       state == nw_connection_state_cancelled ? "canceled" :
+                       state == nw_connection_state_failed ? "failed" :
+                       state == nw_connection_state_waiting ? "canceled" :
+                       state == nw_connection_state_ready ? "ready" : "unknown");
+                if (state != nw_connection_state_cancelled) {
+                    nw_connection_cancel(connection);
+                    // Don't need to release it because only NW framework is holding a reference (XXX right?)
+                }
+            } else {
+                if (state == nw_connection_state_waiting) {
+                    LogMsg("connection to %#a%%%d is waiting", &ncs->addresses[ncs->cur_addr], ncs->ports[ncs->cur_addr]);
+
+                    // XXX the right way to do this is to just let NW Framework wait until we get a connection,
+                    // but there are a bunch of problems with that right now.   First, will we get "waiting" on
+                    // every connection we try?   We aren't relying on NW Framework for DNS lookups, so we are
+                    // connecting to an IP address, not a host, which means in principle that a later IP address
+                    // might be reachable.   So we have to stop trying on this one to try that one.   Oops.
+                    // Once we get NW Framework to use internal calls to resolve names, we can fix this.
+                    // Second, maybe we want to switch to polling if this happens.   Probably not, but we need
+                    // to think this through.   So right now we're just using the semantics of regular sockets,
+                    // which we /have/ thought through.   So in the future we should do this think-through and
+                    // try to use NW Framework as it's intended to work rather than as if it were just sockets.
+                    ncs->connecting = mDNSfalse;
+                    nw_connection_cancel(connection);
+                } else if (state == nw_connection_state_failed) {
+                    // We tried to connect, but didn't succeed.
+                    LogMsg("dso_connect_internal: failed to connect to %s on %#a%%%d: %s%s",
+                           ncs->hostname, &ncs->addresses[ncs->cur_addr], ncs->ports[ncs->cur_addr],
+                           strerror(nw_error_get_error_code(error)), ncs->detail);
+                    nw_release(ncs->connection);
+                    ncs->connection = NULL;
+                    ncs->connecting = mDNSfalse;
+                    // This will do the work of figuring out if there are more addresses to try.
+                    mDNS_Lock(&mDNSStorage);
+                    dso_connect_internal(ncs);
+                    mDNS_Unlock(&mDNSStorage);
+                } else if (state == nw_connection_state_ready) {
+                    ncs->connecting = mDNSfalse;
+                    mDNS_Lock(&mDNSStorage);
+                    dso_connection_succeeded(ncs);
+                    mDNS_Unlock(&mDNSStorage);
+                } else if (state == nw_connection_state_cancelled) {
+                    if (ncs->connection) {
+                        nw_release(ncs->connection);
+                    }
+                    ncs->connection = NULL;
+                    ncs->connecting = mDNSfalse;
+                    // If we get here and cs exists, we are still trying to connect.   So do the next step.
+                    mDNS_Lock(&mDNSStorage);
+                    dso_connect_internal(ncs);
+                    mDNS_Unlock(&mDNSStorage);
+                }
+            }                
+            KQueueUnlock("dso_connect_internal state change handler");
+        });
+    nw_connection_start(connection);
+    cs->connecting = mDNStrue;
+}
+
+#else
+static void dso_connect_callback(TCPSocket *sock, void *context, mDNSBool connected, int err)
+{
+    dso_connect_state_t *cs = context;
+    char *detail;
+    int status;
+    dso_transport_t *transport;
+    mDNS *m = &mDNSStorage;
+
+    (void)connected;
+    mDNS_Lock(m);
+    detail = cs->detail;
+    
+    // If we had a socket open but the connect failed, close it and try the next address, if we have
+    // a next address.
+    if (sock != NULL) {
+        cs->last_event = m->timenow;
+
+        cs->connecting = mDNSfalse;
+        if (err != mStatus_NoError) {
+            mDNSPlatformTCPCloseConnection(sock);
+            LogMsg("dso_connect_callback: connect %p failed (%d)", cs, err);
+        } else {
+        success:
+            // We got a connection.
+            transport = dso_transport_create(sock, false, cs->context, cs->max_outstanding_queries,
+                                             cs->inbuf_size, cs->outbuf_size, cs->hostname, cs->callback, cs->dso);
+            if (transport == NULL) {
+                // If dso_create fails, there's no point in continuing to try to connect to new
+                // addresses
+            fail:
+                LogMsg("dso_connect_callback: dso_create failed");
+                mDNSPlatformTCPCloseConnection(sock);
+            } else {
+                // Call the "we're connected" callback, which will start things up.
+                transport->dso->cb(cs->context, NULL, transport->dso, kDSOEventType_Connected);
+            }
+
+            cs->last_event = 0;
+
+            // When the connection has succeeded, stop asking questions.
+            if (cs->lookup != NULL) {
+                DNSServiceRef ref = cs->lookup;
+                cs->lookup = NULL;
+                mDNS_DropLockBeforeCallback();
+                DNSServiceRefDeallocate(ref);
+                mDNS_ReclaimLockAfterCallback();
+            }
+            mDNS_Unlock(m);
+            return;
+        }
+    }
+
+    // If there are no addresses to connect to, and there are no queries running, then we can give
+    // up.  Otherwise, we wait for one of the queries to deliver an answer.
+    if (cs->num_addrs <= cs->cur_addr) {
+        if (cs->lookup == NULL) {
+            LogMsg("dso_connect_callback: %s: no more addresses to try", cs->hostname);
+            cs->last_event = 0;
+            cs->callback(cs->context, NULL, NULL, kDSOEventType_ConnectFailed);
+        }
+        // Otherwise, we will get more callbacks when outstanding queries either fail or succeed.
+        mDNS_Unlock(m);
+        return;
+    }            
+        
+    sock = mDNSPlatformTCPSocket(kTCPSocketFlags_Zero, cs->addresses[cs->cur_addr].type, NULL, NULL, mDNSfalse);
+    if (sock == NULL) {
+        LogMsg("drConnectCallback: couldn't get a socket for %s: %s%s",
+               cs->hostname, strerror(errno), detail);
+        goto fail;
+    }
+
+    LogMsg("dso_connect_callback: Attempting to connect to %#a%%%d",
+           &cs->addresses[cs->cur_addr], ntohs(cs->ports[cs->cur_addr].NotAnInteger));
+
+    status = mDNSPlatformTCPConnect(sock, &cs->addresses[cs->cur_addr], cs->ports[cs->cur_addr], NULL,
+                                    dso_connect_callback, cs);
+    cs->cur_addr++;
+    if (status == mStatus_NoError || status == mStatus_ConnEstablished) {
+        // This can't happen in practice on MacOS; we don't know about all other operating systems,
+        // so we handle it just in case.
+        LogMsg("dso_connect_callback: synchronous connect to %s", cs->hostname);
+        goto success;
+    } else if (status == mStatus_ConnPending) {
+        LogMsg("dso_connect_callback: asynchronous connect to %s", cs->hostname);
+        cs->connecting = mDNStrue;
+        // We should get called back when the connection succeeds or fails.
+        mDNS_Unlock(m);
+        return;
+    }
+    LogMsg("dso_connect_callback: failed to connect to %s on %#a%d: %s%s",
+           cs->hostname, &cs->addresses[cs->cur_addr],
+           ntohs(cs->ports[cs->cur_addr].NotAnInteger), strerror(errno), detail);
+    mDNS_Unlock(m);
+}
+
+static void dso_connect_internal(dso_connect_state_t *cs)
+{
+    dso_connect_callback(NULL, cs, false, mStatus_NoError);
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+static void dso_inaddr_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex,
+                                DNSServiceErrorType errorCode, const char *fullname, const struct sockaddr *sa,
+                                uint32_t ttl, void *context)
+{
+    dso_connect_state_t *cs = context;
+    char addrbuf[INET6_ADDRSTRLEN + 1];
+    mDNS *m = &mDNSStorage;
+    (void)sdRef;
+
+    cs->last_event = m->timenow;
+    inet_ntop(sa->sa_family, (sa->sa_family == AF_INET
+                              ? (void *)&((struct sockaddr_in *)sa)->sin_addr
+                              : (void *)&((struct sockaddr_in6 *)sa)->sin6_addr), addrbuf, sizeof addrbuf);
+    LogMsg("dso_inaddr_callback: %s: flags %x index %d error %d fullname %s addr %s ttl %lu",
+           cs->hostname, flags, interfaceIndex, errorCode, fullname, addrbuf, (unsigned long)ttl);
+    
+    if (errorCode != mStatus_NoError) {
+        return;
+    }
+
+    if (cs->num_addrs == MAX_DSO_CONNECT_ADDRS) {
+        if (cs->cur_addr > 1) {
+            memmove(&cs->addresses, &cs->addresses[cs->cur_addr],
+                    (MAX_DSO_CONNECT_ADDRS - cs->cur_addr) * sizeof cs->addresses[0]);
+            cs->num_addrs -= cs->cur_addr;
+            cs->cur_addr = 0;
+        } else {
+            LogMsg("dso_inaddr_callback: ran out of room for addresses.");
+            return;
+        }
+    }
+
+    if (sa->sa_family == AF_INET) {
+        cs->addresses[cs->num_addrs].type = mDNSAddrType_IPv4;
+        mDNSPlatformMemCopy(&cs->addresses[cs->num_addrs].ip.v4,
+                            &((struct sockaddr_in *)sa)->sin_addr, sizeof cs->addresses[cs->num_addrs].ip.v4);
+    } else {
+        cs->addresses[cs->num_addrs].type = mDNSAddrType_IPv6;
+        mDNSPlatformMemCopy(&cs->addresses[cs->num_addrs].ip.v6,
+                            &((struct sockaddr_in *)sa)->sin_addr, sizeof cs->addresses[cs->num_addrs].ip.v6);
+    }
+
+    cs->ports[cs->num_addrs] = cs->config_port;
+    cs->num_addrs++;
+    if (!cs->connecting) {
+        LogMsg("dso_inaddr_callback: starting a new connection.");
+        dso_connect_internal(cs);
+    } else {
+        LogMsg("dso_inaddr_callback: connection in progress, deferring new connect until it fails.");
+    }
+}
+
+bool dso_connect(dso_connect_state_t *cs)
+{
+    struct in_addr in;
+    struct in6_addr in6;
+
+    // If the connection state was created with an address, use that rather than hostname.
+    if (cs->num_addrs > 0) {
+        dso_connect_internal(cs);
+    }
+    // Else allow an IPv4 address literal string
+    else if (inet_pton(AF_INET, cs->hostname, &in)) {
+        cs->num_addrs = 1;
+        cs->addresses[0].type = mDNSAddrType_IPv4;
+        cs->addresses[0].ip.v4.NotAnInteger = in.s_addr;
+        cs->ports[0] = cs->config_port;
+        dso_connect_internal(cs);
+    }
+    // ...or an IPv6 address literal string
+    else if (inet_pton(AF_INET6, cs->hostname, &in6)) {
+        cs->num_addrs = 1;
+        cs->addresses[0].type = mDNSAddrType_IPv6;
+        memcpy(&cs->addresses[0].ip.v6, &in6, sizeof in6);
+        cs->ports[0] = cs->config_port;
+        dso_connect_internal(cs);
+    }
+    // ...or else look it up.
+    else {
+        mDNS *m = &mDNSStorage;
+        int err;
+        mDNS_DropLockBeforeCallback();
+        err = DNSServiceGetAddrInfo(&cs->lookup, kDNSServiceFlagsReturnIntermediates,
+                                    kDNSServiceInterfaceIndexAny, 0, cs->hostname, dso_inaddr_callback, cs);
+
+        mDNS_ReclaimLockAfterCallback();
+        if (err != mStatus_NoError) {
+            LogMsg("dso_connect: inaddr lookup query allocate failed for '%s': %d", cs->hostname, err);
+            return false;
+        }
+    }
+    return true;
+}
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+// We don't need this for DNS Push, so it is being left as future work.
+int dso_listen(dso_connect_state_t * __unused listen_context)
+{
+    return mStatus_UnsupportedErr;
+}
+
+#else
+
+// Called whenever we get a connection on the DNS TCP socket
+static void dso_listen_callback(TCPSocket *sock, mDNSAddr *addr, mDNSIPPort *port,
+                                const char *remote_name, void *context)
+{
+    dso_connect_state_t *lc = context;
+    dso_transport_t *transport;
+
+    mDNS_Lock(&mDNSStorage);
+    transport = dso_transport_create(sock, mDNStrue, lc->context, lc->max_outstanding_queries,
+                                     lc->inbuf_size, lc->outbuf_size, remote_name, lc->callback, NULL);
+    if (transport == NULL) {
+        mDNSPlatformTCPCloseConnection(sock);
+        LogMsg("No memory for new DSO connection from %s", remote_name);
+        goto out;
+    }
+
+    transport->remote_addr = *addr;
+    transport->remote_port = ntohs(port->NotAnInteger);
+    if (transport->dso->cb) {
+        transport->dso->cb(lc->context, 0, transport->dso, kDSOEventType_Connected);
+    }
+    LogMsg("DSO connection from %s", remote_name);
+out:
+    mDNS_Unlock(&mDNSStorage);
+}
+
+// Listen for connections; each time we get a connection, make a new dso_state_t object with the specified
+// parameters and call the callback.   Port can be zero to leave it unspecified.
+
+int dso_listen(dso_connect_state_t *listen_context)
+{
+    char addrbuf[INET6_ADDRSTRLEN + 1];
+    mDNSIPPort port;
+    mDNSBool reuseAddr = mDNSfalse;
+    
+    if (listen_context->config_port.NotAnInteger) {
+        port = listen_context->config_port;
+        reuseAddr = mDNStrue;
+    }
+    listen_context->listener = mDNSPlatformTCPListen(mDNSAddrType_None, &port, NULL, kTCPSocketFlags_Zero,
+                                                     reuseAddr, 5, dso_listen_callback, listen_context);
+    if (!listen_context->listener) {
+        return mStatus_UnknownErr;
+    }
+    listen_context->connect_port = port;
+    if (listen_context->addresses[0].type == mDNSAddrType_IPv4) {
+        inet_ntop(AF_INET, &listen_context->addresses[0].ip.v4, addrbuf, sizeof addrbuf);
+    } else {
+        inet_ntop(AF_INET6, &listen_context->addresses[0].ip.v6, addrbuf, sizeof addrbuf);
+    }
+    
+    LogMsg("DSOListen: Listening on %s%%%d", addrbuf, ntohs(listen_context->connect_port.NotAnInteger));
+    return mStatus_NoError;
+}
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/DSO/dso-transport.h b/DSO/dso-transport.h
new file mode 100644 (file)
index 0000000..827aec8
--- /dev/null
@@ -0,0 +1,143 @@
+/* dso-transport.h
+ *
+ * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __DSO_TRANSPORT_H
+#define __DSO_TRANSPORT_H
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+#include <Network/Network.h>
+#endif
+
+// Maximum number of IP addresses that we'll deal with as a result of looking up a name
+// to which to connect.
+#define MAX_DSO_CONNECT_ADDRS 16
+
+// Threshold above which we indicate that a DSO connection isn't writable.   This is advisory,
+// but e.g. for a Discovery Relay, if the remote proxy isn't consuming what we are sending, we
+// should start dropping packets on the floor rather than just queueing more and more packets.
+// 60k may actually be too much.   This is used when we're using NW Framework, because it doesn't
+// allow us to use TCP_NOTSENT_LOWAT directly.
+#define MAX_UNSENT_BYTES 60000
+
+struct dso_transport {
+    dso_state_t *dso;                     // DSO state for which this is the transport 
+    struct dso_transport *next;    // Transport is on list of transports.
+    void *event_context;           // I/O event context
+    mDNSAddr remote_addr;          // The IP address to which we have connected
+    int remote_port;               // The port to which we have connected
+
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    nw_connection_t connection;
+    dispatch_data_t to_write;
+    size_t bytes_to_write;
+    size_t unsent_bytes;
+    uint32_t serial;               // Serial number for locating possibly freed dso_transport_t structs
+    bool write_failed;             // This is set if any of the parts of the dso_write process fail
+#else
+    TCPSocket *connection;         // Socket connected to Discovery Proxy
+    size_t bytes_needed;
+    size_t message_length;         // Length of message we are currently accumulating, if known
+    uint8_t *inbuf;                // Buffer for incoming messages.
+    size_t inbuf_size;
+    uint8_t *inbufp;               // Current read pointer (may not be in inbuf)
+    bool need_length;              // True if we need a 2-byte length
+
+    uint8_t lenbuf[2];             // Buffer for storing the length in a DNS TCP message
+
+#define MAX_WRITE_HUNKS 4          // When writing a DSO message, we need this many separate hunks.
+    const uint8_t *to_write[MAX_WRITE_HUNKS];
+    ssize_t write_lengths[MAX_WRITE_HUNKS];
+    int num_to_write;
+#endif // DSO_USES_NETWORK_FRAMEWORK
+
+    uint8_t *outbuf;               // Output buffer for building and sending DSO messages
+    size_t outbuf_size;
+};
+
+typedef struct dso_lookup dso_lookup_t;
+struct dso_lookup {
+    dso_lookup_t *next;
+    DNSServiceRef sdref;
+};
+
+typedef struct dso_connect_state dso_connect_state_t;
+struct dso_connect_state {
+    dso_connect_state_t *next;
+    dso_event_callback_t callback;
+    dso_state_t *dso;
+    char *detail;
+    void *context;
+    TCPListener *listener;
+
+    char *hostname;
+    int num_addrs;
+    int cur_addr;
+    mDNSAddr addresses[MAX_DSO_CONNECT_ADDRS];
+    mDNSIPPort ports[MAX_DSO_CONNECT_ADDRS];
+    DNSServiceRef lookup;
+
+    mDNSBool connecting;
+    mDNSIPPort config_port, connect_port;
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+    uint32_t serial;
+    nw_connection_t connection;
+    bool tls_enabled;
+#else
+    size_t inbuf_size;
+#endif
+    size_t outbuf_size;
+    int max_outstanding_queries;
+    mDNSs32 last_event;
+    mDNSs32 reconnect_time;
+};
+
+typedef struct {
+       TCPListener *listener;
+    dso_event_callback_t callback;
+       void *context;
+} dso_listen_context_t;
+
+void dso_transport_init(void);
+mStatus dso_set_connection(dso_state_t *dso, TCPSocket *socket);
+void dso_schedule_reconnect(mDNS *m, dso_connect_state_t *cs, mDNSs32 when);
+void dso_set_callback(dso_state_t *dso, void *context, dso_event_callback_t cb);
+mStatus dso_message_write(dso_state_t *dso, dso_message_t *msg, bool disregard_low_water);
+dso_connect_state_t *dso_connect_state_create(const char *host, mDNSAddr *addr, mDNSIPPort port,
+                                              int num_outstanding_queries,
+                                              size_t inbuf_size, size_t outbuf_size,
+                                              dso_event_callback_t callback,
+                                              dso_state_t *dso, void *context, const char *detail);
+#ifdef DSO_USES_NETWORK_FRAMEWORK
+void dso_connect_state_use_tls(dso_connect_state_t *cs);
+#endif
+void dso_connect_state_drop(dso_connect_state_t *cs);
+bool dso_connect(dso_connect_state_t *connect_state);
+mStatus dso_listen(dso_connect_state_t *listen_context);
+bool dso_write_start(dso_transport_t *transport, size_t length);
+bool dso_write_finish(dso_transport_t *transport);
+void dso_write(dso_transport_t *transport, const uint8_t *buf, size_t length);
+#endif // __DSO_TRANSPORT_H
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/DSO/dso.c b/DSO/dso.c
new file mode 100644 (file)
index 0000000..eeef345
--- /dev/null
+++ b/DSO/dso.c
@@ -0,0 +1,764 @@
+/* dso.c
+ *
+ * Copyright (c) 2018-2019 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.
+ *
+ */
+
+//*************************************************************************************************************
+// Headers
+
+#include <stdio.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+
+#include <netdb.h>           // For gethostbyname()
+#include <sys/socket.h>      // For AF_INET, AF_INET6, etc.
+#include <net/if.h>          // For IF_NAMESIZE
+#include <netinet/in.h>      // For INADDR_NONE
+#include <netinet/tcp.h>     // For SOL_TCP, TCP_NOTSENT_LOWAT
+#include <arpa/inet.h>       // For inet_addr()
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "DNSCommon.h"
+#include "mDNSEmbeddedAPI.h"
+
+#include "dso.h"
+
+#ifdef STANDALONE
+#undef LogMsg
+#define LogMsg(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+#define mDNSRandom(x) arc4random_uniform(x)
+#define mDNSPlatformMemAllocateClear(length) calloc(1, length)
+#endif // STANDALONE
+
+//*************************************************************************************************************
+// Remaining work TODO
+
+// - Add keepalive/inactivity timeout support
+// - Notice if it takes a long time to get a response when establishing a session, and treat that
+//   as "DSO not supported."
+// - TLS support
+// - Actually use Network Framework
+
+
+//*************************************************************************************************************
+// Globals
+
+static dso_state_t *dso_connections;
+static dso_state_t *dso_connections_needing_cleanup; // DSO connections that have been shut down but aren't yet freed.
+static uint32_t dso_serial; // Used to uniquely mark DSO objects, incremented once for each dso_state_t created.
+
+dso_state_t *dso_find_by_serial(uint32_t serial)
+{
+    dso_state_t *dsop;
+
+    for (dsop = dso_connections; dsop; dsop = dsop->next) {
+        if (dsop->serial == serial) {
+            return dsop;
+        }
+    }
+    return NULL;
+}
+
+// This function is called either when an error has occurred requiring the a DSO connection be
+// dropped, or else when a connection to a DSO endpoint has been cleanly closed and is ready to be
+// dropped for that reason.
+
+void dso_drop(dso_state_t *dso)
+{
+    dso_state_t *dsop;
+    
+    if (dso_connections == dso) {
+        dso_connections = dso->next;
+    } else {
+        for (dsop = dso_connections; dsop != NULL && dsop->next != dso; dsop = dsop->next) {
+            LogMsg("dsop = %p dsop->next = %p dso = %p", dsop, dsop->next, dso);
+        }
+        if (dsop) {
+            dsop->next = dso->next;
+        // If we get to the end of the list without finding dso, it means that it's already
+        // been dropped.
+        } else {
+            return;
+        }
+    }
+    dso->next = dso_connections_needing_cleanup;
+    dso_connections_needing_cleanup = dso;
+}
+
+int64_t dso_idle(void *context, int64_t now, int64_t next_timer_event)
+{
+    dso_state_t *dso, *dnext;
+    dso_activity_t *ap, *anext;
+    
+    for (dso = dso_connections_needing_cleanup; dso; dso = dnext) {
+        dnext = dso->next;
+        // Finalize and then free any activities.
+        for (ap = dso->activities; ap; ap = anext) {
+            anext = ap->next;
+            if (ap->finalize) {
+                ap->finalize(ap);
+            }
+            free(ap);
+        }
+        if (dso->transport != NULL && dso->transport_finalize != NULL) {
+            dso->transport_finalize(dso->transport);
+            dso->transport = NULL;
+        }
+        if (dso->cb) {
+            dso_disconnect_context_t disconnect_context;
+            memset(&disconnect_context, 0, sizeof disconnect_context);
+            dso->cb(dso->context, &disconnect_context, dso, kDSOEventType_Disconnected);
+            dso->cb(dso->context, NULL, dso, kDSOEventType_Finalize);
+        } else {
+            free(dso);
+        }
+    }
+    dso_connections_needing_cleanup = NULL;
+
+    // Do keepalives.
+    for (dso = dso_connections; dso; dso = dso->next) {
+        if (dso->inactivity_due == 0) {
+            if (dso->inactivity_timeout != 0) {
+                dso->inactivity_due = now + dso->inactivity_timeout;
+                if (next_timer_event - dso->keepalive_due > 0) {
+                    next_timer_event = dso->keepalive_due;
+                }
+            }
+        } else if (now - dso->inactivity_due > 0 && dso->cb != NULL) {
+            dso->cb(dso->context, 0, dso, kDSOEventType_Inactive);
+        }
+        if (dso->keepalive_due != 0 && dso->keepalive_due < now && dso->cb != NULL) {
+            dso_keepalive_context_t kc;
+            memset(&kc, 0, sizeof kc);
+            dso->cb(dso->context, &kc, dso, kDSOEventType_Keepalive);
+            dso->keepalive_due = now + dso->keepalive_interval;
+            if (next_timer_event - dso->keepalive_due > 0) {
+                next_timer_event = dso->keepalive_due;
+            }
+        }
+    }
+    return dso_transport_idle(context, now, next_timer_event);
+}
+
+// Called when something happens that establishes a DSO session.
+static void dso_session_established(dso_state_t *dso)
+{
+    dso->has_session = true;
+    // Set up inactivity timer and keepalive timer...
+}
+
+// Create a dso_state_t structure
+dso_state_t *dso_create(bool is_server, int max_outstanding_queries, const char *remote_name,
+                        dso_event_callback_t callback, void *context, dso_transport_t *transport)
+{
+    dso_state_t *dso;
+    int namelen = strlen(remote_name) + 1;
+    int outsize = (sizeof (dso_outstanding_query_state_t)) + max_outstanding_queries * sizeof (dso_outstanding_query_t);
+
+    // We allocate everything in a single hunk so that we can free it together as well.
+    dso = (dso_state_t *) mDNSPlatformMemAllocateClear((sizeof *dso) + outsize + namelen);
+    if (dso == NULL) {
+        goto out;
+    }
+    dso->outstanding_queries = (dso_outstanding_query_state_t *)(dso + 1);
+    dso->outstanding_queries->max_outstanding_queries = max_outstanding_queries;
+
+    dso->remote_name = ((char *)dso->outstanding_queries) + outsize;
+    memcpy(dso->remote_name, remote_name, namelen);
+    dso->remote_name[namelen] = 0;
+
+    dso->cb = callback;
+    dso->context = context;
+    dso->transport = transport;
+    dso->is_server = is_server;
+    dso->serial = dso_serial++;
+
+    dso->next = dso_connections;
+    dso_connections = dso;
+out:
+    return dso;
+}
+
+// Start building a TLV in an outgoing dso message.
+void dso_start_tlv(dso_message_t *state, int opcode)
+{
+    // Make sure there's room for the length and the TLV opcode.
+    if (state->cur + 4 >= state->max) {
+        LogMsg("dso_start_tlv called when no space in output buffer!");
+        assert(0);
+    }
+
+    // We need to not yet have a TLV.
+    if (state->building_tlv) {
+        LogMsg("dso_start_tlv called while already building a TLV!");
+        assert(0);
+    }
+    state->building_tlv = true;
+    state->tlv_len = 0;
+    
+    // Set up the TLV header.
+    state->buf[state->cur] = opcode >> 8;
+    state->buf[state->cur + 1] = opcode & 255;
+    state->tlv_len_offset = state->cur + 2;
+    state->cur += 4;
+}
+
+// Add some bytes to a TLV that's being built, but don't copy them--just remember the
+// pointer to the buffer.   This is used so that when we have a message to forward, we
+// don't copy it into the output buffer--we just use scatter/gather I/O.
+void dso_add_tlv_bytes_no_copy(dso_message_t *state, const uint8_t *bytes, size_t len)
+{
+    if (!state->building_tlv) {
+        LogMsg("add_tlv_bytes called when not building a TLV!");
+        assert(0);
+    }
+    if (state->no_copy_bytes_len) {
+        LogMsg("add_tlv_bytesNoCopy called twice on the same DSO message.");
+        assert(0);
+    }
+    state->no_copy_bytes_len = len;
+    state->no_copy_bytes = bytes;
+    state->no_copy_bytes_offset = state->cur;
+    state->tlv_len += len;
+}
+
+// Add some bytes to a TLV that's being built.
+void dso_add_tlv_bytes(dso_message_t *state, const uint8_t *bytes, size_t len)
+{
+    if (!state->building_tlv) {
+        LogMsg("add_tlv_bytes called when not building a TLV!");
+        assert(0);
+    }
+    if (state->cur + len > state->max) {
+        LogMsg("add_tlv_bytes called with no room in output buffer.");
+        assert(0);
+    }
+    memcpy(&state->buf[state->cur], bytes, len);
+    state->cur += len;
+    state->tlv_len += len;
+}
+
+// Add a single byte to a TLV that's being built.
+void dso_add_tlv_byte(dso_message_t *state, uint8_t byte)
+{
+    if (!state->building_tlv) {
+        LogMsg("dso_add_tlv_byte called when not building a TLV!");
+        assert(0);
+    }
+    if (state->cur + 1 > state->max) {
+        LogMsg("dso_add_tlv_byte called with no room in output buffer.");
+        assert(0);
+    }
+    state->buf[state->cur++] = byte;
+    state->tlv_len++;
+}
+
+// Add an uint16_t to a TLV that's being built.
+void dso_add_tlv_u16(dso_message_t *state, uint16_t u16)
+{
+    if (!state->building_tlv) {
+        LogMsg("dso_add_tlv_u16 called when not building a TLV!");
+        assert(0);
+    }
+    if ((state->cur + sizeof u16) > state->max) {
+        LogMsg("dso_add_tlv_u16 called with no room in output buffer.");
+        assert(0);
+    }
+    state->buf[state->cur++] = u16 >> 8;
+    state->buf[state->cur++] = u16 & 255;
+    state->tlv_len += 2;
+}
+
+// Add an uint32_t to a TLV that's being built.
+void dso_add_tlv_u32(dso_message_t *state, uint32_t u32)
+{
+    if (!state->building_tlv) {
+        LogMsg("dso_add_tlv_u32 called when not building a TLV!");
+        assert(0);
+    }
+    if ((state->cur + sizeof u32) > state->max) {
+        LogMsg("dso_add_tlv_u32 called with no room in output buffer.");
+        assert(0);
+    }
+    state->buf[state->cur++] = u32 >> 24;
+    state->buf[state->cur++] = (u32 >> 16) & 255;
+    state->buf[state->cur++] = (u32 >> 8) & 255;
+    state->buf[state->cur++] = u32 & 255;
+    state->tlv_len += 4;
+}
+
+// Finish building a TLV.
+void dso_finish_tlv(dso_message_t *state)
+{
+    if (!state->building_tlv) {
+        LogMsg("dso_finish_tlv called when not building a TLV!");
+        assert(0);
+    }
+
+    // A TLV can't be longer than this.
+    if (state->tlv_len > 65535) {
+        LogMsg("dso_finish_tlv was given more than 65535 bytes of TLV payload!");
+        assert(0);
+    }
+    state->buf[state->tlv_len_offset] = state->tlv_len >> 8;
+    state->buf[state->tlv_len_offset + 1] = state->tlv_len & 255;
+    state->tlv_len = 0;
+    state->building_tlv = false;
+}
+
+dso_activity_t *dso_find_activity(dso_state_t *dso, const char *name, const char *activity_type, void *context)
+{
+    dso_activity_t *activity;
+
+    // If we haven't been given something to search for, don't search.
+    if (name == NULL && context == NULL) {
+        return NULL;
+    }
+        
+    // An activity can be identified by name or context, but if name is present, that's what identifies it.
+    for (activity = dso->activities; activity; activity = activity->next) {
+        if (activity->activity_type == activity_type && ((activity->name == NULL || name == NULL|| !strcmp(activity->name, name)) &&
+                                                         (context == NULL && context == activity->context))) {
+            return activity;
+        }
+    }
+    return NULL;
+}
+
+// Make an activity structure to hang off the DSO.
+dso_activity_t *dso_add_activity(dso_state_t *dso, const char *name, const char *activity_type,
+                                 void *context, void (*finalize)(dso_activity_t *))
+{
+    size_t namelen = name ? strlen(name) + 1 : 0;
+    size_t len;
+    dso_activity_t *activity;
+    void *ap;
+
+    // Shouldn't add an activity that's already been added.
+    activity = dso_find_activity(dso, name, activity_type, context);
+    if (activity != NULL) {
+        LogMsg("dso_add_activity: activity %s%s%p added twice.", name ? name : "", name ? " " : "", context);
+        return NULL;
+    }
+
+    len = namelen + sizeof *activity;
+    ap = mDNSPlatformMemAllocateClear(len);
+    if (ap == NULL) {
+        return NULL;
+    }
+    activity = (dso_activity_t *)ap;
+    ap = (char *)ap + sizeof *activity;
+
+    // Activities can be identified either by name or by context
+    if (namelen) {
+        activity->name = ap;
+        memcpy(activity->name, name, namelen);
+    } else {
+        activity->name = NULL;
+    }
+    activity->context = context;
+
+    // Activity type is expected to be a string constant; all activities of the same type must
+    // reference the same constant, not different constants with the same contents.
+    activity->activity_type = activity_type;
+    activity->finalize = finalize;
+
+    // Retain this activity on the list.
+    activity->next = dso->activities;
+    dso->activities = activity;
+    return activity;
+}
+
+void dso_drop_activity(dso_state_t *dso, dso_activity_t *activity)
+{
+    dso_activity_t **app = &dso->activities;
+    bool matched = false;
+
+    // Remove this activity from the list.
+    while (*app) {
+        if (*app == activity) {
+            *app = activity->next;
+            matched = true;
+        } else {
+            app = &((*app)->next);
+        }
+    }
+
+    // If an activity that's not on the DSO list is passed here, it's an internal consistency
+    // error that probably indicates something is corrupted.
+    if (!matched) {
+        LogMsg("dso_drop_activity: FATAL: activity that's not on the list has been dropped!");
+        assert(0);
+    }
+
+    activity->finalize(activity);
+    free(activity);
+}
+
+void dso_ignore_response(dso_state_t *dso, void *context)
+{
+    dso_outstanding_query_state_t *midState = dso->outstanding_queries;
+    int i;
+    for (i = 0; i < midState->max_outstanding_queries; i++) {
+        // The query is still be outstanding, and we want to know it when it comes back, but we forget the context,
+        // which presumably is a reference to something that's going away.
+        if (midState->queries[i].context == context) {
+            midState->queries[i].context = NULL;
+        }
+    }
+}
+
+bool dso_make_message(dso_message_t *state, uint8_t *outbuf, size_t outbuf_size,
+                      dso_state_t *dso, bool unidirectional, void *callback_state)
+{
+    DNSMessageHeader *msg_header;
+    dso_outstanding_query_state_t *midState = dso->outstanding_queries;
+
+    memset(state, 0, sizeof *state);
+    state->buf = outbuf;
+    state->max = outbuf_size;
+
+    // We need space for the TCP message length plus the DNS header.
+    if (state->max < sizeof *msg_header) {
+        LogMsg("dso_make_message: called without enough buffer space to store a DNS header!");
+        assert(0);
+    }
+
+    // This buffer should be 16-bit aligned.
+    msg_header = (DNSMessageHeader *)state->buf;
+    
+    // The DNS header for a DSO message is mostly zeroes
+    memset(msg_header, 0, sizeof *msg_header);
+    msg_header->flags.b[0] = kDNSFlag0_QR_Query | kDNSFlag0_OP_DSO;
+
+    // Servers can't send DSO messages until there's a DSO session.
+    if (dso->is_server && !dso->has_session) {
+        LogMsg("dso_make_message: FATAL: server attempting to make a DSO message with no session!");
+        assert(0);
+    }
+
+    // Response-requiring messages need to have a message ID.
+    if (!unidirectional) {
+        bool msg_id_ok = true;
+        uint16_t message_id;
+        int looping = 0;
+        int i, avail = -1;
+
+        // If we don't have room for another outstanding message, the caller should try
+        // again later.
+        if (midState->outstanding_query_count == midState->max_outstanding_queries) {
+            return false;
+        }
+        // Generate a random message ID.   This doesn't really need to be cryptographically sound
+        // (right?) because we're encrypting the whole data stream in TLS.
+        do {
+            // This would be a surprising fluke, but let's not get killed by it.
+            if (looping++ > 1000) {
+                return false;
+            }
+            message_id = mDNSRandom(65536);
+            msg_id_ok = true;
+            if (message_id == 0) {
+                msg_id_ok = false;
+            } else {
+                for (i = 0; i < midState->max_outstanding_queries; i++) {
+                    if (midState->queries[i].id == 0 && avail == -1) {
+                        avail = i;
+                    } else if (midState->queries[i].id == message_id) {
+                        msg_id_ok = false;
+                    }
+                }
+            }
+        } while (!msg_id_ok);
+        midState->queries[avail].id = message_id;
+        midState->queries[avail].context = callback_state;
+        midState->outstanding_query_count++;
+        msg_header->id.NotAnInteger = message_id;
+        state->outstanding_query_number = avail;
+    } else {
+        // Clients aren't allowed to send unidirectional messages until there's a session.
+        if (!dso->has_session) {
+            LogMsg("dso_make_message: FATAL: client making a DSO unidirectional message with no session!");
+            assert(0);
+        }
+        state->outstanding_query_number = -1;
+    }
+
+    state->cur = sizeof *msg_header;
+    return true;
+}
+
+size_t dso_message_length(dso_message_t *state)
+{
+    return state->cur + state->no_copy_bytes_len;
+}
+
+void dso_retry_delay(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    dso_disconnect_context_t context;
+    if (dso->cb) {
+        memset(&context, 0, sizeof context);
+        if (dso->primary.length != 4) {
+            LogMsg("Invalid DSO Retry Delay length %d from %s", dso->primary.length, dso->remote_name);
+            dso_send_formerr(dso, header);
+            return;
+        }
+        memcpy(&context, dso->primary.payload, dso->primary.length);
+        context.reconnect_delay = ntohl(context.reconnect_delay);
+        dso->cb(dso->context, &context, dso, kDSOEventType_RetryDelay);
+    }
+}
+
+void dso_keepalive(dso_state_t *dso, const DNSMessageHeader *header)
+{
+    dso_keepalive_context_t context;
+    memset(&context, 0, sizeof context);
+    if (dso->primary.length != 8) {
+        LogMsg("Invalid DSO Keepalive length %d from %s", dso->primary.length, dso->remote_name);
+        dso_send_formerr(dso, header);
+        return;
+    }
+    memcpy(&context, dso->primary.payload, dso->primary.length);
+    context.inactivity_timeout = ntohl(context.inactivity_timeout);
+    context.keepalive_interval = ntohl(context.keepalive_interval);
+    if (dso->is_server) {
+        if (dso->cb) {
+            if (dso->keepalive_interval < context.keepalive_interval) {
+                context.keepalive_interval = dso->keepalive_interval;
+            }
+            if (dso->inactivity_timeout < context.inactivity_timeout) {
+                context.inactivity_timeout = dso->inactivity_timeout;
+            }
+            dso->cb(dso->context, &context, dso, kDSOEventType_KeepaliveRcvd);
+        }
+    } else {
+        if (dso->keepalive_interval > context.keepalive_interval) {
+            dso->keepalive_interval = context.keepalive_interval;
+        }
+        if (dso->inactivity_timeout > context.inactivity_timeout) {
+            dso->inactivity_timeout = context.inactivity_timeout;
+        }
+    }    
+}
+
+// We received a DSO message; validate it, parse it and, if implemented, dispatch it.
+void dso_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length)
+{
+    int i;
+    size_t offset;
+    const DNSMessageHeader *header = (const DNSMessageHeader *)message;
+    int response = (header->flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Response;
+    dso_query_receive_context_t qcontext;
+
+    if (message_length < 12) {
+        LogMsg("dso_message_received: response too short: %ld bytes", (long)message_length);
+        dso_drop(dso);
+        goto out;
+    }
+
+    // See if we have sent a message for which a response is expected.
+    if (response) {
+        bool expected = false;
+        
+        // A zero ID on a response is not permitted.
+        if (header->id.NotAnInteger == 0) {
+            LogMsg("dso_message_received: response with id==0 received from %s", dso->remote_name);
+            dso_drop(dso);
+            goto out;
+        }
+        // It's possible for a DSO response to contain no TLVs, but if that's the case, the length
+        // should always be twelve.
+        if (message_length < 16 && message_length != 12) {
+            LogMsg("dso_message_received: response with bogus length==%ld received from %s", (long)message_length, dso->remote_name);
+            dso_drop(dso);
+            goto out;
+        }
+        for (i = 0; i < dso->outstanding_queries->max_outstanding_queries; i++) {
+            if (dso->outstanding_queries->queries[i].id == header->id.NotAnInteger) {
+                qcontext.query_context = dso->outstanding_queries->queries[i].context;
+                qcontext.rcode = header->flags.b[1] & kDNSFlag1_RC_Mask;
+                
+                // If we are a client, and we just got an acknowledgment, a session has been established.
+                if (!dso->is_server && !dso->has_session && (header->flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr) {
+                    dso_session_established(dso);
+                }
+                dso->outstanding_queries->queries[i].id = 0;
+                dso->outstanding_queries->queries[i].context = 0;
+                dso->outstanding_queries->outstanding_query_count--;
+                if (dso->outstanding_queries->outstanding_query_count < 0) {
+                    LogMsg("dso_message_receive: programming error: outstanding_query_count went negative.");
+                    assert(0);
+                }
+                // If there were no TLVs, we don't need to parse them.
+                expected = true;
+                if (message_length == 12) {
+                    dso->primary.opcode = 0;
+                    dso->primary.length = 0;
+                    dso->num_additls = 0;
+                }
+                break;
+            }
+        }
+
+        // This is fatal because we've received a response to a message we didn't send, so
+        // it's not just that we don't understand what was sent.
+        if (!expected) {
+            LogMsg("dso_message_received: fatal: %s sent %ld byte message, QR=1", dso->remote_name, (long)message_length);
+            dso_drop(dso);
+            goto out;
+        }
+    }
+
+    // Make sure that the DNS header is okay (QDCOUNT, ANCOUNT, NSCOUNT and ARCOUNT are all zero)
+    for (i = 0; i < 4; i++) {
+        if (message[4 + i * 2] != 0 || message[4 + i * 2 + 1] != 0) {
+            LogMsg("dso_message_received: fatal: %s sent %ld byte DSO message, %s is nonzero",
+                   dso->remote_name, (long)message_length,
+                   (i == 0 ? "QDCOUNT" : (i == 1 ? "ANCOUNT" : ( i == 2 ? "NSCOUNT" : "ARCOUNT"))));
+            dso_drop(dso);
+            goto out;
+        }
+    }
+
+    // Check that there is space for there to be a primary TLV
+    if (message_length < 16 && message_length != 12) {
+        LogMsg("dso_message_received: fatal: %s sent short (%ld byte) DSO message",
+               dso->remote_name, (long)message_length);
+
+        // Short messages are a fatal error. XXX check DSO document
+        dso_drop(dso);
+        goto out;
+    }
+    
+    // If we are a server, and we don't have a session, and this is a message, then we have now established a session.
+    if (!dso->has_session && dso->is_server && !response) {
+        dso_session_established(dso);
+    }
+
+    // If a DSO session isn't yet established, make sure the message is a request (if is_server) or a
+    // response (if not).
+    if (!dso->has_session && ((dso->is_server && response) || (!dso->is_server && !response))) {
+        LogMsg("dso_message_received: received a %s with no established session from %s",
+               response ? "response" : "request", dso->remote_name);
+        dso_drop(dso);
+    }
+
+    // Get the primary TLV and count how many TLVs there are in total
+    offset = 12;
+    while (offset < message_length) {
+        // Get the TLV opcode
+        int opcode = (((unsigned)message[offset]) << 8) + message[offset + 1];
+        // And the length
+        size_t length = (((unsigned)message[offset + 2]) << 8) + message[offset + 3];
+
+        // Is there room for the contents of this TLV?
+        if (length + offset > message_length) {
+            LogMsg("dso_message_received: fatal: %s: TLV (%d %ld) extends past end (%ld)",
+                   dso->remote_name, opcode, (long)length, (long)message_length);
+
+            // Short messages are a fatal error. XXX check DSO document
+            dso_drop(dso);
+            goto out;
+        }
+
+        // Is this the primary TLV?
+        if (offset == 12) {
+            dso->primary.opcode = opcode;
+            dso->primary.length = length;
+            dso->primary.payload = &message[offset + 4];
+            dso->num_additls = 0;
+        } else {
+            if (dso->num_additls < MAX_ADDITLS) {
+                dso->additl[dso->num_additls].opcode = opcode;
+                dso->additl[dso->num_additls].length = length;
+                dso->additl[dso->num_additls].payload = &message[offset + 4];
+                dso->num_additls++;
+            } else {
+                // XXX MAX_ADDITLS should be enough for all possible additional TLVs, so this
+                // XXX should never happen; if it does, maybe it's a fatal error.
+                LogMsg("dso_message_received: %s: ignoring additional TLV (%d %ld) in excess of %d",
+                       dso->remote_name, opcode, (long)length, MAX_ADDITLS);
+            }
+        }
+        offset += 4 + length;
+    }
+
+    // Call the callback with the message or response
+    if (dso->cb) {
+        if (message_length != 12 && dso->primary.opcode == kDSOType_Keepalive) {
+            dso_keepalive(dso, header);
+        } else if (message_length != 12 && dso->primary.opcode == kDSOType_RetryDelay) {
+            dso_retry_delay(dso, header);
+        } else {
+            if (response) {
+                dso->cb(dso->context, &qcontext, dso, kDSOEventType_DSOResponse);
+            } else {
+                dso->cb(dso->context, header, dso, kDSOEventType_DSOMessage);
+            }
+        }
+    }
+out:
+    ;
+}
+
+// This code is currently assuming that we won't get a DNS message, but that's not true.   Fix.
+void dns_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length)
+{
+    DNSMessageHeader *header;
+    int opcode, response;
+
+    // We can safely assume that the header is 16-bit aligned.
+    header = (DNSMessageHeader *)message;
+    opcode = header->flags.b[0] & kDNSFlag0_OP_Mask;
+    response = (header->flags.b[0] & kDNSFlag0_QR_Mask) == kDNSFlag0_QR_Response;
+
+    // Validate the length of the DNS message.
+    if (message_length < 12) {
+        LogMsg("dns_message_received: fatal: %s sent short (%ld byte) message",
+               dso->remote_name, (long)message_length);
+
+        // Short messages are a fatal error.
+        dso_drop(dso);
+        return;
+    }
+    
+    // This is not correct for the general case.
+    if (opcode != kDNSFlag0_OP_DSO) {
+        LogMsg("dns_message_received: %s sent %ld byte %s, QTYPE=%d",
+               dso->remote_name, (long)message_length, (response ? "response" : "request"), opcode);
+        if (dso->cb) {
+            dso->cb(dso->context, header, dso,
+                    response ? kDSOEventType_DNSMessage : kDSOEventType_DNSResponse);
+        }
+    } else {
+        dso_message_received(dso, message, message_length);
+    }
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/DSO/dso.h b/DSO/dso.h
new file mode 100644 (file)
index 0000000..13ad08a
--- /dev/null
+++ b/DSO/dso.h
@@ -0,0 +1,211 @@
+/* dso.h
+ *
+ * Copyright (c) 2018-2019 Apple Computer, Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __DSO_H
+#define __DSO_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+// Maximum number of additional TLVs we support in a DSO message.
+#define MAX_ADDITLS           10
+
+typedef enum {
+    kDSOType_Keepalive = 1,
+    kDSOType_RetryDelay = 2,
+    kDSOType_EncryptionPadding = 3,
+    kDSOType_DNSPushSubscribe = 0x40,
+    kDSOType_DNSPushUpdate = 0x41,
+    kDSOType_DNSPushUnsubscribe = 0x42,
+    kDSOType_DNSPushReconfirm = 0x43,
+    kDSOType_mDNSLinkRequest = 0xF901,
+    kDSOType_mDNSLinkDiscontinue = 0xF902,
+    kDSOType_mDNSMessage = 0xF903,
+    kDSOType_LinkIdentifier = 0xF904,
+    kDSOType_L2SourceAddress = 0xF905,
+    kDSOType_IPSourceAddress = 0xF906,
+    kDSOType_mDNSReportLinkChanges = 0xF907,
+    kDSOType_mDNSStopLinkChanges = 0xF908,
+    kDSOType_mDNSLinkAvailable = 0xF900,
+    kDSOType_mDNSLinkUnavailable = 0xF90a,
+    kDSOType_LinkPrefix = 0xf90b
+} dso_message_types_t;
+
+// When a DSO message arrives, or one that was sent is acknowledged, or the state of the DSO connection
+// changes, we need to call the user of the DSO connection.
+typedef enum {
+    kDSOEventType_DNSMessage,      // A DNS message that is not a DSO message
+    kDSOEventType_DNSResponse,     // A DNS response that is not a DSO response
+    kDSOEventType_DSOMessage,      // DSOState.primary and DSOState.additl will contain the message TLVs;
+                                   // header will contain the DNS header
+    kDSOEventType_Finalize,        // The DSO connection to the other DSO endpoint has terminated and we are
+                                   // in the idle loop.
+    kDSOEventType_DSOResponse,     // DSOState.primary and DSOState.additl contain any TLVs in the response;
+                                   // header contains the DNS header
+    kDSOEventType_Connected,       // We succeeded in making a connection
+    kDSOEventType_ConnectFailed,   // We failed to get a connection
+    kDSOEventType_Disconnected,    // We were connected, but have disconnected or been disconnected
+    kDSOEventType_ShouldReconnect, // We are disconnected, and a scheduled reconnect timer has gone off.
+                                                          // Recipient is responsible for reconnecting, or deciding not to.
+    kDSOEventType_Inactive,               // We went inactive and the inactivity timeout expired, so it's time to drop the connection.
+    kDSOEventType_Keepalive,       // It's time to send a keepalive message, here are the values to send
+    kDSOEventType_KeepaliveRcvd,   // We just received a keepalive from a client, here are the values.
+    kDSOEventType_RetryDelay       // We got a RetryDelay from the server.   Have to shut down.
+} dso_event_type_t;
+
+typedef struct dso_outstanding_query {
+    uint16_t id;
+    void *context;
+} dso_outstanding_query_t;
+
+typedef struct dso_outstanding_query_state {
+    int outstanding_query_count;
+    int max_outstanding_queries;
+    dso_outstanding_query_t queries[0];
+} dso_outstanding_query_state_t;
+
+typedef struct dso_query_receive_context {
+    void *query_context;
+    uint16_t rcode;
+} dso_query_receive_context_t;
+
+typedef struct dso_disconnect_context {
+    uint32_t reconnect_delay;
+} dso_disconnect_context_t;
+
+typedef struct dso_keepalive_context {
+    uint32_t inactivity_timeout;
+    uint32_t keepalive_interval;
+} dso_keepalive_context_t;
+
+// Structure to represent received DSO TLVs
+typedef struct dsotlv {
+    uint16_t opcode;
+    uint16_t length;
+    const uint8_t *payload;
+} dso_tlv_t;
+
+// DSO message under construction
+typedef struct dso_message {
+    uint8_t *buf;                 // The buffer in which we are constructing the message
+    size_t max;                   // Size of the buffer
+    size_t cur;                   // Current position in the buffer
+    bool building_tlv;            // True if we have started and not finished building a TLV
+    int outstanding_query_number; // Number of the outstanding query state entry for this message, or -1
+    size_t tlv_len;               // Current length of the TLV we are building.
+    size_t tlv_len_offset;        // Where to store the length of the current TLV when finished.
+    const uint8_t *no_copy_bytes; // One TLV can have data that isn't copied into the buffer
+    size_t no_copy_bytes_len;     // Length of that data, if any.
+    size_t no_copy_bytes_offset;  // Where in the buffer the data should be interposed.
+} dso_message_t;
+
+// Record of ongoing activity
+typedef struct dso_activity dso_activity_t;
+struct dso_activity {
+    dso_activity_t *next;
+    void (*finalize)(dso_activity_t *activity);
+    const char *activity_type;  // Name of the activity type, must be the same pointer for all activities of a type.
+    void *context;              // Activity implementation's context (if any).
+    char *name;                 // Name of the individual activity
+};
+
+typedef struct dso_transport dso_transport_t;
+typedef struct dso_state dso_state_t;
+typedef int64_t event_time_t;
+
+typedef void (*dso_event_callback_t)(void *context, const void *header,
+                                     dso_state_t *dso, dso_event_type_t eventType);
+typedef void (*dso_transport_finalize_t)(dso_transport_t *transport);
+
+// DNS Stateless Operations state
+struct dso_state {
+    dso_state_t *next;
+    void *context;                   // The context of the next layer up (e.g., a Discovery Proxy)
+    dso_event_callback_t cb;         // Called when an event happens
+
+    // Transport state; handled separately for reusability
+    dso_transport_t *transport;                 // The transport (e.g., dso-transport.c or other).
+    dso_transport_finalize_t transport_finalize;
+
+    uint32_t serial;                 // Unique serial number which can be used after the DSO has been dropped.
+    bool is_server;                  // True if the endpoint represented by this DSO state is a server
+                                     // (according to the DSO spec)
+    bool has_session;                // True if DSO session establishment has happened for this DSO endpoint
+    event_time_t response_awaited;   // If we are waiting for a session-establishing response, when it's
+                                     // expected; otherwise zero.
+    uint32_t keepalive_interval;     // Time between keepalives (to be sent, on client, expected, on server)
+    uint32_t inactivity_timeout;     // Session can't be inactive more than this amount of time.
+    event_time_t keepalive_due;      // When the next keepalive is due (to be received or sent)
+    event_time_t inactivity_due;     // When next activity has to happen for connection to remain active
+    dso_activity_t *activities;      // Outstanding DSO activities.
+
+    dso_tlv_t primary;               // Primary TLV for current message
+    dso_tlv_t additl[MAX_ADDITLS];   // Additional TLVs
+    int num_additls;                 // Number of additional TLVs in this message
+
+    char *remote_name;
+
+    dso_outstanding_query_state_t *outstanding_queries;
+};
+
+// Provided by dso.c
+dso_state_t *dso_create(bool is_server, int max_outstanding_queries, const char *remote_name,
+                        dso_event_callback_t callback, void *context, dso_transport_t *transport);
+dso_state_t *dso_find_by_serial(uint32_t serial);
+void dso_drop(dso_state_t *dso);
+int64_t dso_idle(void *context, int64_t now, int64_t next_timer_event);
+void dso_release(dso_state_t **dsop);
+void dso_start_tlv(dso_message_t *state, int opcode);
+void dso_add_tlv_bytes(dso_message_t *state, const uint8_t *bytes, size_t len);
+void dso_add_tlv_bytes_no_copy(dso_message_t *state, const uint8_t *bytes, size_t len);
+void dso_add_tlv_byte(dso_message_t *state, uint8_t byte);
+void dso_add_tlv_u16(dso_message_t *state, uint16_t u16);
+void dso_add_tlv_u32(dso_message_t *state, uint32_t u32);
+void dso_finish_tlv(dso_message_t *state);
+dso_activity_t *dso_find_activity(dso_state_t *dso, const char *name, const char *activity_type, void *context);
+dso_activity_t *dso_add_activity(dso_state_t *dso, const char *name, const char *activity_type,
+                                            void *context, void (*finalize)(dso_activity_t *));
+void dso_drop_activity(dso_state_t *dso, dso_activity_t *activity);
+void dso_ignore_response(dso_state_t *dso, void *context);
+bool dso_make_message(dso_message_t *state, uint8_t *outbuf, size_t outbuf_size,
+                      dso_state_t *dso, bool unidirectional, void *callback_state);
+size_t dso_message_length(dso_message_t *state);
+void dso_retry_delay(dso_state_t *dso, const DNSMessageHeader *header);
+void dso_keepalive(dso_state_t *dso, const DNSMessageHeader *header);
+void dso_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length);
+void dns_message_received(dso_state_t *dso, const uint8_t *message, size_t message_length);
+
+// Provided by DSO transport implementation for use by dso.c:
+int64_t dso_transport_idle(void *context, int64_t now, int64_t next_timer_event);
+bool dso_send_simple_response(dso_state_t *dso, int rcode, const DNSMessageHeader *header, const char *pres);
+bool dso_send_not_implemented(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_refused(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_formerr(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_servfail(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_name_error(dso_state_t *dso, const DNSMessageHeader *header);
+bool dso_send_no_error(dso_state_t *dso, const DNSMessageHeader *header);
+#endif // !defined(__DSO_H)
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
index 68ba6b64da422351b2ef9e2196bf86de8406ed2d..4e38d77a9823ecc2aa6a1b882dc0bae9858b7307 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
 #
-# Top level makefile for Build & Integration.
+# Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+#
+# Top level makefile for Build & Integration (B&I).
 # 
-# This file is used to facilitate checking the mDNSResponder project
-# directly out of CVS and submitting to B&I at Apple.
+# This file is used to facilitate checking the mDNSResponder project directly from git and submitting to B&I at Apple.
 #
-# The various platform directories contain makefiles or projects
-# specific to that platform.
+# The various platform directories contain makefiles or projects specific to that platform.
 #
 #    B&I builds must respect the following target:
 #         install:
@@ -17,7 +17,7 @@
 
 include $(MAKEFILEPATH)/pb_makefiles/platform.make
 
-MVERS = "mDNSResponder-878.270.2"
+MVERS = "mDNSResponder-1096.0.2"
 
 VER =
 ifneq ($(strip $(GCC_VERSION)),)
@@ -25,31 +25,80 @@ ifneq ($(strip $(GCC_VERSION)),)
 endif
 echo "VER = $(VER)"
 
+projectdir     := $(SRCROOT)/mDNSMacOSX
+buildsettings  := OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT)
+
+.PHONY: install installSome installEmpty installExtras SystemLibraries installhdrs installapi installsrc java clean
+
+# B&I install build targets
+#
+# For the mDNSResponder build alias, the make target used by B&I depends on the platform:
+#
+#      Platform        Make Target
+#      --------        -----------
+#      osx             install
+#      ios             installSome
+#      atv             installSome
+#      watch           installSome
+#
+# For the mDNSResponderSystemLibraries and mDNSResponderSystemLibraries_sim build aliases, B&I uses the SystemLibraries
+# target for all platforms.
+
+install:
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Services' $(VER)
+else
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) $(VER)
+endif
+
 installSome:
-ifneq ($(findstring iphoneos, $(shell echo '$(SDKROOT)' | tr '[:upper:]' '[:lower:]')),)
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some\ iOS $(VER)
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Services' $(VER)
 else
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target Build\ Some $(VER)
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) $(VER)
 endif
 
-SystemLibraries:
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target SystemLibraries $(VER) 
+installEmpty:
+       mkdir -p $(DSTROOT)/AppleInternal
 
-install:
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install     OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) $(VER) 
+installExtras:
+ifeq ($(RC_PROJECT_COMPILATION_PLATFORM), osx)
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Extras-macOS' $(VER)
+else ifeq ($(RC_PROJECT_COMPILATION_PLATFORM), ios)
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Extras-iOS' $(VER)
+else
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) -target 'Build Extras' $(VER)
+endif
 
-installsrc:
-       ditto . "$(SRCROOT)"
+SystemLibraries:
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) -target SystemLibraries $(VER)
+
+# B&I installhdrs build targets
 
 installhdrs::
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT)  -target SystemLibraries $(VER)
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installhdrs OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT)  -target dns_services $(VER)
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+       cd '$(projectdir)'; xcodebuild installhdrs $(buildsettings) -target 'Build Services' $(VER)
+else ifneq ($(findstring SystemLibraries,$(RC_ProjectName)),)
+       cd '$(projectdir)'; xcodebuild installhdrs $(buildsettings) -target SystemLibraries $(VER)
+endif
+
+# B&I installapi build targets
 
 installapi:
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild installapi  OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT)  -target SystemLibrariesDynamic $(VER)
+ifeq ($(RC_ProjectName), mDNSResponderServices)
+       cd '$(projectdir)'; xcodebuild installapi $(buildsettings) -target 'Build Services' $(VER)
+else ifneq ($(findstring SystemLibraries,$(RC_ProjectName)),)
+       cd '$(projectdir)'; xcodebuild installapi $(buildsettings) -target SystemLibrariesDynamic $(VER)
+endif
+
+# Misc. targets
+
+installsrc:
+       ditto . '$(SRCROOT)'
+       rm -rf '$(SRCROOT)/mDNSWindows' '$(SRCROOT)/Clients/FirefoxExtension'
 
 java:
-       cd "$(SRCROOT)/mDNSMacOSX"; xcodebuild install  OBJROOT=$(OBJROOT) SYMROOT=$(SYMROOT) DSTROOT=$(DSTROOT) MVERS=$(MVERS) SDKROOT=$(SDKROOT) -target libjdns_sd.jnilib $(VER)
+       cd '$(projectdir)'; xcodebuild install $(buildsettings) -target libjdns_sd.jnilib $(VER)
 
 clean::
        echo clean
index 86b041ee821288eea2e9e231fc5bbc81e9d20330..cf6091c86db93904cbf9cc6c01830ea80f1d50b8 100644 (file)
@@ -93,8 +93,8 @@ The "mDNS Core" layer in turn calls through to the "Platform Support"
 layer to send and receive the multicast UDP packets to do the actual work.
 
 Apple currently provides "Platform Support" layers for Mac OS 9, Mac OS X,
-Microsoft Windows, VxWorks, and for POSIX platforms like Linux, Solaris,
-FreeBSD, etc.
+Microsoft Windows, and for POSIX platforms like Linux, Solaris, FreeBSD,
+etc.
 
 Note: Developers writing applications for OS X do not need to incorporate
 this code into their applications, since OS X provides a system service to
diff --git a/ServiceRegistration/.gitignore b/ServiceRegistration/.gitignore
new file mode 100644 (file)
index 0000000..d041cfb
--- /dev/null
@@ -0,0 +1 @@
+.depfile*
diff --git a/ServiceRegistration/Makefile b/ServiceRegistration/Makefile
new file mode 100644 (file)
index 0000000..34ba931
--- /dev/null
@@ -0,0 +1,60 @@
+SRPCFLAGS = -O0 -g -Wall -Werror -DSTANDALONE -I../mDNSCore -I/usr/local/include -I. -I../mDNSShared -I../DSO -MMD -MF .depfile-${notdir $<}
+LINKOPTS = -lmbedcrypto
+
+BUILDDIR = build
+OBJDIR = objects
+
+all:   setup $(BUILDDIR)/srp-simple $(BUILDDIR)/srp-gw $(BUILDDIR)/keydump $(BUILDDIR)/dnssd-proxy
+
+# 'setup' sets up the build directory structure the way we want
+setup:
+       @if test ! -d $(OBJDIR)   ; then mkdir -p $(OBJDIR)   ; fi
+       @if test ! -d $(BUILDDIR) ; then mkdir -p $(BUILDDIR) ; fi
+
+# clean removes targets and objects
+clean:
+       @if test -d $(OBJDIR)   ; then rm -r $(OBJDIR)   ; fi
+       @if test -d $(BUILDDIR) ; then rm -r $(BUILDDIR) ; fi
+
+SIGNOBJS     = $(OBJDIR)/sign-mbedtls.o 
+SIMPLEOBJS   = $(OBJDIR)/towire.o $(SIGNOBJS)
+DSOOBJS      = $(OBJDIR)/dso.o
+MDNSOBJS     = $(OBJDIR)/dnssd_clientstub.o $(OBJDIR)/dnssd_ipc.o
+VERIFYOBJS   = $(OBJDIR)/verify-mbedtls.o
+FROMWIREOBJS = $(OBJDIR)/fromwire.o $(VERIFYOBJS)
+IOOBJS       = $(OBJDIR)/ioloop.o
+
+$(BUILDDIR)/dnssd-proxy:  $(OBJDIR)/dnssd-proxy.o $(SIMPLEOBJS) $(DSOOBJS) $(MDNSOBJS) $(FROMWIREOBJS) $(IOOBJS)
+       $(CC) -o $@ $+ $(LINKOPTS)
+
+$(BUILDDIR)/srp-simple:        $(OBJDIR)/srp-simple.o $(SIMPLEOBJS)
+       $(CC) -o $@ $+ $(LINKOPTS)
+
+$(BUILDDIR)/srp-gw:    $(OBJDIR)/srp-gw.o $(SIMPLEOBJS) $(FROMWIREOBJS) $(IOOBJS)
+       $(CC) -o $@ $+ $(LINKOPTS)
+
+$(BUILDDIR)/keydump:   $(OBJDIR)/keydump.o $(SIMPLEOBJS) $(FROMWIREOBJS)
+       $(CC) -o $@ $+ $(LINKOPTS)
+
+$(OBJDIR)/dso.o:       ../DSO/dso.c
+       $(CC) -o $@ $(SRPCFLAGS) -c -I. -I../mDNSShared $<
+
+$(OBJDIR)/dnssd_clientstub.o:  ../mDNSShared/dnssd_clientstub.c
+       $(CC) -o $@ $(SRPCFLAGS) -c -I. -I../mDNSShared $<
+
+$(OBJDIR)/dnssd_ipc.o:  ../mDNSShared/dnssd_ipc.c
+       $(CC) -o $@ $(SRPCFLAGS) -c -I. -I../mDNSShared $<
+
+$(OBJDIR)/%.o: %.c
+       $(CC) -o $@ $(SRPCFLAGS) -c  $<
+
+-include .depfile-dnssd-proxy.c
+-include .depfile-fromwire.c
+-include .depfile-ioloop.c
+-include .depfile-keydump.c
+-include .depfile-sign-mbedtls.c
+-include .depfile-srp-gw.c
+-include .depfile-srp-simple.c
+-include .depfile-towire.c
+-include .depfile-verify-mbedtls.c
+-include .depfile-dso.c
diff --git a/ServiceRegistration/dns-msg.h b/ServiceRegistration/dns-msg.h
new file mode 100644 (file)
index 0000000..93d5d96
--- /dev/null
@@ -0,0 +1,435 @@
+/* dns-msg.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Lightweight framework for generating, sending, and unpacking DNS messages.
+ * Definitions...
+ */
+
+#ifndef __DNS_MSG_H
+#define __DNS_MSG_H
+
+#ifndef DNS_MAX_UDP_PAYLOAD
+#define DNS_MAX_UDP_PAYLOAD 1410
+#endif
+
+#define DNS_HEADER_SIZE           12
+#define DNS_DATA_SIZE             (DNS_MAX_UDP_PAYLOAD - DNS_HEADER_SIZE)
+#define DNS_MAX_POINTER           ((2 << 14) - 1)
+#define DNS_MAX_LABEL_SIZE        63
+#define DNS_MAX_NAME_SIZE            255
+#define DNS_MAX_NAME_SIZE_ESCAPED 1009
+
+typedef struct dns_wire dns_wire_t;
+struct dns_wire {
+    uint16_t id;
+    uint16_t bitfield;
+    uint16_t qdcount;
+    uint16_t ancount;
+    uint16_t nscount;
+    uint16_t arcount;
+    uint8_t data[DNS_DATA_SIZE];
+};
+
+typedef struct dns_towire_state dns_towire_state_t;
+struct dns_towire_state {
+       dns_wire_t *NULLABLE message;
+    uint8_t *NONNULL p;
+    uint8_t *NONNULL lim;
+    uint8_t *NULLABLE p_rdlength;
+    uint8_t *NULLABLE p_opt;
+    int error;
+};
+
+typedef struct dns_transaction dns_transaction_t;
+struct dns_transaction {
+    dns_transaction_t *NULLABLE next;
+    dns_towire_state_t towire;
+    dns_wire_t *NULLABLE response;
+    int response_length;
+    int sock;
+};    
+
+typedef struct dns_name_pointer dns_name_pointer_t;
+struct dns_name_pointer {
+    uint8_t *NONNULL message_start;
+    uint8_t *NONNULL name_start;
+    int num_labels;
+    int length;
+};
+
+typedef void (*dns_response_callback_t)(dns_transaction_t *NONNULL txn);
+
+typedef struct dns_label dns_label_t;
+typedef dns_label_t dns_name_t;
+struct dns_label {
+    dns_label_t *NULLABLE next;
+    uint8_t len;
+    char data[DNS_MAX_LABEL_SIZE];
+};
+
+typedef struct dns_txt_element dns_txt_element_t;
+struct dns_txt_element {
+    dns_txt_element_t *NULLABLE next;
+    uint8_t len;
+    char data[0];
+};
+
+typedef struct dns_rdata_unparsed dns_rdata_unparsed_t;
+struct dns_rdata_unparsed {
+    uint8_t *NULLABLE data;
+    uint16_t len;
+};
+
+typedef struct dns_rdata_single_name dns_rdata_ptr_t;
+typedef struct dns_rdata_single_name dns_rdata_cname_t;
+struct dns_rdata_single_name {
+    dns_label_t *NONNULL name;
+};
+
+typedef struct dns_rdata_a dns_rdata_a_t;
+struct dns_rdata_a {
+    struct in_addr *NONNULL addrs;
+    int num;
+};
+
+typedef struct dns_rdata_aaaa dns_rdata_aaaa_t;
+struct dns_rdata_aaaa {
+    struct in6_addr *NONNULL addrs;
+    int num;
+} aaaa;
+
+typedef struct dns_rdata_srv dns_rdata_srv_t;
+struct dns_rdata_srv {
+    dns_label_t *NONNULL name;
+    uint16_t priority;
+    uint16_t weight;
+    uint16_t port;
+} srv;
+
+typedef struct dns_rdata_sig dns_rdata_sig_t;
+struct dns_rdata_sig {
+    uint16_t type;
+    uint8_t algorithm;
+    uint8_t label;
+    uint32_t rrttl;
+    uint32_t expiry;
+    uint32_t inception;
+    uint16_t key_tag;
+    dns_label_t *NONNULL signer;
+    int start;
+    int len;
+    uint8_t *NONNULL signature;
+} sig;
+
+typedef struct dns_rdata_key dns_rdata_key_t;
+struct dns_rdata_key {
+    uint16_t flags;
+    uint8_t protocol;
+    uint8_t algorithm;
+    int len;
+    uint8_t *NONNULL key;
+} key;
+
+typedef struct dns_rr dns_rr_t;
+struct dns_rr {
+    dns_label_t *NONNULL name;
+    uint16_t type;
+    uint16_t qclass;
+    uint32_t ttl;
+    union {
+        dns_rdata_unparsed_t unparsed;
+        dns_rdata_ptr_t ptr;
+        dns_rdata_cname_t cname;
+        dns_rdata_a_t a;
+        dns_rdata_aaaa_t aaaa;
+        dns_rdata_srv_t srv;
+        dns_txt_element_t *NONNULL txt;
+        dns_rdata_sig_t sig;
+        dns_rdata_key_t key;
+    } data;
+};
+
+typedef struct dns_edns0 dns_edns0_t;
+struct dns_edns0 {
+    dns_edns0_t *NULLABLE next;
+    uint16_t length;
+    uint8_t data[0];
+};
+
+typedef struct dns_message dns_message_t;
+struct dns_message {
+    dns_wire_t *NULLABLE wire;
+    int qdcount, ancount, nscount, arcount;
+    dns_rr_t *NULLABLE questions;
+    dns_rr_t *NULLABLE answers;
+    dns_rr_t *NULLABLE authority;
+    dns_rr_t *NULLABLE additional;
+    dns_edns0_t *NULLABLE edns0;
+};
+
+// Masks for bitfield data
+#define dns_qr_mask     0x8000
+#define dns_opcode_mask 0x7800
+#define dns_flags_mask  0x07f0
+#define dns_rcode_mask  0x000f
+
+// Shifts for bitfield data
+#define dns_qr_shift     15
+#define dns_opcode_shift 11
+#define dns_rcode_shift  0
+
+// Booleans
+#define dns_flags_aa 0x0400
+#define dns_flags_tc 0x0200
+#define dns_flags_rd 0x0100
+#define dns_flags_ra 0x0080
+#define dns_flags_ad 0x0020
+#define dns_flags_cd 0x0010
+
+// Getters
+#define dns_qr_get(w) ((ntohs((w)->bitfield) & dns_qr_mask) >> dns_qr_shift)
+#define dns_opcode_get(w) ((ntohs((w)->bitfield) & dns_opcode_mask) >> dns_opcode_shift)
+#define dns_rcode_get(w) ((ntohs((w)->bitfield) & dns_rcode_mask) >> dns_rcode_shift)
+
+// Setters
+#define dns_qr_set(w, value) ((w)->bitfield = htons(((ntohs((w)->bitfield) & ~dns_qr_mask) | \
+                                                     ((value) << dns_qr_shift))))
+#define dns_opcode_set(w, value) ((w)->bitfield = htons(((ntohs((w)->bitfield) & ~dns_opcode_mask) | \
+                                                         ((value) << dns_opcode_shift))))
+#define dns_rcode_set(w, value) ((w)->bitfield = htons(((ntohs((w)->bitfield) & ~dns_rcode_mask) | \
+                                                        ((value) << dns_rcode_shift))))
+
+// Query/Response
+#define dns_qr_query           0
+#define dns_qr_response        1
+
+// Opcodes
+#define dns_opcode_query       0
+#define dns_opcode_iquery      1
+#define dns_opcode_status      2
+#define dns_opcode_notify      4
+#define dns_opcode_update      5
+#define dns_opcode_dso         6
+
+// Response Codes
+#define dns_rcode_noerror      0 // [RFC1035] No Error
+#define dns_rcode_formerr      1 // [RFC1035] Format Error
+#define dns_rcode_servfail     2 // [RFC1035] Server Failure
+#define dns_rcode_nxdomain     3 // [RFC1035] Non-Existent Domain
+#define dns_rcode_notimp       4 // [RFC1035] Not Implemented
+#define dns_rcode_refused      5 // [RFC1035] Query Refused
+#define dns_rcode_yxdomain     6 // [RFC2136][RFC6672] Name Exists when it should not
+#define dns_rcode_yxrrset      7 // [RFC2136] RR Set Exists when it should not
+#define dns_rcode_nxrrset      8 // [RFC2136] RR Set that should exist does not
+#define dns_rcode_notauth      9 // [RFC2136] Server Not Authoritative for zone, or [RFC2845] Not Authorized
+#define dns_rcode_notzone     10 // [RFC2136] Name not contained in zone
+#define dns_rcode_dsotypeni   11 // [RFCTBD draft-ietf-dnsop-session-signal] DSO-Type Not Implemented
+#define dns_rcode_badvers     16 // [RFC6891] Bad OPT Version, or [RFC2845] TSIG Signature Failure
+#define dns_rcode_badkey      17 // [RFC2845] Key not recognized
+#define dns_rcode_badtime     18 // [RFC2845] Signature out of time window
+#define dns_rcode_badmode     19 // [RFC2930] Bad TKEY Mode
+#define dns_rcode_badname     20 // [RFC2930] Duplicate key name
+#define dns_rcode_badalg      21 // [RFC2930] Algorithm not supported
+#define dns_rcode_badtrunc    22 // [RFC4635] Bad Truncation
+#define dns_rcode_badcookie   23 // [RFC7873] Bad/missing Server Cookie
+
+#define dns_qclass_in          1 // [RFC1035] Internet (IN)
+#define dns_qclass_chaos       3 // [D. Moon, "Chaosnet"] Chaosnet (MIT)
+#define dns_qclass_hesiod      4 // [MIT Project Athena Technical Plan] Hesiod service
+#define dns_qclass_none      254 // [RFC2136] NONE (delete, or not in use)
+#define dns_qclass_any       255 // [RFC1035] ANY (wildcard)
+
+#define dns_rrtype_a           1 // [RFC1035] a host address
+#define dns_rrtype_ns          2 // [RFC1035] an authoritative name server
+#define dns_rrtype_md          3 // [RFC1035] a mail destination (OBSOLETE - use MX)
+#define dns_rrtype_mf          4 // [RFC1035] a mail forwarder (OBSOLETE - use MX)
+#define dns_rrtype_cname       5 // [RFC1035] the canonical name for an alias
+#define dns_rrtype_soa         6 // [RFC1035] marks the start of a zone of authority
+#define dns_rrtype_mb          7 // [RFC1035] a mailbox domain name (EXPERIMENTAL)
+#define dns_rrtype_mg          8 // [RFC1035] a mail group member (EXPERIMENTAL)
+#define dns_rrtype_mr          9 // [RFC1035] a mail rename domain name (EXPERIMENTAL)
+#define dns_rrtype_null       10 // [RFC1035]   a null RR (EXPERIMENTAL)
+#define dns_rrtype_wks        11 // [RFC1035]   a well known service description
+#define dns_rrtype_ptr        12 // [RFC1035]   a domain name pointer
+#define dns_rrtype_hinfo      13 // [RFC1035]   host information
+#define dns_rrtype_minfo      14 // [RFC1035]   mailbox or mail list information
+#define dns_rrtype_mx         15 // [RFC1035]   mail exchange
+#define dns_rrtype_txt        16 // [RFC1035] text strings
+#define dns_rrtype_rp         17 // [RFC1183] for Responsible Person
+#define dns_rrtype_afsdb      18 // [RFC1183,RFC5864] for AFS Data Base location
+#define dns_rrtype_x25        19 // [RFC1183] for X.25 PSDN address
+#define dns_rrtype_isdn       20 // [RFC1183] for ISDN address
+#define dns_rrtype_rt         21 // [RFC1183] for Route Through
+#define dns_rrtype_nsap       22 // [RFC1706] for NSAP address, NSAP style A record
+#define dns_rrtype_nsap_ptr   23 // [RFC1348,RFC1637,RFC1706] for domain name pointer, NSAP style
+#define dns_rrtype_sig        24 // [RFC4034,RFC3755,RFC2535,RFC2536,RFC2537,RFC2931,RFC3110,RFC3008]
+#define dns_rrtype_key        25 // [RFC4034,RFC3755,RFC2535,RFC2536,RFC2537,RFC2539,RFC3008,RFC3110]
+#define dns_rrtype_px         26 // [RFC2163] X.400 mail mapping information
+#define dns_rrtype_gpos       27 // [RFC1712] Geographical Position
+#define dns_rrtype_aaaa       28 // [RFC3596] IP6 Address
+#define dns_rrtype_loc        29 // [RFC1876] Location Information
+#define dns_rrtype_nxt        30 // [RFC3755] [RFC2535] Next Domain (OBSOLETE)
+#define dns_rrtype_eid        31 // [http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] Endpoint Identifier
+#define dns_rrtype_nimloc     32 // [http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt] Nimrod Locator
+#define dns_rrtype_srv        33 // [RFC2782] Server Selection
+#define dns_rrtype_atma       34 // ["ATM Name System, V2.0"] ATM Address
+#define dns_rrtype_naptr      35 // [RFC2915] [RFC2168] [RFC3403] Naming Authority Pointer
+#define dns_rrtype_kx         36 // [RFC2230] Key Exchanger
+#define dns_rrtype_cert       37 // [RFC4398] CERT
+#define dns_rrtype_a6         38 // [RFC3226] [RFC2874] [RFC6563]       A6 (OBSOLETE - use AAAA)
+#define dns_rrtype_dname      39 // [RFC6672]
+#define dns_rrtype_sink       40 // [http://tools.ietf.org/html/draft-eastlake-kitchen-sink]
+#define dns_rrtype_opt        41 // [RFC6891] [RFC3225]
+#define dns_rrtype_apl        42 // [RFC3123]
+#define dns_rrtype_ds         43 // [RFC4034] [RFC3658] Delegation Signer
+#define dns_rrtype_sshfp      44 // [RFC4255] SSH Key Fingerprint
+#define dns_rrtype_ipseckey   45 // [RFC4025]
+#define dns_rrtype_rrsig      46 // [RFC4034] [RFC3755]
+#define dns_rrtype_nsec       47 // [RFC4034] [RFC3755]
+#define dns_rrtype_dnskey     48 // [RFC4034] [RFC3755]
+#define dns_rrtype_dhcid      49 // [RFC4701] DHCID
+#define dns_rrtype_nsec3      50 // [RFC5155] NSEC3
+#define dns_rrtype_nsec3param 51 // [RFC5155] NSEC3PARAM
+#define dns_rrtype_tlsa       52 // [RFC6698] TLSA
+#define dns_rrtype_smimea     53 // [RFC8162] S/MIME cert association
+#define dns_rrtype_hip        55 // Host Identity Protocol
+#define dns_rrtype_ninfo      56 // [Jim_Reid] NINFO/ninfo-completed-template
+#define dns_rrtype_rkey       57 // [Jim_Reid] RKEY/rkey-completed-template
+#define dns_rrtype_talink     58 // [Wouter_Wijngaards] Trust Anchor LINK
+#define dns_rrtype_cds        59 // [RFC7344] Child DS
+#define dns_rrtype_cdnskey    60 // [RFC7344]  DNSKEY(s) the Child wants reflected in DS
+#define dns_rrtype_openpgpkey 61 // [RFC7929]  OpenPGP Key
+#define dns_rrtype_csync      62 // [RFC7477] Child-To-Parent Synchronization
+#define dns_rrtype_spf        99 // [RFC7208]
+#define dns_rrtype_uinfo     100 // [IANA-Reserved]            
+#define dns_rrtype_uid       101 // [IANA-Reserved]            
+#define dns_rrtype_gid       102 // [IANA-Reserved]            
+#define dns_rrtype_unspec    103 // [IANA-Reserved]            
+#define dns_rrtype_nid       104 // [RFC6742]
+#define dns_rrtype_l32       105 // [RFC6742]
+#define dns_rrtype_l64       106 // [RFC6742]
+#define dns_rrtype_lp        107 // [RFC6742]
+#define dns_rrtype_eui48     108 // an EUI-48 address [RFC7043]
+#define dns_rrtype_eui64     109 // an EUI-64 address [RFC7043]
+#define dns_rrtype_tkey      249 // Transaction Key    [RFC2930]               
+#define dns_rrtype_tsig      250 // Transaction Signature [RFC2845]            
+#define dns_rrtype_ixfr      251 // incremental transfer       [RFC1995]               
+#define dns_rrtype_axfr      252 // transfer of an entire zone [RFC1035][RFC5936]              
+#define dns_rrtype_mailb     253 // mailbox-related RRs (MB, MG or MR) [RFC1035]               
+#define dns_rrtype_maila     254 // mail agent RRs (OBSOLETE - see MX) [RFC1035]               
+#define dns_rrtype_any       255 // A request for some or all records the server has available
+#define dns_rrtype_uri       256 // URI        [RFC7553]       URI/uri-completed-template
+#define dns_rrtype_caa       257 // Certification Authority Restriction [RFC6844]
+#define dns_rrtype_avc       258 // Application Visibility and Control [Wolfgang_Riedel]
+#define dns_rrtype_doa       259 // Digital Object Architecture [draft-durand-doa-over-dns]
+
+#define dns_opt_llq            1 // On-hold [http://files.dns-sd.org/draft-sekar-dns-llq.txt]
+#define dns_opt_update_lease   2 // On-hold    [http://files.dns-sd.org/draft-sekar-dns-ul.txt]
+#define dns_opt_nsid           3 // [RFC5001]
+#define dns_opt_owner          4 // [draft-cheshire-edns0-owner-option]
+#define dns_opt_dau            5 // [RFC6975]
+#define dns_opt_dhu            6 // [RFC6975]
+#define dns_opt_n3u            7 // [RFC6975]
+#define dns_opt_client_subnet  8 // [RFC7871]
+#define dns_opt_expire         9 // [RFC7314]
+#define dns_opt_cookie        10 // [RFC7873]
+#define dns_opt_keepalive     11 // [RFC7828]
+#define dns_opt_padding       12 // [RFC7830]
+#define dns_opt_chain         13 // [RFC7901]
+#define dns_opt_key_tag       14 // [RFC8145]
+
+// towire.c:
+
+uint16_t srp_random16(void);
+void dns_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+                      dns_towire_state_t *NONNULL txn,
+                      const char *NONNULL name);
+void dns_full_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+                           dns_towire_state_t *NONNULL txn,
+                           const char *NONNULL name);
+void dns_pointer_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+                         dns_towire_state_t *NONNULL txn,
+                         dns_name_pointer_t *NONNULL pointer);
+void dns_u8_to_wire(dns_towire_state_t *NONNULL txn,
+                    uint8_t val);
+void dns_u16_to_wire(dns_towire_state_t *NONNULL txn,
+                      uint16_t val);
+void dns_u32_to_wire(dns_towire_state_t *NONNULL txn,
+                      uint32_t val);
+void dns_ttl_to_wire(dns_towire_state_t *NONNULL txn,
+                     int32_t val);
+void dns_rdlength_begin(dns_towire_state_t *NONNULL txn);
+void dns_rdlength_end(dns_towire_state_t *NONNULL txn);
+void dns_rdata_a_to_wire(dns_towire_state_t *NONNULL txn,
+                         const char *NONNULL ip_address);
+void dns_rdata_aaaa_to_wire(dns_towire_state_t *NONNULL txn,
+                            const char *NONNULL ip_address);
+uint16_t dns_rdata_key_to_wire(dns_towire_state_t *NONNULL txn,
+                               unsigned key_type,
+                               unsigned name_type,
+                               unsigned signatory,
+                               srp_key_t *NONNULL key);
+void dns_rdata_txt_to_wire(dns_towire_state_t *NONNULL txn,
+                           const char *NONNULL txt_record);
+void dns_rdata_raw_data_to_wire(dns_towire_state_t *NONNULL txn, const void *NONNULL raw_data, size_t length);
+void dns_edns0_header_to_wire(dns_towire_state_t *NONNULL txn,
+                              int mtu,
+                              int xrcode,
+                              int version,
+                              int DO);
+void dns_edns0_option_begin(dns_towire_state_t *NONNULL txn);
+void dns_edns0_option_end(dns_towire_state_t *NONNULL txn);
+void dns_sig0_signature_to_wire(dns_towire_state_t *NONNULL txn,
+                                srp_key_t *NONNULL key, uint16_t key_tag,
+                                dns_name_pointer_t *NONNULL signer,
+                                const char *NONNULL signer_fqdn);
+int dns_send_to_server(dns_transaction_t *NONNULL txn,
+                       const char *NONNULL anycast_address, uint16_t port,
+                       dns_response_callback_t NONNULL callback);
+
+// fromwire.c:
+dns_label_t *NULLABLE dns_label_parse(const uint8_t *NONNULL buf, unsigned mlen, unsigned *NONNULL offp);
+bool dns_opt_parse(dns_edns0_t *NONNULL *NULLABLE ret, dns_rr_t *NONNULL rrset);
+bool dns_name_parse(dns_label_t *NONNULL *NULLABLE ret, const uint8_t *NONNULL buf, unsigned len,
+                    unsigned *NONNULL offp, unsigned base);
+bool dns_u8_parse(const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, uint8_t *NONNULL ret);
+bool dns_u16_parse(const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, uint16_t *NONNULL ret);
+bool dns_u32_parse(const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, uint32_t *NONNULL ret);
+bool dns_rdata_parse_data(dns_rr_t *NONNULL rr, const uint8_t *NONNULL buf, unsigned *NONNULL offp,
+                          unsigned target, unsigned rdlen, unsigned rrstart);
+bool dns_rr_parse(dns_rr_t *NONNULL rrset,
+                  const uint8_t *NONNULL buf, unsigned len, unsigned *NONNULL offp, bool rrdata_permitted);
+void dns_name_free(dns_label_t *NONNULL name);
+void dns_rrdata_free(dns_rr_t *NONNULL rr);
+void dns_message_free(dns_message_t *NONNULL message);
+bool dns_rdata_parse_data(dns_rr_t *NONNULL rr, const uint8_t *NONNULL buf, unsigned *NONNULL offp,
+                          unsigned target, unsigned rdlen, unsigned rrstart);
+bool dns_wire_parse(dns_message_t *NONNULL *NULLABLE ret, dns_wire_t *NONNULL message, unsigned len);
+bool dns_names_equal(dns_label_t *NONNULL name1, dns_label_t *NONNULL name2);
+const char *NONNULL dns_name_print(dns_name_t *NONNULL name, char *NONNULL buf, int bufmax);
+bool dns_names_equal_text(dns_label_t *NONNULL name1, const char *NONNULL name2);
+size_t dns_name_wire_length(dns_label_t *NONNULL name);
+size_t dns_name_to_wire_canonical(uint8_t *NONNULL buf, size_t max, dns_label_t *NONNULL name);
+#endif // _DNS_MSG_H
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/dnssd-proxy.c b/ServiceRegistration/dnssd-proxy.c
new file mode 100644 (file)
index 0000000..589d1dd
--- /dev/null
@@ -0,0 +1,1248 @@
+/* dnssd-proxy.c
+ *
+ * Copyright (c) 2018-2019 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 is a Discovery Proxy module for the SRP gateway.
+ *
+ * The motivation here is that it makes sense to co-locate the SRP relay and the Discovery Proxy because
+ * these functions are likely to co-exist on the same node, listening on the same port.  For homenet-style
+ * name resolution, we need a DNS proxy that implements DNSSD Discovery Proxy for local queries, but
+ * forwards other queries to an ISP resolver.  The SRP gateway is already expecting to do this.
+ * This module implements the functions required to allow the SRP gateway to also do Discovery Relay.
+ * 
+ * The Discovery Proxy relies on Apple's DNS-SD library and the mDNSResponder DNSSD server, which is included
+ * in Apple's open source mDNSResponder package, available here:
+ *
+ *            https://opensource.apple.com/tarballs/mDNSResponder/
+ */
+
+#define __APPLE_USE_RFC_3542
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <ctype.h>
+
+#include "dns_sd.h"
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+#include "dso.h"
+#include "ioloop.h"
+
+// Enumerate the list of interfaces, map them to interface indexes, give each one a name
+// Have a tree of subdomains for matching
+
+typedef struct dnssd_query {
+    io_t io;
+    DNSServiceRef ref;
+    char *name;                                                // The name we are looking up.
+    const char *enclosing_domain;      // The domain the name is in, or NULL if not ours; if null, name is an FQDN.
+    dns_name_pointer_t enclosing_domain_pointer;
+    message_t *question;
+    comm_t *connection;
+    dso_activity_t *activity;
+    int serviceFlags;                          // Service flags to use with this query.
+    bool is_dns_push;
+    bool is_edns0;
+    uint16_t type, qclass;                     // Original query type and class.
+    dns_towire_state_t towire;
+    uint8_t *p_dso_length;                     // Where to store the DSO length just before we write out a push notification.
+    dns_wire_t response;                       // This has to be at the end because we don't zero the RRdata buffer.
+} dnssd_query_t;
+
+const char push_subscription_activity_type[] = "push subscription";
+
+const char local_suffix[] = ".local.";
+#define PROXIED_DOMAIN "proxy.home.arpa."
+const char proxied_domain[] = PROXIED_DOMAIN;
+const char proxied_domain_ld[] = "." PROXIED_DOMAIN;
+#define MY_NAME "proxy.example.com."
+#define MY_IPV4_ADDR "192.0.2.1"
+// #define MY_IPV6_ADDR "2001:db8::1" // for example
+
+#define TOWIRE_CHECK(note, towire, func) { func; if ((towire)->error != 0 && failnote == NULL) failnote = (note); }
+
+int64_t dso_transport_idle(void *context, int64_t next_event)
+{
+    return next_event;
+}
+
+void dnssd_query_cancel(io_t *io)
+{
+    dnssd_query_t *query = (dnssd_query_t *)io;
+    if (query->io.sock != -1) {
+        DNSServiceRefDeallocate(query->ref);
+        query->io.sock = -1;
+    }
+    query->connection = NULL;
+}
+
+void
+dns_push_finalize(dso_activity_t *activity)
+{
+    dnssd_query_t *query = (dnssd_query_t *)activity->context;
+    INFO("dnssd_push_finalize: %s", activity->name);
+    dnssd_query_cancel(&query->io);
+}
+
+void
+dnssd_query_finalize(io_t *io)
+{
+    dnssd_query_t *query = (dnssd_query_t *)io;
+    INFO("dnssd_query_finalize on %s%s", query->name, query->enclosing_domain ? ".local" : "");
+    if (query->question) {
+        message_free(query->question);
+    }
+    free(query->name);
+    free(query);
+}
+
+static void
+dnssd_query_callback(io_t *io)
+{
+    dnssd_query_t *query = (dnssd_query_t *)io;
+    int status = DNSServiceProcessResult(query->ref);
+    if (status != kDNSServiceErr_NoError) {
+        ERROR("DNSServiceProcessResult on %s%s returned %d", query->name, query->enclosing_domain ? ".local" : "", status);
+        if (query->activity != NULL && query->connection != NULL) {
+            dso_drop_activity(query->connection->dso, query->activity);
+        } else {
+            dnssd_query_cancel(&query->io);
+        }
+    }
+}
+
+static void
+add_dnssd_query(dnssd_query_t *query)
+{
+    io_t *io = &query->io;
+    io->sock = DNSServiceRefSockFD(query->ref);
+    io->cancel = dnssd_query_cancel;
+    io->cancel_on_close = &query->connection->io;
+    add_reader(io, dnssd_query_callback, dnssd_query_finalize);
+}
+
+// Parse a NUL-terminated text string into a sequence of labels.
+dns_name_t *
+dns_pres_name_parse(const char *pname)
+{
+    const char *dot = strchr(pname, '.');
+    dns_label_t *ret;
+    int len;
+    if (dot == NULL) {
+        dot = pname + strlen(pname);
+    }
+    len = (dot - pname) + 1 + (sizeof *ret) - DNS_MAX_LABEL_SIZE;
+    ret = calloc(len, 1);
+    if (ret == NULL) {
+        return NULL;
+    }
+    ret->len = dot - pname;
+    if (ret->len > 0) {
+        memcpy(ret->data, pname, ret->len);
+    }
+    ret->data[ret->len] = 0;
+    if (dot[0] == '.') {
+        ret->next = dns_pres_name_parse(dot + 1);
+    }
+    return ret;
+}
+
+bool
+dns_subdomain_of(dns_name_t *name, dns_name_t *domain, char *buf, size_t buflen)
+{
+    int dnum = 0, nnum = 0;
+    dns_name_t *np, *dp;
+    char *bufp = buf;
+    size_t bytesleft = buflen;
+
+    for (dp = domain; dp; dp = dp->next) {
+        dnum++;
+    }
+    for (np = name; np; np = np->next) {
+        nnum++;
+    }
+    if (nnum < dnum) {
+        return false;
+    }
+    for (np = name; np; np = np->next) {
+        if (nnum-- == dnum) {
+            break;
+        }
+    }
+    if (dns_names_equal(np, domain)) {
+        for (dp = name; dp != np; dp = dp->next) {
+            if (dp->len + 1 > bytesleft) {
+                // It's okay to return false here because a name that overflows the buffer isn't valid.
+                ERROR("dns_subdomain_of: out of buffer space!");
+                return false;
+            }
+            memcpy(bufp, dp->data, dp->len);
+            bufp += dp->len;
+            bytesleft = bytesleft - dp->len;
+            if (dp->next != np) {
+                *bufp++ = '.';
+                bytesleft -= dp->len;
+            }
+        }
+        *bufp = 0;
+        return true;
+    }
+    return false;
+}
+
+void
+dp_simple_response(comm_t *comm, int rcode)
+{
+    if (comm->send_response) {
+        struct iovec iov;
+        dns_wire_t response;
+        memset(&response, 0, DNS_HEADER_SIZE);
+
+        // We take the ID and the opcode from the incoming message, because if the
+        // header has been mangled, we (a) wouldn't have gotten here and (b) don't
+        // have any better choice anyway.
+        response.id = comm->message->wire.id;
+        dns_qr_set(&response, dns_qr_response);
+        dns_opcode_set(&response, dns_opcode_get(&comm->message->wire));
+        dns_rcode_set(&response, rcode);
+        iov.iov_base = &response;
+        iov.iov_len = DNS_HEADER_SIZE; // No RRs
+        comm->send_response(comm, comm->message, &iov, 1);
+    }
+}
+
+bool
+dp_served(dns_name_t *name, char *buf, size_t bufsize)
+{
+    static dns_name_t *home_dot_arpa = NULL;
+    if (home_dot_arpa == NULL) {
+        home_dot_arpa = dns_pres_name_parse(proxied_domain);
+        if (home_dot_arpa == NULL) {
+            ERROR("Unable to parse %s!", proxied_domain);
+            return false;
+        }
+    }
+
+     // For now we treat any query to home.arpa as local.
+    return dns_subdomain_of(name, home_dot_arpa, buf, bufsize);
+}
+
+// Utility function to find "local" on the end of a string of labels.
+bool
+truncate_local(dns_name_t *name)
+{
+    dns_label_t *lp, *prev, *prevprev;
+    
+    prevprev = prev = NULL;
+    // Find the root label.
+    for (lp = name; lp && lp->len; lp = lp->next) {
+        prevprev = prev;
+        prev = lp;
+    }
+    if (lp && prev && prevprev) {
+        if (prev->len == 5 && !strncasecmp(prev->data, "local", 5)) {
+            dns_name_free(prev);
+            prevprev->next = NULL;
+            return true;
+        }
+    }
+    dns_name_free(name);
+    return false;
+}    
+
+void
+dp_query_add_data_to_response(dnssd_query_t *query, const char *fullname,
+                              uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl)
+{
+    dns_towire_state_t *towire = &query->towire;
+    const char *failnote = NULL;
+
+    // Rewrite the domain if it's .local.
+    if (query->enclosing_domain != NULL) {
+        TOWIRE_CHECK("query name", towire, dns_name_to_wire(NULL, towire, query->name));
+        if (query->enclosing_domain_pointer.message_start != NULL) {
+            // This happens if we are sending a DNS response, because we can always point back to the question.
+            TOWIRE_CHECK("enclosing_domain_pointer", towire,
+                         dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+            INFO(" dns answer:  type %02d class %02d %s.%s (p)", rrtype, rrclass, query->name, query->enclosing_domain);
+        } else {
+            // This happens if we are sending a DNS Push notification.
+            TOWIRE_CHECK("enclosing_domain", towire, dns_full_name_to_wire(NULL, towire, query->enclosing_domain));
+            INFO("push answer:  type %02d class %02d %s.%s", rrtype, rrclass, query->name, query->enclosing_domain);
+        }
+    } else {
+        TOWIRE_CHECK("query->name", towire, dns_full_name_to_wire(NULL, towire, query->name));
+        INFO("%s answer:  type %02d class %02d %s.%s (p)",
+             query->is_dns_push ? "push" : " dns", rrtype, rrclass, query->name, query->enclosing_domain);
+    }
+    TOWIRE_CHECK("rrtype", towire, dns_u16_to_wire(towire, rrtype));
+    TOWIRE_CHECK("rrclass", towire, dns_u16_to_wire(towire, rrclass));
+    TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, ttl));
+
+    if (rdlen > 0) {
+        // If necessary, correct domain names inside of rrdata.
+        if (rrclass == dns_qclass_in && (rrtype == dns_rrtype_srv ||
+                                         rrtype == dns_rrtype_ptr ||
+                                         rrtype == dns_rrtype_cname)) {
+            dns_rr_t answer;
+            dns_name_t *name;
+            unsigned offp = 0;
+            answer.type = rrtype;
+            answer.qclass = rrclass;
+            if (!dns_rdata_parse_data(&answer, rdata, &offp, rdlen, rdlen, 0)) {
+                ERROR("dp_query_add_data_to_response: rdata from mDNSResponder didn't parse!!");
+                goto raw;
+            }
+            switch(rrtype) {
+            case dns_rrtype_cname:
+            case dns_rrtype_ptr:
+                name = answer.data.ptr.name;
+                if (!truncate_local(name)) {
+                    goto raw;
+                }
+                TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
+                break;
+            case dns_rrtype_srv:
+                name = answer.data.srv.name;
+                if (!truncate_local(name)) {
+                    goto raw;
+                }
+                TOWIRE_CHECK("rdlength begin", towire, dns_rdlength_begin(towire));
+                TOWIRE_CHECK("answer.data.srv.priority", towire, dns_u16_to_wire(towire, answer.data.srv.priority));
+                TOWIRE_CHECK("answer.data.srv.weight", towire, dns_u16_to_wire(towire, answer.data.srv.weight));
+                TOWIRE_CHECK("answer.data.srv.port", towire, dns_u16_to_wire(towire, answer.data.srv.port));
+                break;
+            default:
+                ERROR("dp_query_add_data_to_response: can't get here.");
+                goto raw;
+                break;
+            }
+            // If we get here, the name ended in "local."
+            int bytes_written = dns_name_to_wire_canonical(towire->p, towire->lim - towire->p, name);
+            towire->p += bytes_written;
+            if (query->enclosing_domain_pointer.message_start != NULL) {
+                TOWIRE_CHECK("enclosing_domain_pointer internal", towire,
+                             dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+            } else {
+                TOWIRE_CHECK("enclosing_domain internal", towire,
+                             dns_full_name_to_wire(NULL, towire, query->enclosing_domain));
+            }
+            dns_rdlength_end(towire);
+        } else {
+        raw:
+            TOWIRE_CHECK("rdlen", towire, dns_u16_to_wire(towire, rdlen));
+            TOWIRE_CHECK("rdata", towire, dns_rdata_raw_data_to_wire(towire, rdata, rdlen));
+        }
+    } else {
+        TOWIRE_CHECK("rdlen", towire, dns_u16_to_wire(towire, rdlen));
+    }
+    if (failnote) {
+        ERROR("dp_query_add_data_to_response: %s", failnote);
+    }
+}
+
+typedef struct hardwired hardwired_t;
+struct hardwired {
+    hardwired_t *next;
+    uint16_t type;
+    char *name;
+    char *fullname;
+    uint8_t *rdata;
+    uint16_t rdlen;
+} *hardwired_responses;
+
+void
+dnssd_hardwired_add(const char *name, const char *domain, size_t rdlen, uint8_t *rdata, uint16_t type)
+{
+    hardwired_t *hp;
+    int namelen = strlen(name);
+    size_t total = (sizeof *hp) + rdlen + namelen * 2 + strlen(proxied_domain_ld) + 2;
+
+    hp = calloc(1, (sizeof *hp) + rdlen + namelen * 2 + strlen(proxied_domain_ld) + 2);
+    hp->rdata = (uint8_t *)(hp + 1);
+    hp->rdlen = rdlen;
+    memcpy(hp->rdata, rdata, rdlen);
+    hp->name = (char *)hp->rdata + rdlen;
+    strcpy(hp->name, name);
+    hp->fullname = hp->name + namelen + 1;
+    strcpy(hp->fullname, name);
+    strcpy(hp->fullname + namelen, proxied_domain_ld);
+    if (hp->fullname + strlen(hp->fullname) + 1 != (char *)hp + total) {
+        ERROR("%p != %p", hp->fullname + strlen(hp->fullname) + 1, ((char *)hp) + total);
+    }
+    hp->type = type;
+    hp->next = hardwired_responses;
+    hardwired_responses = hp;
+
+    INFO("hardwired_add: fullname %s name %s type %d rdlen %d", hp->fullname, hp->name, hp->type, hp->rdlen);
+}
+
+void
+dnssd_hardwired_setup(void)
+{
+    dns_wire_t wire;
+    dns_towire_state_t towire;
+
+#define RESET \
+    memset(&towire, 0, sizeof towire); \
+    towire.message = &wire; \
+    towire.p = wire.data; \
+    towire.lim = towire.p + sizeof wire.data
+
+    // Browsing pointers...
+    RESET;
+    dns_full_name_to_wire(NULL, &towire, proxied_domain);
+    dnssd_hardwired_add("b._dns-sd._udp", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_ptr);
+    dnssd_hardwired_add("lb._dns-sd._udp", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_ptr);
+    
+    // SRV
+    // _dns-push-tls._tcp
+    RESET;
+    dns_u16_to_wire(&towire, 0); // priority
+    dns_u16_to_wire(&towire, 0); // weight
+    dns_u16_to_wire(&towire, 53); // port
+    // Define MY_NAME to reference a name for this server in a different zone.
+#ifndef MY_NAME
+    dns_name_to_wire(NULL, &towire, "ns");
+    dns_full_name_to_wire(NULL, &towire, proxied_domain);
+#else
+    dns_full_name_to_wire(NULL, &towire, MY_NAME);
+#endif
+    dnssd_hardwired_add("_dns-push-tls._tcp", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_srv);
+    
+    // A
+#ifndef MY_NAME
+    // ns
+#ifdef MY_IPV4_ADDR
+    RESET;
+    dns_rdata_a_to_wire(&towire, MY_IPV4_ADDR);
+    dnssd_hardwired_add("ns", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_a);
+#endif
+
+    // AAAA
+#ifdef MY_IPV6_ADDR
+    RESET;
+    dns_rdata_aaaa_to_wire(&towire, MY_IPV6_ADDR);
+    dnssd_hardwired_add("ns", proxied_domain_ld, towire.p - wire.data, wire.data, dns_rrtype_aaaa);
+#endif
+#endif
+
+    // NS
+    RESET;
+#ifdef MY_NAME
+    dns_full_name_to_wire(NULL, &towire, MY_NAME);
+#else
+    dns_name_to_wire(NULL, &towire, "ns");
+    dns_full_name_to_wire(NULL, &towire, proxied_domain);
+#endif
+    dnssd_hardwired_add("", proxied_domain, towire.p - wire.data, wire.data, dns_rrtype_ns);
+
+    // SOA (piggybacking on what we already did for NS, which starts the same.
+    dns_name_to_wire(NULL, &towire, "postmaster");
+    dns_full_name_to_wire(NULL, &towire, proxied_domain);
+    dns_u32_to_wire(&towire, 0);     // serial 
+    dns_ttl_to_wire(&towire, 7200);  // refresh
+    dns_ttl_to_wire(&towire, 3600);  // retry
+    dns_ttl_to_wire(&towire, 86400); // expire
+    dns_ttl_to_wire(&towire, 120);    // minimum
+    dnssd_hardwired_add("", proxied_domain, towire.p - wire.data, wire.data, dns_rrtype_soa);
+}
+
+void
+dp_query_send_dns_response(dnssd_query_t *query)
+{
+    struct iovec iov;
+    dns_towire_state_t *towire = &query->towire;
+    const char *failnote = NULL;
+
+    // Send an SOA record if it's a .local query.
+    if (query->enclosing_domain != NULL) {
+        // DNSSD Hybrid, Section 6.1.
+        TOWIRE_CHECK("&query->enclosing_domain_pointer", towire,
+                     dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+        TOWIRE_CHECK("dns_rrtype_soa", towire,
+                     dns_u16_to_wire(towire, dns_rrtype_soa));
+        TOWIRE_CHECK("dns_qclass_in", towire,
+                     dns_u16_to_wire(towire, dns_qclass_in));
+        TOWIRE_CHECK("ttl", towire, dns_ttl_to_wire(towire, 3600));
+        TOWIRE_CHECK("rdlength_begin ", towire, dns_rdlength_begin(towire));
+#ifdef MY_NAME
+        TOWIRE_CHECK(MY_NAME, towire, dns_full_name_to_wire(NULL, towire, MY_NAME));
+#else
+        TOWIRE_CHECK("\"ns\"", towire, dns_name_to_wire(NULL, towire, "ns"));
+        TOWIRE_CHECK("&query->enclosing_domain_pointer", towire,
+                     dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+#endif
+        TOWIRE_CHECK("\"postmaster\"", towire,
+                     dns_name_to_wire(NULL, towire, "postmaster"));
+        TOWIRE_CHECK("&query->enclosing_domain_pointer", towire,
+                     dns_pointer_to_wire(NULL, towire, &query->enclosing_domain_pointer));
+        TOWIRE_CHECK("serial", towire,dns_u32_to_wire(towire, 0));     // serial 
+        TOWIRE_CHECK("refresh", towire, dns_ttl_to_wire(towire, 7200));  // refresh
+        TOWIRE_CHECK("retry", towire, dns_ttl_to_wire(towire, 3600));  // retry
+        TOWIRE_CHECK("expire", towire, dns_ttl_to_wire(towire, 86400)); // expire
+        TOWIRE_CHECK("minimum", towire, dns_ttl_to_wire(towire, 120));    // minimum
+        dns_rdlength_end(towire);
+        query->response.nscount = htons(1);
+
+        // Response is authoritative and not recursive.
+        query->response.bitfield = htons((ntohs(query->response.bitfield) | dns_flags_aa) & ~dns_flags_ra);
+    } else {
+        // Response is recursive and not authoritative.
+        query->response.bitfield = htons((ntohs(query->response.bitfield) | dns_flags_ra) & ~dns_flags_aa);
+    }
+    // Not truncated, not authentic, checking not disabled.
+    query->response.bitfield = htons(ntohs(query->response.bitfield) & ~(dns_flags_rd | dns_flags_tc | dns_flags_ad | dns_flags_cd));
+
+    // This is a response
+    dns_qr_set(&query->response, dns_qr_response);
+    // No error.
+    dns_rcode_set(&query->response, dns_rcode_noerror);
+    
+    // Send an OPT RR if we got one
+    if (query->is_edns0) {
+        TOWIRE_CHECK("Root label", towire, dns_u8_to_wire(towire, 0));     // Root label
+        TOWIRE_CHECK("dns_rrtype_opt", towire, dns_u16_to_wire(towire, dns_rrtype_opt));
+        TOWIRE_CHECK("UDP Payload size", towire, dns_u16_to_wire(towire, 4096)); // UDP Payload size
+        TOWIRE_CHECK("extended-rcode", towire, dns_u8_to_wire(towire, 0));     // extended-rcode
+        TOWIRE_CHECK("EDNS version 0", towire, dns_u8_to_wire(towire, 0));     // EDNS version 0
+        TOWIRE_CHECK("No extended flags", towire, dns_u16_to_wire(towire, 0));    // No extended flags
+        TOWIRE_CHECK("No payload", towire, dns_u16_to_wire(towire, 0));    // No payload
+        query->response.arcount = htons(1);
+    }
+
+    if (towire->error) {
+        ERROR("dp_query_send_dns_response failed on %s", failnote);
+    }
+
+    iov.iov_len = (query->towire.p - (uint8_t *)&query->response);
+    iov.iov_base = &query->response;
+    INFO("dp_query_send_dns_response: %s (len %zd)", query->name, iov.iov_len);
+
+    if (query->connection != NULL) {
+        query->connection->send_response(query->connection, query->question, &iov, 1);
+    }
+
+    // Free up state
+    dnssd_query_cancel(&query->io);
+    // Query will be freed automatically next time through the io loop.
+}
+
+void
+dp_query_towire_reset(dnssd_query_t *query)
+{
+    query->towire.p = &query->response.data[0];  // We start storing RR data here.
+    query->towire.lim = &query->response.data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
+    query->towire.message = &query->response;
+    query->p_dso_length = NULL;
+}
+
+void
+dns_push_start(dnssd_query_t *query)
+{
+    const char *failnote = NULL;
+    
+    // If we don't have a dso header yet, start one.
+    if (query->p_dso_length == NULL) {
+        memset(&query->response, 0, (sizeof query->response) - DNS_DATA_SIZE);
+        dns_opcode_set(&query->response, dns_opcode_dso);
+        // This is a unidirectional DSO message, which is marked as a query
+        dns_qr_set(&query->response, dns_qr_query);
+        // No error cuz not a response.
+        dns_rcode_set(&query->response, dns_rcode_noerror);
+
+        TOWIRE_CHECK("kDSOType_DNSPushUpdate", &query->towire,
+                     dns_u16_to_wire(&query->towire, kDSOType_DNSPushUpdate));
+        if (query->towire.p + 2 > query->towire.lim) {
+            ERROR("No room for dso length in DNS Push notification message.");
+            dp_query_towire_reset(query);
+            return;
+        }
+        query->p_dso_length = query->towire.p;
+        query->towire.p += 2;
+    }
+    if (failnote != NULL) {
+        ERROR("dns_push_start: couldn't start update: %s", failnote);
+    }
+}
+
+void
+dp_push_response(dnssd_query_t *query)
+{
+    struct iovec iov;
+
+    if (query->p_dso_length != NULL) {
+        int16_t dso_length = query->towire.p - query->p_dso_length - 2;
+        iov.iov_len = (query->towire.p - (uint8_t *)&query->response);
+        iov.iov_base = &query->response;
+        INFO("dp_push_response: %s (len %zd)", query->name, iov.iov_len);
+
+        query->towire.p = query->p_dso_length;
+        dns_u16_to_wire(&query->towire, dso_length);
+        if (query->connection != NULL) {
+            query->connection->send_response(query->connection, query->question, &iov, 1);
+        }
+        dp_query_towire_reset(query);
+    }
+}
+
+bool
+dnssd_hardwired_response(dnssd_query_t *query, DNSServiceQueryRecordReply callback)
+{
+    hardwired_t *hp;
+    bool got_response = false;
+
+    for (hp = hardwired_responses; hp; hp = hp->next) {
+        if ((query->type == hp->type || query->type == dns_rrtype_any) &&
+            query->qclass == dns_qclass_in && !strcasecmp(hp->name, query->name)) {
+            if (query->is_dns_push) {
+                dns_push_start(query);
+                dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in, hp->rdlen, hp->rdata, 3600);
+            } else {
+                // Store the response
+                dp_query_add_data_to_response(query, hp->fullname, hp->type, dns_qclass_in, hp->rdlen, hp->rdata, 3600);
+                query->response.ancount = htons(ntohs(query->response.ancount) + 1);
+            }
+            got_response = true;
+        }
+    }
+    if (got_response) {
+        if (query->is_dns_push) {
+            dp_push_response(query);
+        } else {
+            // Steal the question
+            query->question = query->connection->message;
+            query->connection->message = NULL;
+            // Send the answer(s).
+            dp_query_send_dns_response(query);
+        }
+        return true;
+    }
+    return false;
+}
+
+// This is the callback for dns query results.
+void
+dns_query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+                   const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata,
+                   uint32_t ttl, void *context)
+{
+    dnssd_query_t *query = context;
+    
+    INFO("%s %d %d %x %d", fullname, rrtype, rrclass, rdlen, errorCode);
+
+    if (errorCode == kDNSServiceErr_NoError) {
+        dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata,
+                                      ttl > 10 ? 10 : ttl); // Per dnssd-hybrid 5.5.1, limit ttl to 10 seconds
+        query->response.ancount = htons(ntohs(query->response.ancount) + 1);
+        // If there isn't more coming, send the response now
+        if (!(flags & kDNSServiceFlagsMoreComing)) {
+            dp_query_send_dns_response(query);
+        }
+    } else if (errorCode == kDNSServiceErr_NoSuchRecord) {
+        // If we get "no such record," we can't really do much except return the answer.
+        dp_query_send_dns_response(query);
+    } else {
+        dns_rcode_set(&query->response, dns_rcode_servfail);
+        dp_query_send_dns_response(query);
+    }
+}
+
+void
+dp_query_wakeup(io_t *io)
+{
+    dnssd_query_t *query = (dnssd_query_t *)io;
+    char name[DNS_MAX_NAME_SIZE + 1];
+    int namelen = strlen(query->name);
+
+    // Should never happen.
+    if ((namelen + query->enclosing_domain != NULL ? sizeof local_suffix : 0) > sizeof name) {
+        ERROR("db_query_wakeup: no space to construct name.");
+        dnssd_query_cancel(&query->io);
+    }
+
+    strcpy(name, query->name);
+    if (query->enclosing_domain != NULL) {
+        strcpy(name + namelen, local_suffix);
+    }
+    dp_query_send_dns_response(query);
+}
+
+bool
+dp_query_start(comm_t *comm, dnssd_query_t *query, int *rcode, DNSServiceQueryRecordReply callback)
+{
+    char name[DNS_MAX_NAME_SIZE + 1];
+    char *np;
+
+    if (query->enclosing_domain != NULL) {
+        if (dnssd_hardwired_response(query, callback)) {
+            *rcode = dns_rcode_noerror;
+            return true;
+        }
+
+        int len = strlen(query->name);
+        if (len + sizeof local_suffix > sizeof name) {
+            *rcode = dns_rcode_servfail;
+            free(query->name);
+            free(query);
+            ERROR("question name %s is too long for .local.", name);
+            return false;
+        }
+        memcpy(name, query->name, len);
+        memcpy(&name[len], local_suffix, sizeof local_suffix);
+        np = name;
+    } else {
+        np = query->name;
+    }
+        
+    // Issue a DNSServiceQueryRecord call
+    int err = DNSServiceQueryRecord(&query->ref, query->serviceFlags,
+                                    kDNSServiceInterfaceIndexAny, np, query->type,
+                                    query->qclass, callback, query);
+    if (err != kDNSServiceErr_NoError) {
+        ERROR("dp_query_start: DNSServiceQueryRecord failed for '%s': %d", np, err);
+        *rcode = dns_rcode_servfail;
+        return false;
+    } else {
+        INFO("dp_query_start: DNSServiceQueryRecord started for '%s': %d", np, err);
+    }
+    
+    // If this isn't a DNS Push subscription, we need to respond quickly with as much data as we have.  It
+    // turns out that dig gives us a second, but also that responses seem to come back in on the order of a
+    // millisecond, so we'll wait 100ms.
+    if (!query->is_dns_push && query->enclosing_domain) {
+        query->io.wakeup_time = ioloop_now + IOLOOP_SECOND / 10;
+        query->io.wakeup = dp_query_wakeup;
+    }
+
+    add_dnssd_query(query);
+    return true;
+}
+
+dnssd_query_t *
+dp_query_generate(comm_t *comm, dns_rr_t *question, bool dns_push, int *rcode)
+{
+    char name[DNS_MAX_NAME_SIZE + 1];
+    const char *enclosing_domain;
+
+    // If it's a query for a name served by the local discovery proxy, do an mDNS lookup.
+    if ((dp_served(question->name, name, sizeof name))) {
+        enclosing_domain = proxied_domain;
+        INFO("%s question: type %d class %d %s%s -> %s.local", dns_push ? "push" : " dns",
+             question->type, question->qclass, name, proxied_domain, name);
+    } else {
+        dns_name_print(question->name, name, sizeof name);
+        enclosing_domain = NULL;
+        INFO("%s question: type %d class %d %s",
+             dns_push ? "push" : " dns", question->type, question->qclass, name);
+    }
+
+    dnssd_query_t *query = malloc(sizeof *query);
+    if (query == NULL) {
+        ERROR("Unable to allocate memory for query on %s", name);
+        *rcode = dns_rcode_servfail;
+        return NULL;
+    }
+    // Zero out everything except the message data buffer, which is large and doesn't need it.
+    memset(query, 0, (sizeof *query) - (sizeof query->response) + DNS_HEADER_SIZE);
+
+    // Steal the data from the question.   If subdomain is not null, this is a local mDNS query; otherwise
+    // we are recursing.
+    INFO("name = %s", name);
+    query->name = strdup(name);
+    if (!query->name) {
+        *rcode = dns_rcode_servfail;
+        free(query);
+        ERROR("unable to allocate memory for question name on %s", name);
+        return NULL;
+    }
+    // It is safe to assume that enclosing domain will not be freed out from under us.
+    query->enclosing_domain = enclosing_domain;
+    query->serviceFlags = 0;
+
+    // If this is a local query, add ".local" to the end of the name and require multicast.
+    if (enclosing_domain != NULL) {
+        query->serviceFlags |= kDNSServiceFlagsForceMulticast;
+    } else {
+        query->serviceFlags |= kDNSServiceFlagsReturnIntermediates;
+    }
+    // Name now contains the name we want mDNSResponder to look up.
+
+    // XXX make sure finalize does the right thing.
+    query->connection = comm;
+
+    // Remember whether this is a long-lived query.
+    query->is_dns_push = dns_push;
+
+    // Start writing the response
+    dp_query_towire_reset(query);
+
+    query->type = question->type;
+    query->qclass = question->qclass;
+
+    // Just in case we don't need to do a DNSServiceQueryRecord query to satisfy it.
+    query->io.sock = -1;
+
+    *rcode = dns_rcode_noerror;
+    return query;
+}
+
+// This is the callback for DNS push query results, as opposed to push updates.
+void
+dns_push_query_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+                        const char *fullname, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata,
+                        uint32_t ttl, void *context)
+{
+    dnssd_query_t *query = context;
+    
+    // From DNSSD-Hybrid, for mDNS queries:
+    // If we have cached answers, respond immediately, because we probably have all the answers.
+    // If we don't have cached answers, respond as soon as we get an answer (presumably more-coming will be false).
+
+    // The spec says to not query if we have cached answers.   We trust the DNSServiceQueryRecord call to handle this.
+
+    // If we switch to using a single connection to mDNSResponder, we could have !more-coming trigger a flush of
+    // all outstanding queries that aren't waiting on a time trigger.   This is because more-coming isn't
+    // query-specific
+
+    INFO("PUSH %s %d %d %x %d", fullname, rrtype, rrclass, rdlen, errorCode);
+
+    // query_state_waiting means that we're answering a regular DNS question
+    if (errorCode == kDNSServiceErr_NoError) {
+        dns_push_start(query);
+
+        // If kDNSServiceFlagsAdd is set, it's an add, otherwise a delete.
+        if (flags & kDNSServiceFlagsAdd) {
+            dp_query_add_data_to_response(query, fullname, rrtype, rrclass, rdlen, rdata, ttl);
+        } else {
+            // I think if this happens it means delete all RRs of this type.
+            if (rdlen == 0) {
+                dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_any, rdlen, rdata, 0);
+            } else {
+                dp_query_add_data_to_response(query, fullname, rrtype, dns_qclass_none, rdlen, rdata, 0);
+            }
+        }
+        // If there isn't more coming, send a DNS Push notification now.
+        // XXX If enough comes to fill the response, send the message.
+        if (!(flags & kDNSServiceFlagsMoreComing)) {
+            dp_push_response(query);
+        }
+    } else {
+        ERROR("dns_push_query_callback: unexpected error code %d", errorCode);
+        if (query->connection != NULL) {
+            dso_drop_activity(query->connection->dso, query->activity);
+        }
+    }
+}
+
+void
+dns_push_subscribe(comm_t *comm, dns_wire_t *header, dso_state_t *dso, dns_rr_t *question,
+                   const char *activity_name, const char *opcode_name)
+{
+    int rcode;
+    dnssd_query_t *query = dp_query_generate(comm, question, true, &rcode);
+    
+    if (!query) {
+        dp_simple_response(comm, rcode);
+        return;
+    }
+
+    dso_activity_t *activity = dso_add_activity(dso, activity_name, push_subscription_activity_type, query, dns_push_finalize);
+    query->activity = activity;
+    if (!dp_query_start(comm, query, &rcode, dns_push_query_callback)) {
+        dso_drop_activity(dso, activity);
+        dp_simple_response(comm, rcode);
+        return;
+    }
+    dp_simple_response(comm, dns_rcode_noerror);
+}
+
+void
+dns_push_reconfirm(comm_t *comm, dns_wire_t *header, dso_state_t *dso)
+{
+    dns_rr_t question;
+    char name[DNS_MAX_NAME_SIZE + 1];
+    uint16_t rdlen;
+
+    // The TLV offset should always be pointing into the message.
+    unsigned offp = dso->primary.payload - &header->data[0];
+    int len = offp + dso->primary.length;
+    
+    // Parse the name, rrtype and class.   We say there's no rdata even though there is
+    // because there's no ttl and also we want the raw rdata, not parsed rdata.
+    if (!dns_rr_parse(&question, header->data, len, &offp, false) ||
+        !dns_u16_parse(header->data, len, &offp, &rdlen)) {
+        dp_simple_response(comm, dns_rcode_formerr);
+        ERROR("dns_push_reconfirm: RR parse from %s failed", dso->remote_name);
+        return;
+    }
+    if (rdlen + offp != len) {
+        dp_simple_response(comm, dns_rcode_formerr);
+        ERROR("dns_push_reconfirm: RRdata parse from %s failed: length mismatch (%d != %d)",
+              dso->remote_name, rdlen + offp, len);
+        return;
+    }
+
+    if ((dp_served(question.name, name, sizeof name))) {
+        int len = strlen(name);
+        if (len + sizeof local_suffix > sizeof name) {
+            dp_simple_response(comm, dns_rcode_formerr);
+            ERROR("dns_push_reconfirm: name is too long for .local suffix: %s", name);
+            return;
+        }
+        memcpy(&name[len], local_suffix, sizeof local_suffix);
+    } else {
+        dns_name_print(question.name, &name[8], sizeof name - 8);
+    }
+    // transmogrify name.
+    DNSServiceReconfirmRecord(0, kDNSServiceInterfaceIndexAny, name,
+                              question.type, question.qclass, rdlen, &header->data[offp]);
+    dp_simple_response(comm, dns_rcode_noerror);
+}
+
+void
+dns_push_unsubscribe(comm_t *comm, dns_wire_t *header, dso_state_t *dso, dns_rr_t *question,
+                   dso_activity_t *activity, const char *opcode_name)
+{
+    dso_drop_activity(dso, activity);
+    // No response, unsubscribe is unidirectional.
+}
+
+void
+dns_push_subscription_change(const char *opcode_name, comm_t *comm, dns_wire_t *header, dso_state_t *dso)
+{
+    // type-in-hex/class-in-hex/name-to-subscribe
+    char activity_name[DNS_MAX_NAME_SIZE_ESCAPED + 3 + 4 + 4];
+    dso_activity_t *activity;
+    
+    // The TLV offset should always be pointing into the message.
+    unsigned offp = dso->primary.payload - &header->data[0];
+    // Get the question
+    dns_rr_t question;
+
+    if (!dns_rr_parse(&question, header->data, offp + dso->primary.length, &offp, false)) {
+        // Unsubscribes are unidirectional, so no response can be sent
+        if (dso->primary.opcode != kDSOType_DNSPushUnsubscribe) {
+            dp_simple_response(comm, dns_rcode_formerr);
+        }
+        ERROR("RR parse for %s from %s failed", dso->remote_name, opcode_name);
+        return;
+    }
+
+    // Concoct an activity name.
+    snprintf(activity_name, sizeof activity_name, "%04x%04x", question.type, question.qclass);
+    if ((dp_served(question.name, &activity_name[8], (sizeof activity_name) - 8))) {
+        int len = strlen(activity_name);
+        if (len + sizeof local_suffix + 8 > sizeof (activity_name)) {
+            ERROR("activity name overflow for %s", activity_name);
+            return;
+        }
+        strncpy(&activity_name[len], local_suffix, sizeof local_suffix);
+    } else {
+        dns_name_print(question.name, &activity_name[8], (sizeof activity_name) - 8);
+    }
+    
+    activity = dso_find_activity(dso, activity_name, push_subscription_activity_type, NULL);
+    if (activity == NULL) {
+        // Unsubscribe with no activity means no work to do; just return noerror.
+        if (dso->primary.opcode != kDSOType_DNSPushSubscribe) {
+            ERROR("dso_message: %s for %s when no subscription exists.", opcode_name, activity_name);
+            if (dso->primary.opcode == kDSOType_DNSPushReconfirm) {
+                dp_simple_response(comm, dns_rcode_noerror);
+            }
+        } else {
+            // In this case we have a push subscribe for which no subscription exists, which means we can do it.
+            dns_push_subscribe(comm, header, dso, &question, activity_name, opcode_name);
+        }
+    } else {
+        // Subscribe with a matching activity means no work to do; just return noerror.
+        if (dso->primary.opcode == kDSOType_DNSPushSubscribe) {
+            dp_simple_response(comm, dns_rcode_noerror);
+        }            
+        // Otherwise cancel the subscription.
+        else {
+            dns_push_unsubscribe(comm, header, dso, &question, activity, opcode_name);
+        }
+    }
+}
+
+static void dso_message(comm_t *comm, dns_wire_t *header, dso_state_t *dso)
+{
+    switch(dso->primary.opcode) {
+    case kDSOType_DNSPushSubscribe:
+        dns_push_subscription_change("DNS Push Subscribe", comm, header, dso);
+        break;
+    case kDSOType_DNSPushUnsubscribe:
+        dns_push_subscription_change("DNS Push Unsubscribe", comm, header, dso);
+        break;
+
+    case kDSOType_DNSPushReconfirm:
+        dns_push_reconfirm(comm, header, dso);
+        break;
+        
+    case kDSOType_DNSPushUpdate:
+        INFO("dso_message: bogus push update message %d", dso->primary.opcode);
+        dso_drop(dso);
+        break;
+
+    default:
+        INFO("dso_message: unexpected primary TLV %d", dso->primary.opcode);
+        dp_simple_response(comm, dns_rcode_dsotypeni);
+        break;
+    }
+    // XXX free the message if we didn't consume it.
+}
+
+static void dns_push_callback(void *context, void *header_context,
+                              dso_state_t *dso, dso_event_type_t eventType)
+{
+    dns_wire_t *header = header_context;
+       switch(eventType)
+    {
+       case kDSOEventType_DNSMessage:
+        // We shouldn't get here because we already handled any DNS messages
+               INFO("dns_push_callback: DNS Message (opcode=%d) received from %s", dns_opcode_get(header), dso->remote_name);
+               break;
+       case kDSOEventType_DNSResponse:
+        // We shouldn't get here because we already handled any DNS messages
+               INFO("dns_push_callback: DNS Response (opcode=%d) received from %s", dns_opcode_get(header), dso->remote_name);
+               break;
+       case kDSOEventType_DSOMessage:
+               INFO("dns_push_callback: DSO Message (Primary TLV=%d) received from %s",
+               dso->primary.opcode, dso->remote_name);
+        dso_message((comm_t *)context, (dns_wire_t *)header, dso);
+               break;
+       case kDSOEventType_DSOResponse:
+               INFO("dns_push_callback: DSO Response (Primary TLV=%d) received from %s",
+               dso->primary.opcode, dso->remote_name);
+               break;
+
+       case kDSOEventType_Finalize:
+               INFO("dns_push_callback: Finalize");
+               break;
+
+       case kDSOEventType_Connected:
+               INFO("dns_push_callback: Connected to %s", dso->remote_name);
+               break;
+
+       case kDSOEventType_ConnectFailed:
+               INFO("dns_push_callback: Connection to %s failed", dso->remote_name);
+               break;
+
+       case kDSOEventType_Disconnected:
+               INFO("dns_push_callback: Connection to %s disconnected", dso->remote_name);
+               break;
+       }
+}
+
+void
+dp_dns_query(comm_t *comm, dns_rr_t *question)
+{
+    int rcode;
+    dnssd_query_t *query = dp_query_generate(comm, question, false, &rcode);
+    const char *failnote = NULL;
+    if (!query) {
+        dp_simple_response(comm, rcode);
+        return;
+    }
+
+    // For regular DNS queries, copy the ID, etc.
+    query->response.id = comm->message->wire.id;
+    query->response.bitfield = comm->message->wire.bitfield;
+    dns_rcode_set(&query->response, dns_rcode_noerror);
+
+    // For DNS queries, we need to return the question.
+    query->response.qdcount = htons(1);
+    if (query->enclosing_domain != NULL) {
+        TOWIRE_CHECK("name", &query->towire, dns_name_to_wire(NULL, &query->towire, query->name));
+        TOWIRE_CHECK("enclosing_domain", &query->towire,
+                     dns_full_name_to_wire(&query->enclosing_domain_pointer,
+                                           &query->towire, query->enclosing_domain));
+    } else {
+        TOWIRE_CHECK("full name", &query->towire, dns_full_name_to_wire(NULL, &query->towire, query->name));
+    }        
+    TOWIRE_CHECK("TYPE", &query->towire, dns_u16_to_wire(&query->towire, question->type));    // TYPE
+    TOWIRE_CHECK("CLASS", &query->towire, dns_u16_to_wire(&query->towire, question->qclass));  // CLASS
+    if (failnote != NULL) {
+        ERROR("dp_dns_query: failure encoding question: %s", failnote);
+        goto fail;
+    }
+    
+    // We should check for OPT RR, but for now assume it's there.
+    query->is_edns0 = true;
+
+    if (!dp_query_start(comm, query, &rcode, dns_query_callback)) {
+    fail:
+        dp_simple_response(comm, rcode);
+        free(query->name);
+        free(query);
+        return;
+    }
+    
+    // XXX make sure that finalize frees this.
+    query->question = comm->message;
+    comm->message = NULL;
+}
+
+void dso_transport_finalize(comm_t *comm)
+{
+    dso_state_t *dso = comm->dso;
+    INFO("dso_transport_finalize: %s", dso->remote_name);
+    if (comm) {
+        ioloop_close(&comm->io);
+    }
+    free(dso);
+    comm->dso = NULL;
+}
+
+void dns_evaluate(comm_t *comm)
+{
+    dns_rr_t question;
+    unsigned offset = 0;
+
+    // Drop incoming responses--we're a server, so we only accept queries.
+    if (dns_qr_get(&comm->message->wire) == dns_qr_response) {
+        return;
+    }
+
+    // If this is a DSO message, see if we have a session yet.
+    switch(dns_opcode_get(&comm->message->wire)) {
+    case dns_opcode_dso:
+        if (!comm->tcp_stream) {
+            ERROR("DSO message received on non-tcp socket %s", comm->name);
+            dp_simple_response(comm, dns_rcode_notimp);
+            return;
+        }
+        
+        if (!comm->dso) {
+            comm->dso = dso_create(true, 0, comm->name, dns_push_callback, comm, comm);
+            if (!comm->dso) {
+                ERROR("Unable to create a dso context for %s", comm->name);
+                dp_simple_response(comm, dns_rcode_servfail);
+                ioloop_close(&comm->io);
+                return;
+            }
+            comm->dso->transport_finalize = dso_transport_finalize;
+        }
+        dso_message_received(comm->dso, (uint8_t *)&comm->message->wire, comm->message->length);
+        break;
+
+    case dns_opcode_query:
+        // In theory this is permitted but it can't really be implemented because there's no way
+        // to say "here's the answer for this, and here's why that failed.
+        if (ntohs(comm->message->wire.qdcount) != 1) {
+            dp_simple_response(comm, dns_rcode_formerr);
+            return;
+        }
+        if (!dns_rr_parse(&question, comm->message->wire.data, comm->message->length, &offset, 0)) {
+            dp_simple_response(comm, dns_rcode_formerr);
+            return;
+        }
+        dp_dns_query(comm, &question);
+        dns_rrdata_free(&question);
+        break;
+
+        // No support for other opcodes yet.
+    default:
+        dp_simple_response(comm, dns_rcode_notimp);
+        break;
+    }
+}
+
+void dns_input(comm_t *comm)
+{
+    dns_evaluate(comm);
+    if (comm->message != NULL) {
+        message_free(comm->message);
+        comm->message = NULL;
+    }
+}
+
+static int
+usage(const char *progname)
+{
+    ERROR("usage: %s", progname);
+    ERROR("ex: dnssd-proxy");
+    return 1;
+}
+
+// Called whenever we get a connection.
+void
+connected(comm_t *comm)
+{
+    INFO("connection from %s", comm->name);
+    return;
+}
+
+int
+main(int argc, char **argv)
+{
+    int i;
+    int16_t port;
+    comm_t *tcp4_listener;
+    comm_t *udp4_listener;
+
+    port = htons(53);
+
+    // Read the configuration from the command line.
+    for (i = 1; i < argc; i++) {
+        return usage(argv[0]);
+    }
+
+    if (!ioloop_init()) {
+        return 1;
+    }
+
+    // Set up hardwired answers
+    dnssd_hardwired_setup();
+
+    // XXX Support IPv6!
+    tcp4_listener = setup_listener_socket(AF_INET, IPPROTO_TCP, port, "IPv4 DNS Push Listener", dns_input, connected, 0);
+    if (tcp4_listener == NULL) {
+        ERROR("TCPv4 listener: fail.");
+        return 1;
+    }
+    
+    udp4_listener = setup_listener_socket(AF_INET, IPPROTO_UDP, port, "IPv4 DNS UDP Listener", dns_input, 0, 0);
+    if (udp4_listener == NULL) {
+        ERROR("UDP4 listener: fail.");
+        return 1;
+    }
+    
+    do {
+        int something = 0;
+        something = ioloop_events(0);
+        INFO("dispatched %d events.", something);
+    } while (1);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/dnssd-proxy.h b/ServiceRegistration/dnssd-proxy.h
new file mode 100644 (file)
index 0000000..6e8b462
--- /dev/null
@@ -0,0 +1,25 @@
+/* dnssd-proxy.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Discovery Proxy globals.
+ */
+
+void dp_formerr(comm_t *NONNULL comm);
+bool dp_served(dns_name_t *NONNULL name);
+void dp_query(comm_t *NONNULL comm, unsigned offset, dns_rr_t *NONNULL question);
+
+
+
diff --git a/ServiceRegistration/fromwire.c b/ServiceRegistration/fromwire.c
new file mode 100644 (file)
index 0000000..0152536
--- /dev/null
@@ -0,0 +1,750 @@
+/* fromwire.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS wire-format functions.
+ *
+ * These are really simple functions for constructing DNS messages wire format.
+ * The flow is that there is a transaction structure which contains pointers to both
+ * a message output buffer and a response input buffer.   The structure is initialized,
+ * and then the various wire format functions are called repeatedly to store data.
+ * If an error occurs during this process, it's okay to just keep going, because the
+ * error is recorded in the transaction; once all of the copy-in functions have been
+ * called, the error status can be checked once at the end.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "srp.h"
+#include "dns-msg.h"
+
+bool
+dns_opt_parse(dns_edns0_t *NONNULL *NULLABLE ret, dns_rr_t *rr)
+{
+    return true;
+}
+
+dns_label_t * NULLABLE
+dns_label_parse(const uint8_t *buf, unsigned mlen, unsigned *NONNULL offp)
+{
+    uint8_t llen = buf[*offp];
+    dns_label_t *rv;
+
+    // Make sure that we got the data this label claims to encompass.
+    if (*offp + llen + 1 > mlen) {
+        DEBUG("claimed length of label is too long: %u > %u.\n", *offp + llen + 1, mlen);
+        return NULL;
+    }
+
+    rv = calloc(llen + 1 - DNS_MAX_LABEL_SIZE + sizeof *rv, 1);
+    if (rv == NULL) {
+        DEBUG("memory allocation for %u byte label (%.*s) failed.\n",
+              *offp + llen + 1, *offp + llen + 1, &buf[*offp + 1]);
+        return NULL;
+    }
+
+    rv->len = llen;
+    memcpy(rv->data, &buf[*offp + 1], llen);
+    rv->data[llen] = 0; // We NUL-terminate the label for convenience
+    *offp += llen + 1;
+    return rv;
+}
+
+bool
+dns_name_parse(dns_label_t *NONNULL *NULLABLE ret, const uint8_t *buf, unsigned len,
+               unsigned *NONNULL offp, unsigned base)
+{
+    dns_label_t *rv;
+
+    if (*offp == len) {
+        return false;
+    }
+
+    // A pointer?
+    if ((buf[*offp] & 0xC0) == 0xC0) {
+        unsigned pointer;
+        if (*offp + 2 > len) {
+            DEBUG("incomplete compression pointer: %u > %u", *offp + 2, len);
+            return false;
+        }
+        pointer = (((unsigned)buf[*offp] & 0x3f) << 8) | (unsigned)buf[*offp + 1];
+        *offp += 2;
+        if (pointer >= base) {
+            // Don't allow a pointer forward, or to a pointer we've already visited.
+            DEBUG("compression pointer points forward: %u >= %u.\n", pointer, base);
+            return false;
+        }
+        if (pointer < DNS_HEADER_SIZE) {
+            // Don't allow pointers into the header.
+            DEBUG("compression pointer points into header: %u.\n", pointer);
+            return false;
+        }
+        pointer -= DNS_HEADER_SIZE;
+        if (buf[pointer] & 0xC0) {
+            // If this is a pointer to a pointer, it's not valid.
+            DEBUG("compression pointer points into pointer: %u %02x%02x.\n", pointer,
+                  buf[pointer], pointer + 1 < len ? buf[pointer + 1] : 0xFF);
+            return false;
+        }
+        if (buf[pointer] + pointer >= base || buf[pointer] + pointer >= *offp) {
+            // Possibly this isn't worth checking.
+            DEBUG("compression pointer points to something that goes past current position: %u %u\n",
+                  pointer, buf[pointer]);
+            return false;
+        }
+        return dns_name_parse(ret, buf, len, &pointer, pointer);
+    }
+    // We don't support binary labels, which are historical, and at this time there are no other valid
+    // DNS label types.
+    if (buf[*offp] & 0xC0) {
+        DEBUG("invalid label type: %x\n", buf[*offp]);
+        return false;
+    }
+    
+    rv = dns_label_parse(buf, len, offp);
+    if (rv == NULL) {
+        return false;
+    }
+
+    *ret = rv;
+
+    if (rv->len == 0) {
+        return true;
+    }
+    return dns_name_parse(&rv->next, buf, len, offp, base);
+}
+
+bool
+dns_u8_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint8_t *NONNULL ret)
+{
+    uint8_t rv;
+    if (*offp + 1 > len) {
+        DEBUG("dns_u8_parse: not enough room: %u > %u.\n", *offp + 1, len);
+        return false;
+    }
+
+    rv = buf[*offp];
+    *offp += 1;
+    *ret = rv;
+    return true;
+}
+
+bool
+dns_u16_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint16_t *NONNULL ret)
+{
+    uint16_t rv;
+    if (*offp + 2 > len) {
+        DEBUG("dns_u16_parse: not enough room: %u > %u.\n", *offp + 2, len);
+        return false;
+    }
+
+    rv = ((uint16_t)(buf[*offp]) << 8) | (uint16_t)(buf[*offp + 1]);
+    *offp += 2;
+    *ret = rv;
+    return true;
+}
+
+bool
+dns_u32_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint32_t *NONNULL ret)
+{
+    uint32_t rv;
+    if (*offp + 4 > len) {
+        DEBUG("dns_u32_parse: not enough room: %u > %u.\n", *offp + 4, len);
+        return false;
+    }
+
+    rv = (((uint32_t)(buf[*offp]) << 24) | ((uint32_t)(buf[*offp + 1]) << 16) |
+          ((uint32_t)(buf[*offp + 2]) << 8) | (uint32_t)(buf[*offp + 3]));
+    *offp += 4;
+    *ret = rv;
+    return true;
+}
+
+static void
+dns_name_dump(FILE *outfile, dns_label_t *name)
+{
+    char buf[DNS_MAX_NAME_SIZE_ESCAPED + 1];
+    
+    dns_name_print(name, buf, sizeof buf);
+    fputs(buf, outfile);
+}
+
+static void
+dns_rrdata_dump(FILE *outfile, dns_rr_t *rr)
+{
+    int i;
+    char nbuf[80];
+    dns_txt_element_t *txt;
+
+    switch(rr->type) {
+    case dns_rrtype_key:
+        fprintf(outfile, "KEY <AC %d> <Z %d> <XT %d> <ZZ %d> <NAMTYPE %d> <ZZZZ %d> <ORY %d> %d %d ",
+                ((rr->data.key.flags & 0xC000) >> 14 & 3), ((rr->data.key.flags & 0x2000) >> 13) & 1,
+                ((rr->data.key.flags & 0x1000) >> 12) & 1, ((rr->data.key.flags & 0xC00) >> 10) & 3,
+                ((rr->data.key.flags & 0x300) >> 8) & 3, ((rr->data.key.flags & 0xF0) >> 4) & 15, rr->data.key.flags & 15,
+                rr->data.key.protocol, rr->data.key.algorithm);
+        for (i = 0; i < rr->data.key.len; i++) {
+            if (i == 0) {
+                fprintf(outfile, "%d [%02x", rr->data.key.len, rr->data.key.key[i]);
+            } else {
+                fprintf(outfile, " %02x", rr->data.key.key[i]);
+            }
+        }
+        fputc(']', outfile);
+        break;
+        
+    case dns_rrtype_sig:
+        fprintf(outfile, "SIG %d %d %d %lu %lu %lu %d ",
+                rr->data.sig.type, rr->data.sig.algorithm, rr->data.sig.label,
+                (unsigned long)rr->data.sig.rrttl, (unsigned long)rr->data.sig.expiry,
+                (unsigned long)rr->data.sig.inception, rr->data.sig.key_tag);
+        dns_name_dump(outfile, rr->data.sig.signer);
+        for (i = 0; i < rr->data.sig.len; i++) {
+            if (i == 0) {
+                fprintf(outfile, "%d [%02x", rr->data.sig.len, rr->data.sig.signature[i]);
+            } else {
+                fprintf(outfile, " %02x", rr->data.sig.signature[i]);
+            }
+        }
+        fputc(']', outfile);
+        break;
+        
+    case dns_rrtype_srv:
+        fprintf(outfile, "SRV %d %d %d ", rr->data.srv.priority, rr->data.srv.weight, rr->data.srv.port);
+        dns_name_dump(outfile, rr->data.ptr.name);
+        break;
+
+    case dns_rrtype_ptr:
+        fputs("PTR ", outfile);
+        dns_name_dump(outfile, rr->data.ptr.name);
+        break;
+
+    case dns_rrtype_cname:
+        fputs("CNAME ", outfile);
+        dns_name_dump(outfile, rr->data.ptr.name);
+        break;
+
+    case dns_rrtype_a:
+        fputs("A", outfile);
+        for (i = 0; i < rr->data.a.num; i++) {
+            inet_ntop(AF_INET, &rr->data.a.addrs[i], nbuf, sizeof nbuf);
+            putc(' ', outfile);
+            fputs(nbuf, outfile);
+        }
+        break;
+        
+    case dns_rrtype_aaaa:
+        fputs("AAAA", outfile);
+        for (i = 0; i < rr->data.aaaa.num; i++) {
+            inet_ntop(AF_INET6, &rr->data.aaaa.addrs[i], nbuf, sizeof nbuf);
+            putc(' ', outfile);
+            fputs(nbuf, outfile);
+        }
+        break;
+
+    case dns_rrtype_txt:
+        fputs("TXT", outfile);
+        for (txt = rr->data.txt; txt; txt = txt->next) {
+            putc(' ', outfile);
+            putc('"', outfile);
+            for (i = 0; i < txt->len; i++) {
+                if (isascii(txt->data[i]) && isprint(txt->data[i])) {
+                    putc(txt->data[i], outfile);
+                } else {
+                    fprintf(outfile, "<%x>", txt->data[i]);
+                }
+            }
+            putc('"', outfile);
+        }
+        break;
+
+    default:
+        fprintf(outfile, "<rrtype %d>:", rr->type);
+        if (rr->data.unparsed.len == 0) {
+            fputs(" <none>", outfile);
+        } else {
+            for (i = 0; i < rr->data.unparsed.len; i++) {
+                fprintf(outfile, " %02x", rr->data.unparsed.data[i]);
+            }
+        }
+        break;
+    }
+}
+
+bool
+dns_rdata_parse_data(dns_rr_t *NONNULL rr, const uint8_t *buf, unsigned *NONNULL offp, unsigned target, unsigned rdlen, unsigned rrstart)
+{
+    uint16_t addrlen;
+    dns_txt_element_t *txt, **ptxt;
+
+    switch(rr->type) {
+    case dns_rrtype_key:
+        if (!dns_u16_parse(buf, target, offp, &rr->data.key.flags) ||
+            !dns_u8_parse(buf, target, offp, &rr->data.key.protocol) ||
+            !dns_u8_parse(buf, target, offp, &rr->data.key.algorithm)) {
+            return false;
+        }
+        rr->data.key.len = target - *offp;
+        rr->data.key.key = malloc(rr->data.key.len);
+        if (!rr->data.key.key) {
+            return false;
+        }
+        memcpy(rr->data.key.key, &buf[*offp], rr->data.key.len);
+        *offp += rr->data.key.len;
+        break;
+
+    case dns_rrtype_sig:
+        rr->data.sig.start = rrstart;
+        if (!dns_u16_parse(buf, target, offp, &rr->data.sig.type) ||
+            !dns_u8_parse(buf, target, offp, &rr->data.sig.algorithm) ||
+            !dns_u8_parse(buf, target, offp, &rr->data.sig.label) ||
+            !dns_u32_parse(buf, target, offp, &rr->data.sig.rrttl) ||
+            !dns_u32_parse(buf, target, offp, &rr->data.sig.expiry) ||
+            !dns_u32_parse(buf, target, offp, &rr->data.sig.inception) ||
+            !dns_u16_parse(buf, target, offp, &rr->data.sig.key_tag) ||
+            !dns_name_parse(&rr->data.sig.signer, buf, target, offp, *offp)) {
+            return false;
+        }
+        // The signature is what's left of the RRDATA.  It covers the message up to the signature, so we
+        // remember where it starts so as to know what memory to cover to validate it.
+        rr->data.sig.len = target - *offp;
+        rr->data.sig.signature = malloc(rr->data.sig.len);
+        if (!rr->data.sig.signature) {
+            return false;
+        }
+        memcpy(rr->data.sig.signature, &buf[*offp], rr->data.sig.len);
+        *offp += rr->data.sig.len;
+        break;
+        
+    case dns_rrtype_srv:
+        if (!dns_u16_parse(buf, target, offp, &rr->data.srv.priority) ||
+            !dns_u16_parse(buf, target, offp, &rr->data.srv.weight) ||
+            !dns_u16_parse(buf, target, offp, &rr->data.srv.port)) {
+            return false;
+        }
+        // This fallthrough assumes that the first element in the srv, ptr and cname structs is
+        // a pointer to a domain name.
+
+    case dns_rrtype_ptr:
+    case dns_rrtype_cname:
+        if (!dns_name_parse(&rr->data.ptr.name, buf, target, offp, *offp)) {
+            return false;
+        }
+        break;
+
+        // We assume below that the a and aaaa structures in the data union are exact aliases of
+        // each another.
+    case dns_rrtype_a:
+        addrlen = 4;
+        goto addr_parse;
+        
+    case dns_rrtype_aaaa:
+        addrlen = 16;
+    addr_parse:
+        if (rdlen & (addrlen - 1)) {
+            DEBUG("dns_rdata_parse: %s rdlen not an even multiple of %u: %u",
+                  addrlen == 4 ? "A" : "AAAA", addrlen, rdlen);
+            return false;
+        }
+        rr->data.a.addrs = malloc(rdlen);
+        if (rr->data.a.addrs == NULL) {
+            return false;
+        }
+        rr->data.a.num = rdlen /  addrlen;
+        memcpy(rr->data.a.addrs, &buf[*offp], rdlen);
+        *offp = target;
+        break;
+        
+    case dns_rrtype_txt:
+        ptxt = &rr->data.txt;
+        while (*offp < target) {
+            unsigned tlen = buf[*offp];
+            if (*offp + tlen + 1 > target) {
+                DEBUG("dns_rdata_parse: TXT RR length is larger than available space: %u %u",
+                      *offp + tlen + 1, target);
+                *ptxt = NULL;
+                return false;
+            }
+            txt = malloc(tlen + 1 + sizeof *txt);
+            if (txt == NULL) {
+                DEBUG("dns_rdata_parse: no memory for TXT RR");
+                return false;
+            }
+            txt->len = tlen;
+            ++*offp;
+            memcpy(txt->data, &buf[*offp], tlen);
+            *offp += tlen;
+            txt->data[tlen] = 0;
+            *ptxt = txt;
+            ptxt = &txt->next;
+        }
+        break;
+
+    default:
+        if (rdlen > 0) {
+            rr->data.unparsed.data = malloc(rdlen);
+            if (rr->data.unparsed.data == NULL) {
+                return false;
+            }
+            memcpy(rr->data.unparsed.data, &buf[*offp], rdlen);
+        }
+        rr->data.unparsed.len = rdlen;
+        *offp = target;
+        break;
+    }
+    if (*offp != target) {
+        DEBUG("dns_rdata_parse: parse for rrtype %d not fully contained: %u %u", rr->type, target, *offp);
+        return false;
+    }
+    return true;
+}
+
+static bool
+dns_rdata_parse(dns_rr_t *NONNULL rr,
+                const uint8_t *buf, unsigned len, unsigned *NONNULL offp, unsigned rrstart)
+{
+    uint16_t rdlen;
+    unsigned target;
+    
+    if (!dns_u16_parse(buf, len, offp, &rdlen)) {
+        return false;
+    }
+    target = *offp + rdlen;
+    if (target > len) {
+        return false;
+    }
+    return dns_rdata_parse_data(rr, buf, offp, target, rdlen, rrstart);
+}
+
+bool
+dns_rr_parse(dns_rr_t *NONNULL rr,
+             const uint8_t *buf, unsigned len, unsigned *NONNULL offp, bool rrdata_expected)
+{
+    int rrstart = *offp; // Needed to mark the start of the SIG RR for SIG(0).
+    memset(rr, 0, sizeof *rr);
+    if (!dns_name_parse(&rr->name, buf, len, offp, *offp)) {
+        return false;
+    }
+    
+    if (!dns_u16_parse(buf, len, offp, &rr->type)) {
+        return false;
+    }
+
+    if (!dns_u16_parse(buf, len, offp, &rr->qclass)) {
+        return false;
+    }
+    
+    if (rrdata_expected) {
+        if (!dns_u32_parse(buf, len, offp, &rr->ttl)) {
+            return false;
+        }
+        if (!dns_rdata_parse(rr, buf, len, offp, rrstart)) {
+            return false;
+        }
+    }
+        
+    printf("rrtype: %u  qclass: %u  name: ", rr->type, rr->qclass);
+    dns_name_dump(stdout, rr->name);
+    if (rrdata_expected) {
+        printf("  rrdata: ");
+        dns_rrdata_dump(stdout, rr);
+    }
+    printf("\n");
+    return true;
+}
+
+void dns_name_free(dns_label_t *name)
+{
+    dns_label_t *next;
+    if (name == NULL) {
+        return;
+    }
+    next = name->next;
+    free(name);
+    return dns_name_free(next);
+}    
+
+void
+dns_rrdata_free(dns_rr_t *rr)
+{
+    switch(rr->type) {
+    case dns_rrtype_key:
+        free(rr->data.key.key);
+        break;
+        
+    case dns_rrtype_sig:
+        dns_name_free(rr->data.sig.signer);
+        free(rr->data.sig.signature);
+        break;
+        
+    case dns_rrtype_srv:
+    case dns_rrtype_ptr:
+    case dns_rrtype_cname:
+        dns_name_free(rr->data.ptr.name);
+        rr->data.ptr.name = NULL;
+        break;
+
+    case dns_rrtype_a:
+    case dns_rrtype_aaaa:
+        free(rr->data.a.addrs);
+        rr->data.a.addrs = NULL;
+        break;
+        
+    case dns_rrtype_txt:
+    default:
+        free(rr->data.unparsed.data);
+        rr->data.unparsed.data = NULL;
+        break;
+    }
+}
+
+void
+dns_message_free(dns_message_t *message)
+{
+    int i;
+
+#define FREE(count, sets)                           \
+    for (i = 0; i < message->count; i++) {          \
+        dns_rr_t *set = &message->sets[i];          \
+        if (set->name) {                            \
+            dns_name_free(set->name);               \
+            set->name = NULL;                       \
+        }                                           \
+        dns_rrdata_free(set);                       \
+    }                                               \
+    if (message->sets) {                            \
+        free(message->sets);                        \
+    }
+    FREE(qdcount, questions);
+    FREE(ancount, answers);
+    FREE(nscount, authority);
+    FREE(arcount, additional);
+#undef FREE
+}
+
+bool
+dns_wire_parse(dns_message_t *NONNULL *NULLABLE ret, dns_wire_t *message, unsigned len)
+{
+    unsigned offset = 0;
+    dns_message_t *rv = calloc(sizeof *rv, 1);
+    int i;
+    
+    if (rv == NULL) {
+        return false;
+    }
+    
+#define PARSE(count, sets, name, rrdata_expected)                                   \
+    rv->count = ntohs(message->count);                                              \
+    if (rv->count > 50) {                                                           \
+        dns_message_free(rv);                                                       \
+        return false;                                                               \
+    }                                                                               \
+                                                                                    \
+    if (rv->qdcount != 0) {                                                         \
+        rv->sets = calloc(sizeof *rv->sets, rv->count);                             \
+        if (rv->sets == NULL) {                                                     \
+            dns_message_free(rv);                                                   \
+            return false;                                                           \
+        }                                                                           \
+    }                                                                               \
+                                                                                    \
+    for (i = 0; i < rv->count; i++) {                                               \
+        if (!dns_rr_parse(&rv->sets[i], message->data, len, &offset, rrdata_expected)) {       \
+            dns_message_free(rv);                                                   \
+            fprintf(stderr, name " %d RR parse failed.\n", i);                      \
+            return false;                                                           \
+        }                                                                           \
+    }
+    PARSE(qdcount,  questions, "question", false);
+    PARSE(ancount,    answers, "answers", true);
+    PARSE(nscount,  authority, "authority", true);
+    PARSE(arcount, additional, "additional", true);
+#undef PARSE
+    
+    for (i = 0; i < rv->ancount; i++) {
+        // Parse EDNS(0)
+        if (rv->additional[i].type == dns_rrtype_opt) {
+            if (!dns_opt_parse(&rv->edns0, &rv->additional[i])) {
+                dns_message_free(rv);
+                return false;
+            }
+        }
+    }
+    *ret = rv;
+    return true;
+}
+
+const char *NONNULL
+dns_name_print(dns_name_t *NONNULL name, char *buf, int bufmax)
+{
+    dns_label_t *lp;
+    int ix = 0;
+    int i;
+
+    // Copy the labels in one at a time, putting a dot between each one; if there isn't room
+    // in the buffer (shouldn't be the case), copy as much as will fit, leaving room for a NUL
+    // termination.
+    for (lp = name; lp; lp = lp->next) {
+        if (ix != 0) {
+            if (ix + 2 >= bufmax) {
+                break;
+            }
+            buf[ix++] = '.';
+        }
+        for (i = 0; i < lp->len; i++) {
+            if (isascii(lp->data[i]) && isprint(lp->data[i])) {
+                if (ix + 2 >= bufmax) {
+                    break;
+                }
+                buf[ix++] = lp->data[i];
+            } else {
+                if (ix + 5 >= bufmax) {
+                    break;
+                }
+                buf[ix++] = '\\';
+                buf[ix++] = '0' + (lp->data[i] >> 6);
+                buf[ix++] = '0' + (lp->data[i] >> 3) & 3;
+                buf[ix++] = '0' + lp->data[i] & 3;
+            }
+        }
+        if (i != lp->len) {
+            break;
+        }
+    }
+    buf[ix++] = 0;
+    return buf;
+}
+
+bool
+labeleq(const char *label1, const char *label2, size_t len)
+{
+    int i;
+    for (i = 0; i < len; i++) {
+        if (isascii(label1[i]) && isascii(label2[i])) {
+            if (tolower(label1[i]) != tolower(label2[i])) {
+                return false;
+            }
+        }
+        else {
+            if (label1[i] != label2[i]) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool
+dns_names_equal(dns_label_t *NONNULL name1, dns_label_t *NONNULL name2)
+{
+    if (name1->len != name2->len) {
+        return false;
+    }
+    if (name1->len != 0 && !labeleq(name1->data, name2->data, name1->len) != 0) {
+        return false;
+    }
+    if (name1->next != NULL && name2->next != NULL) {
+        return dns_names_equal(name1->next, name2->next);
+    }
+    if (name1->next == NULL && name2->next == NULL) {
+        return true;
+    }
+    return false;
+}
+
+// Note that "foo.arpa" is not the same as "foo.arpa."
+bool
+dns_names_equal_text(dns_label_t *NONNULL name1, const char *NONNULL name2)
+{
+    const char *ndot;
+    ndot = strchr(name2, '.');
+    if (ndot == NULL) {
+        ndot = name2 + strlen(name2);
+    }
+    if (name1->len != ndot - name2) {
+        return false;
+    }
+    if (name1->len != 0 && !labeleq(name1->data, name2, name1->len) != 0) {
+        return false;
+    }
+    if (name1->next != NULL && *ndot == '.') {
+        return dns_names_equal_text(name1->next, ndot + 1);
+    }
+    if (name1->next == NULL && *ndot == 0) {
+        return true;
+    }
+    return false;
+}
+
+// Find the length of a name in uncompressed wire format.
+// This is in fromwire because we use it for validating signatures, and don't need it for
+// sending.
+static size_t
+dns_name_wire_length_in(dns_label_t *NONNULL name, size_t ret)
+{
+    // Root label.
+    if (name == NULL)
+        return ret;
+    return dns_name_wire_length_in(name->next, ret + name->len + 1);
+}
+
+size_t
+dns_name_wire_length(dns_label_t *NONNULL name)
+{
+    return dns_name_wire_length_in(name, 0);
+}
+
+// Copy a name we've parsed from a message out in canonical wire format so that we can
+// use it to verify a signature.   As above, not actually needed for copying to a message
+// we're going to send, since in that case we want to try to compress.
+static size_t
+dns_name_to_wire_canonical_in(uint8_t *NONNULL buf, size_t max, size_t ret, dns_label_t *NONNULL name)
+{
+    INFO("dns_name_to_wire_canonical_in: buf %p max %zd ret %zd  name = %p '%.*s'",
+         buf, max, ret, name, name ? name->len : 0, name ? name->data : "");
+    if (name == NULL) {
+        return ret;
+    }
+    if (max < name->len + 1) {
+        return 0;
+    }
+    *buf = name->len;
+    memcpy(buf + 1, name->data, name->len);
+    return dns_name_to_wire_canonical_in(buf + name->len + 1,
+                                         max - name->len - 1, ret + name->len + 1, name->next);
+}
+
+size_t
+dns_name_to_wire_canonical(uint8_t *NONNULL buf, size_t max, dns_label_t *NONNULL name)
+{
+    return dns_name_to_wire_canonical_in(buf, max, 0, name);
+}
+    
+
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/ioloop.c b/ServiceRegistration/ioloop.c
new file mode 100644 (file)
index 0000000..3218e7b
--- /dev/null
@@ -0,0 +1,618 @@
+/* dispatch.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Simple event dispatcher for DNS.
+ */
+
+#define __APPLE_USE_RFC_3542
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/uio.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/time.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+#include "ioloop.h"
+#include "dnssd-proxy.h"
+
+#define USE_SELECT
+#pragma mark Globals
+io_t *ios;
+int64_t ioloop_now;
+
+#ifdef USE_KQUEUE
+int kq;
+#endif
+
+int
+getipaddr(addr_t *addr, const char *p)
+{
+    if (inet_pton(AF_INET, p, &addr->sin.sin_addr)) {
+        addr->sa.sa_family = AF_INET;
+        return sizeof addr->sin;
+    }  else if (inet_pton(AF_INET6, p, &addr->sin6.sin6_addr)) {
+        addr->sa.sa_family = AF_INET6;
+        return sizeof addr->sin6;
+    } else {
+        return 0;
+    }
+}                
+
+int64_t
+ioloop_timenow()
+{
+    int64_t now;
+    struct timeval tv;
+    gettimeofday(&tv, 0);
+    now = (int64_t)tv.tv_sec * 1000 + (int64_t)tv.tv_usec / 1000;
+    return now;
+}
+
+message_t *
+message_allocate(size_t message_size)
+{
+    message_t *message = (message_t *)malloc(message_size + (sizeof (message_t)) - (sizeof (dns_wire_t)));
+    if (message)
+        memset(message, 0, (sizeof (message_t)) - (sizeof (dns_wire_t)));
+    return message;
+}
+
+void
+message_free(message_t *message)
+{
+    free(message);
+}
+
+void
+comm_free(comm_t *comm)
+{
+    if (comm->name) {
+        free(comm->name);
+        comm->name = NULL;
+    }
+    if (comm->message) {
+        message_free(comm->message);
+        comm->message = NULL;
+        comm->buf = NULL;
+    }
+    free(comm);
+}
+
+void
+ioloop_close(io_t *io)
+{
+    close(io->sock);
+    io->sock = -1;
+}
+
+void
+add_reader(io_t *io, io_callback_t callback, io_callback_t finalize)
+{
+    io->next = ios;
+    ios = io;
+    io->read_callback = callback;
+    io->finalize = finalize;
+#ifdef USE_SELECT
+    io->want_read = true;
+#endif
+#ifdef USE_EPOLL
+#endif
+#ifdef USE_KQUEUE
+    struct kevent ev;
+    int rv;
+    EV_SET(&ev, io->sock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, io);
+    rv = kevent(kq, &ev, 1, NULL, 0, NULL);
+    if (rv < 0) {
+        ERROR("kevent add: %s", strerror(errno));
+        return;
+    }
+#endif // USE_EPOLL
+}
+
+bool
+ioloop_init(void)
+{
+    signal(SIGPIPE, SIG_IGN); // because why ever?
+#ifdef USE_KQUEUE
+    kq = kqueue();
+    if (kq < 0) {
+        ERROR("kqueue(): %s", strerror(errno));
+        return false;
+    }
+#endif
+    return true;
+}
+
+int
+ioloop_events(int64_t timeout_when)
+{
+    io_t *io, **iop;
+    int nev = 0, rv;
+    int64_t now = ioloop_timenow();
+    int64_t next_event = timeout_when;
+    int64_t timeout = 0;
+
+    INFO("%qd.%03qd seconds have passed on entry to ioloop_events", (now - ioloop_now) / 1000, (now - ioloop_now) % 1000);
+    ioloop_now = now;
+
+    // A timeout of zero means don't time out.
+    if (timeout_when == 0) {
+        next_event = INT64_MAX;
+    } else {
+        next_event = timeout_when;
+    }
+
+#ifdef USE_SELECT
+    int nfds = 0;
+    fd_set reads, writes, errors;
+    struct timeval tv;
+
+    FD_ZERO(&reads);
+    FD_ZERO(&writes);
+    FD_ZERO(&errors);
+    
+#endif
+    iop = &ios;
+    while (*iop) {
+        io = *iop;
+        if (io->sock != -1 && io->wakeup_time != 0) {
+            if (io->wakeup_time <= ioloop_now) {
+                io->wakeup_time = 0;
+                io->wakeup(io);
+                ++nev;
+            } else if (io->wakeup_time < next_event) {
+                next_event = io->wakeup_time;
+            }
+        }
+
+        if (io->sock == -1) {
+            *iop = io->next;
+            if (io->finalize) {
+                io->finalize(io);
+            } else {
+                free(io);
+            }
+            continue;
+        }
+
+        // INFO("now: %qd  io %d wakeup_time %qd  next_event %qd", ioloop_now, io->sock, io->wakeup_time, next_event);
+
+        // If we were given a timeout in the future, or told to wait indefinitely, wait until the next event.
+        if (timeout_when == 0 || timeout_when > ioloop_now) {
+            timeout = next_event - ioloop_now;
+            // Don't choose a time so far in the future that it might overflow some math in the kernel.
+            if (timeout > IOLOOP_DAY * 100) {
+                timeout = IOLOOP_DAY * 100;
+            }
+#ifdef USE_SELECT
+            tv.tv_sec = timeout / 1000;
+            tv.tv_usec = (timeout % 1000) * 1000;
+#endif
+#ifdef USE_KQUEUE
+            ts.tv_sec = timeout / 1000;
+            ts.tv_nsec = (timeout % 1000) * 1000 * 1000;
+#endif
+        }
+        iop = &io->next;
+    }
+
+#ifdef USE_SELECT
+    for (io = ios; io; io = io->next) {
+        if (io->sock != -1 && (io->want_read || io->want_write)) {
+            if (io->sock >= nfds) {
+                nfds = io->sock + 1;
+            }
+            if (io->want_read) {
+                FD_SET(io->sock, &reads);
+            }
+            if (io->want_write) {
+                FD_SET(io->sock, &writes);
+            }
+        }
+    }
+#endif
+
+#ifdef USE_SELECT
+    INFO("waiting %ld %d seconds", tv.tv_sec, tv.tv_usec);
+    rv = select(nfds, &reads, &writes, &writes, &tv);
+    if (rv < 0) {
+        ERROR("select: %s", strerror(errno));
+        exit(1);
+    }
+    now = ioloop_timenow();
+    INFO("%qd.%03qd seconds passed waiting, got %d events", (now - ioloop_now) / 1000, (now - ioloop_now) % 1000, rv);
+    ioloop_now = now;
+    for (io = ios; io; io = io->next) {
+        if (io->sock != -1) {
+            if (FD_ISSET(io->sock, &reads)) {
+                io->read_callback(io);
+            } else if (FD_ISSET(io->sock, &writes)) {
+                io->write_callback(io);
+            }
+        }
+    }
+    nev += rv;
+#endif // USE_SELECT
+#ifdef USE_KQUEUE
+#define KEV_MAX 20
+    struct kevent evs[KEV_MAX];
+    int i, rv;
+    struct timespec ts;
+
+    INFO("waiting %qd/%qd seconds", ts.tv_sec, ts.tv_nsec);
+    do {
+        rv = kevent(kq, NULL, 0, evs, KEV_MAX, &ts);
+        now = ioloop_timenow();
+        INFO("%qd.%03qd seconds passed waiting, got %d events", (now - ioloop_now) / 1000, (now - ioloop_now) % 1000, rv);
+        ioloop_now = now;
+        ts.tv_sec = 0;
+        ts.tv_nsec = 0;
+        if (rv < 0) {
+            ERROR("kevent poll: %s", strerror(errno));
+            exit(1);
+        }
+        for (i = 0; i < nev; i++) {
+            io = evs[i].udata;
+            if (evs[i].filter == EVFILT_WRITE) {
+                io->write_callback(io);
+            } else if (evs[i].filter == EVFILT_READ) {
+                io->read_callback(io);
+            }
+        }
+        nev += rv;
+    } while (rv == KEV_MAX);
+#endif
+    return nev;
+}
+
+static void
+udp_read_callback(io_t *io)
+{
+    comm_t *connection = (comm_t *)io;
+    addr_t src;
+    int rv;
+    struct msghdr msg;
+    struct iovec bufp;
+    uint8_t msgbuf[DNS_MAX_UDP_PAYLOAD];
+    char cmsgbuf[128];
+    struct cmsghdr *cmh;
+    message_t *message;
+
+    bufp.iov_base = msgbuf;
+    bufp.iov_len = DNS_MAX_UDP_PAYLOAD;
+    msg.msg_iov = &bufp;
+    msg.msg_iovlen = 1;
+    msg.msg_name = &src;
+    msg.msg_namelen = sizeof src;
+    msg.msg_control = cmsgbuf;
+    msg.msg_controllen = sizeof cmsgbuf;
+    
+    rv = recvmsg(connection->io.sock, &msg, 0);
+    if (rv < 0) {
+        ERROR("udp_read_callback: %s", strerror(errno));
+        return;
+    }
+    message = message_allocate(rv);
+    if (!message) {
+        ERROR("udp_read_callback: out of memory");
+        return;
+    }
+    memcpy(&message->src, &src, sizeof src);
+    message->length = rv;
+    memcpy(&message->wire, msgbuf, rv);
+    
+    // For UDP, we use the interface index as part of the validation strategy, so go get
+    // the interface index.
+    for (cmh = CMSG_FIRSTHDR(&msg); cmh; cmh = CMSG_NXTHDR(&msg, cmh)) {
+        if (cmh->cmsg_level == IPPROTO_IPV6 && cmh->cmsg_type == IPV6_PKTINFO) {
+            struct in6_pktinfo pktinfo;    
+
+            memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo);
+            message->ifindex = pktinfo.ipi6_ifindex;
+        } else if (cmh->cmsg_level == IPPROTO_IP && cmh->cmsg_type == IP_PKTINFO) { 
+            struct in_pktinfo pktinfo;
+          
+            memcpy(&pktinfo, CMSG_DATA(cmh), sizeof pktinfo);
+            message->ifindex = pktinfo.ipi_ifindex;
+        }
+    }
+    connection->message = message;
+    connection->datagram_callback(connection);
+}
+
+static void
+tcp_read_callback(io_t *context)
+{
+    comm_t *connection = (comm_t *)context;
+    int rv;
+    if (connection->message_length_len < 2) {
+        rv = read(connection->io.sock, &connection->message_length_bytes[connection->message_length_len],
+                  2 - connection->message_length_len);
+        if (rv < 0) {
+        read_error:
+            ERROR("tcp_read_callback: %s", strerror(errno));
+            close(connection->io.sock);
+            connection->io.sock = -1;
+            // connection->io.finalize() will be called from the io loop.
+            return;
+        }
+        // If we read zero here, the remote endpoint has closed or shutdown the connection.  Either case is
+        // effectively the same--if we are sensitive to read events, that means that we are done processing
+        // the previous message.
+        if (rv == 0) {
+        eof:
+            ERROR("tcp_read_callback: remote end (%s) closed connection on %d", connection->name, connection->io.sock);
+            close(connection->io.sock);
+            connection->io.sock = -1;
+            // connection->io.finalize() will be called from the io loop.
+            return;
+        }
+        connection->message_length_len += rv;
+        if (connection->message_length_len == 2) {
+            connection->message_length = (((uint16_t)connection->message_length_bytes[0] << 8) |
+                                          ((uint16_t)connection->message_length_bytes[1]));
+        }
+        return;
+    }
+
+    // If we only just got the length, we need to allocate a message
+    if (connection->message == NULL) {
+        connection->message = message_allocate(connection->message_length);
+        if (!connection->message) {
+            ERROR("udp_read_callback: out of memory");
+            return;
+        }
+        connection->buf = (uint8_t *)&connection->message->wire;
+        connection->message->length = connection->message_length;
+        memset(&connection->message->src, 0, sizeof connection->message->src);
+    }
+
+    rv = read(connection->io.sock, &connection->buf[connection->message_cur],
+              connection->message_length - connection->message_cur);
+    if (rv < 0) {
+        goto read_error;
+    }
+    if (rv == 0) {
+        goto eof;
+    }
+
+    connection->message_cur += rv;
+    if (connection->message_cur == connection->message_length) {
+        connection->datagram_callback(connection);
+        // Caller is expected to consume the message, we are immediately ready for the next read.
+        connection->message_length = connection->message_length_len = 0;
+    }
+}
+
+static void
+tcp_send_response(comm_t *comm, message_t *responding_to, struct iovec *iov, int iov_len)
+{
+    struct msghdr mh;
+    struct iovec iovec[4];
+    char lenbuf[2];
+    ssize_t status;
+    size_t payload_length = 0;
+    int i;
+
+    // We don't anticipate ever needing more than four hunks, but if we get more, handle then?
+    if (iov_len > 3) {
+        ERROR("tcp_send_response: too many io buffers");
+        close(comm->io.sock);
+        comm->io.sock = -1;
+        return;
+    }
+
+    iovec[0].iov_base = &lenbuf[0];
+    iovec[0].iov_len = 2;
+    for (i = 0; i < iov_len; i++) {
+        iovec[i + 1] = iov[i];
+        payload_length += iov[i].iov_len;
+    }
+    lenbuf[0] = payload_length / 256;
+    lenbuf[1] = payload_length & 0xff;
+    payload_length += 2;
+
+    memset(&mh, 0, sizeof mh);
+    mh.msg_iov = &iovec[0];
+    mh.msg_iovlen = iov_len + 1;
+    mh.msg_name = 0;
+
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL 0
+#endif
+    status = sendmsg(comm->io.sock, &mh, MSG_NOSIGNAL);
+    if (status < 0 || status != payload_length) {
+        if (status < 0) {
+            ERROR("tcp_send_response: write failed: %s", strerror(errno));
+        } else {
+            ERROR("tcp_send_response: short write (%zd out of %zu bytes)", status, payload_length);
+        }
+        close(comm->io.sock);
+        comm->io.sock = -1;
+    }
+}
+
+static void
+udp_send_response(comm_t *comm, message_t *responding_to, struct iovec *iov, int iov_len)
+{
+    struct msghdr mh;
+    memset(&mh, 0, sizeof mh);
+    mh.msg_iov = iov;
+    mh.msg_iovlen = iov_len;
+    mh.msg_name = &responding_to->src;
+    if (responding_to->src.sa.sa_family == AF_INET) {
+        mh.msg_namelen = sizeof (struct sockaddr_in);
+    } else if (responding_to->src.sa.sa_family == AF_INET6) {
+        mh.msg_namelen = sizeof (struct sockaddr_in6);
+    } else {
+        ERROR("send_udp_response: unknown family %d", responding_to->src.sa.sa_family);
+        abort();
+    }
+    sendmsg(comm->io.sock, &mh, 0);
+}
+
+// When a communication is closed, scan the io event list to see if any other ios are referencing this one.
+void
+comm_finalize(io_t *io_in) {
+    io_t *io;
+
+    for (io = ios; io; io = io->next) {
+        if (io->cancel_on_close == io_in && io->cancel != NULL) {
+            io->cancel(io);
+        }
+    }
+}
+
+static void
+listen_callback(io_t *context)
+{
+    comm_t *listener = (comm_t *)context;
+    int rv;
+    addr_t addr;
+    socklen_t addr_len = sizeof addr;
+    comm_t *comm;
+    char addrbuf[INET6_ADDRSTRLEN + 7];
+    int addrlen;
+
+    rv = accept(listener->io.sock, &addr.sa, &addr_len);
+    if (rv < 0) {
+        ERROR("accept: %s", strerror(errno));
+        close(listener->io.sock);
+        listener->io.sock = -1;
+        return;
+    }
+    inet_ntop(addr.sa.sa_family, (addr.sa.sa_family == AF_INET
+                                  ? (void *)&addr.sin.sin_addr
+                                  : (void *)&addr.sin6.sin6_addr), addrbuf, sizeof addrbuf);
+    addrlen = strlen(addrbuf);
+    snprintf(&addrbuf[addrlen], (sizeof addrbuf) - addrlen, "%%%d",
+             (addr.sa.sa_family == AF_INET ? addr.sin.sin_port : addr.sin6.sin6_port));
+    comm = calloc(1, sizeof *comm);
+    comm->name = strdup(addrbuf);
+    comm->io.sock = rv;
+    comm->address = addr;
+    comm->datagram_callback = listener->datagram_callback;
+    comm->send_response = tcp_send_response;
+    comm->tcp_stream = true;
+
+    if (listener->connected) {
+        listener->connected(comm);
+    }
+    add_reader(&comm->io, tcp_read_callback, NULL);
+    comm->io.finalize = comm_finalize;
+
+#ifdef SO_NOSIGPIPE
+    int one = 1;
+    rv = setsockopt(comm->io.sock, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof one);
+    if (rv < 0) {
+        ERROR("SO_NOSIGPIPE failed: %s", strerror(errno));
+    }
+#endif
+}
+
+comm_t *
+setup_listener_socket(int family, int protocol, uint16_t port, const char *name,
+                      comm_callback_t datagram_callback,
+                      comm_callback_t connected, void *context)
+{
+    comm_t *listener;
+    socklen_t sl;
+    int rv;
+    int flag = 1;
+    
+    listener = calloc(1, sizeof *listener);
+    if (listener == NULL) {
+        return NULL;
+    }
+    listener->name = strdup(name);
+    if (!listener->name) {
+        free(listener);
+        return NULL;
+    }
+    listener->io.sock = socket(family, protocol == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, protocol);
+    if (listener->io.sock < 0) {
+        ERROR("Can't get socket: %s", strerror(errno));
+        comm_free(listener);
+        return NULL;
+    }
+    rv = setsockopt(listener->io.sock, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof flag);
+    if (rv < 0) {
+        ERROR("SO_REUSEPORT failed: %s", strerror(errno));
+        comm_free(listener);
+        return NULL;
+    }
+
+    if (family == AF_INET) {
+        sl = sizeof listener->address.sin;
+        listener->address.sin.sin_port = port ? port : htons(53);
+    } else {
+        sl = sizeof listener->address.sin6;
+        listener->address.sin6.sin6_port = port ? port : htons(53);
+    }
+    listener->address.sa.sa_family = family;
+    listener->address.sa.sa_len = sl;
+    if (bind(listener->io.sock, &listener->address.sa, sl) < 0) {
+        ERROR("Can't bind to 0#53/%s%s: %s",
+                protocol == IPPROTO_UDP ? "udp" : "tcp", family == AF_INET ? "v4" : "v6",
+                strerror(errno));
+    out:
+        close(listener->io.sock);
+        free(listener);
+        return NULL;
+    }
+
+    if (protocol == IPPROTO_TCP) {
+        if (listen(listener->io.sock, 5 /* xxx */) < 0) {
+            ERROR("Can't listen on 0#53/%s%s: %s.",
+                    protocol == IPPROTO_UDP ? "udp" : "tcp", family == AF_INET ? "v4" : "v6",
+                    strerror(errno));
+            goto out;
+        }                
+        add_reader(&listener->io, listen_callback, NULL);
+    } else {
+        rv = setsockopt(listener->io.sock, family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6,
+                        family == AF_INET ? IP_PKTINFO : IPV6_RECVPKTINFO, &flag, sizeof flag);
+        if (rv < 0) {
+            ERROR("Can't set %s: %s.", family == AF_INET ? "IP_PKTINFO" : "IPV6_RECVPKTINFO",
+                    strerror(errno));
+            goto out;
+        }
+        add_reader(&listener->io, udp_read_callback, NULL);
+        listener->send_response = udp_send_response;
+    }
+    listener->datagram_callback = datagram_callback;
+    listener->connected = connected;
+    return listener;
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/ioloop.h b/ServiceRegistration/ioloop.h
new file mode 100644 (file)
index 0000000..9d73d5f
--- /dev/null
@@ -0,0 +1,106 @@
+/* ioloop.c
+ *
+ * Copyright (c) 2018-2019 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.
+ *
+ * Definitions for simple dispatch implementation.
+ */
+
+#ifndef __IOLOOP_H
+#define __IOLOOP_H
+
+#ifndef __DSO_H
+typedef struct dso_state dso_state_t;
+#endif
+
+typedef union addr addr_t;
+union addr {
+    struct sockaddr sa;
+    struct sockaddr_in sin;
+    struct sockaddr_in6 sin6;
+};
+
+typedef struct message message_t;
+struct message {
+    addr_t src;
+    int ifindex;
+    size_t length;
+    dns_wire_t wire;
+};
+
+typedef struct dso_transport comm_t;
+typedef struct io io_t;
+typedef void (*io_callback_t)(io_t *NONNULL io);
+typedef void (*comm_callback_t)(comm_t *NONNULL comm);
+typedef void (*send_response_t)(comm_t *NONNULL comm, message_t *NONNULL responding_to, struct iovec *NONNULL iov, int count);
+
+#define IOLOOP_SECOND  1000LL
+#define IOLOOP_MINUTE  60 * IOLOOP_SECOND
+#define IOLOOP_HOUR            60 * IOLOOP_MINUTE
+#define IOLOOP_DAY             24 * IOLOOP_HOUR
+
+struct io {
+    io_t *NULLABLE next;
+    io_callback_t NULLABLE read_callback;
+    io_callback_t NULLABLE write_callback;
+    io_callback_t NULLABLE finalize;
+    io_callback_t NULLABLE wakeup;
+    io_callback_t NULLABLE cancel;
+    int sock;
+    int64_t wakeup_time;
+    io_t *NULLABLE cancel_on_close;
+    bool want_read : 1;
+    bool want_write : 1;
+};
+
+struct dso_transport {
+    io_t io;
+    char *NONNULL name;
+    void *NULLABLE context;
+    comm_callback_t NULLABLE datagram_callback;
+    comm_callback_t NULLABLE close_callback;
+    send_response_t NULLABLE send_response;
+    comm_callback_t NULLABLE connected;
+    message_t *NULLABLE message;
+    uint8_t *NULLABLE buf;
+    dso_state_t *NULLABLE dso;
+    addr_t address;
+    size_t message_length_len;
+    size_t message_length, message_cur;
+    uint8_t message_length_bytes[2];
+    bool tcp_stream: 1;
+};
+
+extern int64_t ioloop_now;
+int getipaddr(addr_t *NONNULL addr, const char *NONNULL p);
+int64_t ioloop_timenow(void);
+message_t *NULLABLE message_allocate(size_t message_size);
+void message_free(message_t *NONNULL message);
+void comm_free(comm_t *NONNULL comm);
+void ioloop_close(io_t *NONNULL io);
+void add_reader(io_t *NONNULL io, io_callback_t NONNULL callback, io_callback_t NULLABLE finalize);
+bool ioloop_init(void);
+int ioloop_events(int64_t timeout_when);
+comm_t *NULLABLE setup_listener_socket(int family, int protocol, uint16_t port, const char *NONNULL name,
+                                       comm_callback_t NONNULL datagram_callback,
+                                       comm_callback_t NULLABLE connected, void *NULLABLE context);
+#endif
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/keydump.c b/ServiceRegistration/keydump.c
new file mode 100644 (file)
index 0000000..eb39d6e
--- /dev/null
@@ -0,0 +1,53 @@
+/* keydump.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Dump the contents of a key file saved by e.g. srp-simple as a DNS key.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+int
+main(int argc, char **argv)
+{
+    const char *keyfile_name = "srp-simple.key";
+    srp_key_t *key;
+
+    key = srp_load_keypair(keyfile_name);
+    if (key == NULL) {
+        if (key == NULL) {
+            printf("Unable to load key from %s.", keyfile_name);
+            exit(1);
+        }
+    }
+
+    srp_print_key(key);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/sign-mbedtls.c b/ServiceRegistration/sign-mbedtls.c
new file mode 100644 (file)
index 0000000..2455d99
--- /dev/null
@@ -0,0 +1,340 @@
+/* sign.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS SIG(0) signature generation for DNSSD SRP using mbedtls.
+ *
+ * Functions required for loading, saving, and generating public/private keypairs, extracting the public key
+ * into KEY RR data, and computing signatures.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/random.h>
+#include <sys/errno.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#define SRP_CRYPTO_MBEDTLS_INTERNAL
+#include "srp-crypto.h"
+
+// For debugging
+#ifdef DEBUG_SHA256
+int
+srp_mbedtls_sha256_update_ret(mbedtls_sha256_context *sha, uint8_t *data, size_t len)
+{
+    int i;
+    fprintf(stderr, "data %lu: ", (unsigned long)len);
+    for (i = 0; i < len; i++) {
+        fprintf(stderr, "%02x", data[i]);
+    }
+    fputs("\n", stderr);
+    return mbedtls_sha256_update_ret(sha, data, len);
+}
+
+int
+srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context *sha, uint8_t *hash)
+{
+    int i;
+    int status = mbedtls_sha256_finish_ret(sha, hash);
+    fprintf(stderr, "hash:     ");
+    for (i = 0; i < ECDSA_SHA256_HASH_SIZE; i++) {
+        fprintf(stderr, "%02x", hash[i]);
+    }
+    fputs("\n", stderr);
+    return status;
+}
+#endif
+
+// Key is stored in an opaque data structure, for mbedtls this is an mbedtls_pk_context.
+// Function to read a public key from a KEY record
+// Function to validate a signature given some data and a public key (not required on client)
+
+// Function to free a key
+void
+srp_keypair_free(srp_key_t *key)
+{
+    mbedtls_pk_free(&key->key);
+    mbedtls_entropy_free(&key->entropy);
+    mbedtls_ctr_drbg_free(&key->ctr);
+    free(key);
+}
+
+// Needed to see the RNG with good entropy data.
+static int
+get_entropy(void *data, unsigned char *output, size_t len, size_t *outlen)
+{
+    int result = getentropy(output, len);
+    (void)data;
+
+    if (result != 0) {
+        ERROR("getentropy returned %s", strerror(errno));
+        return MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
+    }
+    *outlen = len;
+    return 0;
+}
+
+static srp_key_t *
+srp_key_setup(void)
+{
+    int status;
+    srp_key_t *key = calloc(sizeof *key, 1);
+    char errbuf[64];
+
+    if (key == NULL) {
+        return key;
+    }
+    
+    mbedtls_pk_init(&key->key);
+    mbedtls_entropy_init(&key->entropy);
+    if ((status = mbedtls_entropy_add_source(&key->entropy, get_entropy,
+                                             NULL, 1, MBEDTLS_ENTROPY_SOURCE_STRONG)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_entropy_add_source failed: %s", errbuf);
+    } else if ((status = mbedtls_ctr_drbg_seed(&key->ctr, mbedtls_entropy_func, &key->entropy, NULL, 0)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_ctr_drbg_seed failed: %s", errbuf);
+    } else {
+        return key;
+    }
+    mbedtls_pk_free(&key->key);
+    mbedtls_entropy_free(&key->entropy);
+    free(key);
+    return NULL;
+}
+
+// Function to read a keypair from a file
+srp_key_t *
+srp_load_keypair(const char *file)
+{
+    int fd = open(file, O_RDONLY);
+    unsigned char buf[256];
+    ssize_t rv;
+    srp_key_t *key;
+    int status;
+    char errbuf[64];
+
+    if (fd < 0) {
+        if (errno != ENOENT) {
+            ERROR("Unable to open srp.key: %s", strerror(errno));
+            return NULL;
+        }
+        return NULL;
+    }        
+
+    // The key is of limited size, so there's no reason to get fancy.
+    rv = read(fd, buf, sizeof buf);
+    close(fd);
+    if (rv == sizeof buf) {
+        ERROR("key file is unreasonably large.");
+        return NULL;
+    }
+
+    key = srp_key_setup();
+    if (key == NULL) {
+        return NULL;
+    }
+
+    if ((status = mbedtls_pk_parse_key(&key->key, buf, rv, NULL, 0)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_pk_parse_key failed: %s", errbuf);
+    } else if (!mbedtls_pk_can_do(&key->key, MBEDTLS_PK_ECDSA)) {
+        ERROR("%s does not contain a usable ECDSA key.", file);
+    } else {
+        return key;
+    }
+    srp_keypair_free(key);
+    return NULL;
+}
+
+// Function to generate a key
+srp_key_t *
+srp_generate_key(void)
+{
+    int status;
+    char errbuf[64];
+    srp_key_t *key = srp_key_setup();
+    const mbedtls_pk_info_t *key_type = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
+
+    if (key == NULL || key_type == NULL) {
+        return NULL;
+    }
+    
+    if ((status = mbedtls_pk_setup(&key->key, key_type)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_pk_setup failed: %s", errbuf);
+    } else if ((status = mbedtls_ecdsa_genkey(mbedtls_pk_ec(key->key), MBEDTLS_ECP_DP_SECP256R1,
+                                              mbedtls_ctr_drbg_random, &key->ctr)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_ecdsa_genkey failed: %s", errbuf);
+    } else {
+        return key;
+    }
+    srp_keypair_free(key);
+    return NULL;
+}
+
+// Function to write a keypair to a file
+int
+srp_write_key_to_file(const char *file, srp_key_t *key)
+{
+    int fd;
+    unsigned char buf[256];
+    ssize_t rv;
+    int len;
+    char errbuf[64];
+
+    len = mbedtls_pk_write_key_der(&key->key, buf, sizeof buf);
+    if (len <= 0) {
+        mbedtls_strerror(len, errbuf, sizeof errbuf);
+        ERROR("mbedtls_pk_write_key_der failed: %s", errbuf);
+        return 0;
+    }
+
+#ifndef O_DIRECT
+#define O_DIRECT 0
+#endif
+    fd = open(file, O_CREAT | O_EXCL | O_WRONLY | O_DIRECT, 0700);
+    if (fd < 0) {
+        ERROR("Unable to create srp.key: %s", strerror(errno));
+        return 0;
+    }        
+
+    rv = write(fd, &buf[sizeof buf - len], len);
+    close(fd);
+    if (rv != len) {
+        ERROR("key file write truncated.");
+        unlink(file);
+        return 0;
+    }
+
+    return 1;
+}
+
+// Function to get the length of the public key
+size_t
+srp_pubkey_length(srp_key_t *key)
+{
+    return ECDSA_KEY_SIZE;
+}
+
+int
+srp_key_algorithm(srp_key_t *key)
+{
+    return dnssec_keytype_ecdsa;
+}
+
+size_t
+srp_signature_length(srp_key_t *key)
+{
+    return ECDSA_KEY_SIZE;
+}
+
+// Function to copy out the public key as binary data
+int
+srp_pubkey_copy(uint8_t *buf, size_t max, srp_key_t *key)
+{
+    mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
+    char errbuf[64];
+    int status;
+
+    if (max < ECDSA_KEY_SIZE) {
+        return 0;
+    }
+
+    // Currently ECP only.
+    if ((status = mbedtls_mpi_write_binary(&ecp->Q.X, buf, ECDSA_KEY_PART_SIZE)) != 0 ||
+        (status = mbedtls_mpi_write_binary(&ecp->Q.Y, buf + ECDSA_KEY_PART_SIZE, ECDSA_KEY_PART_SIZE)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_mpi_write_binary: %s", errbuf);
+        return 0;
+    }
+
+#ifdef MBEDTLS_PUBKEY_DUMP
+    int i;
+    fprintf(stderr, "pubkey %d: ", ECDSA_KEY_SIZE);
+    for (i = 0; i < ECDSA_KEY_SIZE; i++) {
+        fprintf(stderr, "%02x", buf[i]);
+    }
+    putc('\n', stderr);
+#endif
+
+    return ECDSA_KEY_SIZE;
+}
+
+// Function to generate a signature given some data and a private key
+int
+srp_sign(uint8_t *output, size_t max, uint8_t *message, size_t msglen, uint8_t *rr, size_t rdlen, srp_key_t *key)
+{
+    int status;
+    unsigned char hash[ECDSA_SHA256_HASH_SIZE];
+    char errbuf[64];
+    mbedtls_sha256_context sha;
+    mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
+    mbedtls_mpi r, s;
+
+    if (max < ECDSA_SHA256_SIG_SIZE) {
+        ERROR("srp_sign: not enough space in output buffer (%lu) for signature (%d).",
+              (unsigned long)max, ECDSA_SHA256_SIG_SIZE);
+        return 0;
+    }
+
+    mbedtls_sha256_init(&sha);
+    memset(hash, 0, sizeof hash);
+    mbedtls_mpi_init(&r);
+    mbedtls_mpi_init(&s);
+
+    // Calculate the hash across first the SIG RR (minus the signature) and then the message
+    // up to but not including the SIG RR.
+    if ((status = mbedtls_sha256_starts_ret(&sha, 0)) != 0 ||
+        (status = srp_mbedtls_sha256_update_ret(&sha, rr, rdlen) != 0) ||
+        (status = srp_mbedtls_sha256_update_ret(&sha, message, msglen)) != 0 ||
+        (status = srp_mbedtls_sha256_finish_ret(&sha, hash)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_sha_256 hash failed: %s", errbuf);
+        return 0;
+    }
+
+    status = mbedtls_ecdsa_sign(&ecp->grp, &r, &s, &ecp->d, hash, sizeof hash,
+                                mbedtls_ctr_drbg_random, &key->ctr);
+    if (status != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_ecdsa_sign failed: %s", errbuf);
+        return 0;
+    }
+
+    if ((status = mbedtls_mpi_write_binary(&r, output, ECDSA_SHA256_SIG_PART_SIZE)) != 0 ||
+        (status = mbedtls_mpi_write_binary(&s, output + ECDSA_SHA256_SIG_PART_SIZE,
+                                           ECDSA_SHA256_SIG_PART_SIZE)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_ecdsa_sign failed: %s", errbuf);
+        return 0;
+    }
+    return 1;
+}
+    
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/srp-crypto.h b/ServiceRegistration/srp-crypto.h
new file mode 100644 (file)
index 0000000..0065dd9
--- /dev/null
@@ -0,0 +1,94 @@
+/* srp-key.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS SIG(0) signature generation for DNSSD SRP using mbedtls.
+ *
+ * Functions required for loading, saving, and generating public/private keypairs, extracting the public key
+ * into KEY RR data, and computing signatures.
+ */
+
+#ifndef __SRP_CRYPTO_H
+#define __SRP_CRYPTO_H
+// Anonymous key structure, depends on the target.
+typedef struct srp_key srp_key_t;
+
+#ifdef SRP_CRYPTO_MBEDTLS_INTERNAL
+#include <mbedtls/error.h>
+#include <mbedtls/pk.h>
+#include <mbedtls/ecp.h>
+#include <mbedtls/ecdsa.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/sha256.h>
+#include <mbedtls/base64.h>
+
+// The SRP key includes both the ecdsa key and the pseudo-random number generator context, so that we can
+// use the PRNG for signing as well as generating keys.   The PRNG is seeded with a high-entropy data source.
+// This structure assumes that we are just using this one key; if we want to support multiple keys then
+// the entropy source and PRNG should be shared by all keys (of course, that's not thread-safe, so...)
+struct srp_key {
+    mbedtls_pk_context key;
+    mbedtls_entropy_context entropy;
+    mbedtls_ctr_drbg_context ctr;
+};    
+
+#ifdef DEBUG_SHA256
+int srp_mbedtls_sha256_update_ret(mbedtls_sha256_context *NONNULL sha, uint8_t *NONNULL message, size_t msglen);
+int srp_mbedtls_sha256_finish_ret(mbedtls_sha256_context *NONNULL sha, uint8_t *NONNULL hash);
+#else
+#define srp_mbedtls_sha256_update_ret mbedtls_sha256_update_ret
+#define srp_mbedtls_sha256_finish_ret mbedtls_sha256_finish_ret
+#endif // DEBUG_SHA256
+#endif // SRP_CRYPTO_MBEDTLS_INTERNAL
+
+#define ECDSA_KEY_SIZE 64
+#define ECDSA_KEY_PART_SIZE 32
+#define ECDSA_SHA256_HASH_SIZE 32
+#define ECDSA_SHA256_SIG_SIZE 64
+#define ECDSA_SHA256_SIG_PART_SIZE 32
+
+#define SIG_HEADERLEN 11
+#define SIG_STATIC_RDLEN 18
+
+
+#define dnssec_keytype_ecdsa  13
+
+// sign_*.c:
+void srp_keypair_free(srp_key_t *NONNULL key);
+srp_key_t *NULLABLE srp_load_keypair(const char *NONNULL file);
+srp_key_t *NULLABLE srp_generate_key(void);
+int srp_write_key_to_file(const char *NONNULL file, srp_key_t *NONNULL key);
+int srp_key_algorithm(srp_key_t *NONNULL key);
+size_t srp_pubkey_length(srp_key_t *NONNULL key);
+size_t srp_signature_length(srp_key_t *NONNULL key);
+int srp_pubkey_copy(uint8_t *NONNULL buf, size_t max, srp_key_t *NONNULL key);
+int srp_sign(uint8_t *NONNULL output, size_t max,
+            uint8_t *NONNULL message, size_t msglen, uint8_t *NONNULL rdata, size_t rdlen, srp_key_t *NONNULL key);
+
+// verify_*.c:
+bool srp_sig0_verify(dns_wire_t *NONNULL message, dns_rr_t *NONNULL key, dns_rr_t *NONNULL signature);
+void srp_print_key(srp_key_t *NONNULL key);
+
+#endif // __SRP_CRYPTO_H
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/srp-gw.c b/ServiceRegistration/srp-gw.c
new file mode 100644 (file)
index 0000000..add3086
--- /dev/null
@@ -0,0 +1,642 @@
+/* srp-gw.c
+ *
+ * Copyright (c) 2018 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 is a DNSSD Service Registration Protocol gateway.   The purpose of this is to make it possible
+ * for SRP clients to update DNS servers that don't support SRP.
+ *
+ * The way it works is that this gateway listens on port ANY:53 and forwards either to another port on
+ * the same host (not recommended) or to any port (usually 53) on a different host.   Requests are accepted
+ * over both TCP and UDP in principle, but UDP requests should be from constrained nodes, and rely on
+ * network topology for authentication.
+ *
+ * Note that this is not a full DNS proxy, so you can't just put it in front of a DNS server.
+ */
+
+// Get DNS server IP address
+// Get list of permitted source subnets for TCP updates
+// Get list of permitted source subnet/interface tuples for UDP updates
+// Set up UDP listener
+// Set up TCP listener (no TCP Fast Open)
+// Event loop
+// Transaction processing:
+//   1. If UDP, validate that it's from a subnet that is valid for the interface on which it was received.
+//   2. If TCP, validate that it's from a permitted subnet
+//   3. Check that the message is a valid SRP update according to the rules
+//   4. Check the signature
+//   5. Do a DNS Update with prerequisites to prevent overwriting a host record with the same owner name but
+//      a different key.
+//   6. Send back the response
+
+#define __APPLE_USE_RFC_3542
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/event.h>
+#include <fcntl.h>
+#include <sys/time.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+#include "ioloop.h"
+#include "dnssd-proxy.h"
+
+#pragma mark structures
+
+typedef struct subnet subnet_t;
+struct subnet {
+    subnet_t *NULLABLE next;
+    uint8_t preflen;
+    uint8_t family;
+    char bytes[8];
+};
+
+typedef struct udp_validator udp_validator_t;
+struct udp_validator {
+    udp_validator_t *NULLABLE next;
+    char *NONNULL ifname;
+    int ifindex;
+    subnet_t *subnets;
+};
+
+static int
+usage(const char *progname)
+{
+    ERROR("usage: %s -s <addr> <port> -t <subnet> ... -u <ifname> <subnet> ...", progname);
+    ERROR("  -s can only appear once.");
+    ERROR("  -t can only appear once, and is followed by one or more subnets.");
+    ERROR("  -u can appear more than once, is followed by one interface name, and");
+    ERROR("     one or more subnets.");
+    ERROR("  <addr> is an IPv4 address or IPv6 address.");
+    ERROR("  <port> is a UDP port number.");
+    ERROR("  <subnet> is an IP address followed by a slash followed by the prefix width.");
+    ERROR("  <ifname> is the printable name of the interface.");
+    ERROR("ex: srp-gw -s 2001:DB8::1 53 -t 2001:DB8:1300::/48 -u en0 2001:DB8:1300:1100::/56");
+    return 1;
+}
+
+typedef struct delete delete_t;
+struct delete {
+    delete_t *next;
+    dns_name_t *name;
+};
+
+typedef struct dns_host_description dns_host_description_t;
+struct dns_host_description {
+    dns_name_t *name;
+    dns_rr_t *a, *aaaa, *key;
+    delete_t *delete;
+    int num_instances;
+};
+
+typedef struct service_instance service_instance_t;
+struct service_instance {
+    service_instance_t *next;
+    dns_host_description_t *host_description;
+    dns_name_t *name;
+    delete_t *delete;
+    int num_instances;
+    dns_rr_t *srv, *txt;
+};
+
+typedef struct service service_t;
+struct service {
+    service_t *next;
+    service_instance_t *instance;
+    dns_name_t *name;
+    dns_rr_t *rr;
+};
+
+bool
+srp_relay(comm_t *comm, dns_message_t *message)
+{
+    dns_name_t *update_zone;
+    bool updating_services_dot_arpa = false;
+    int i;
+    dns_host_description_t *host_description = NULL;
+    delete_t *deletes = NULL, *dp, **dpp = &deletes;
+    service_instance_t *service_instances = NULL, *sip, **sipp = &service_instances;
+    service_t *services = NULL, *sp, **spp = &services;
+    dns_rr_t *signature;
+    char namebuf[DNS_MAX_NAME_SIZE + 1], namebuf1[DNS_MAX_NAME_SIZE + 1];
+    bool ret = false;
+    struct timeval now;
+
+    // Update requires a single SOA record as the question
+    if (message->qdcount != 1) {
+        ERROR("srp_relay: update received with qdcount > 1");
+        return false;
+    }
+
+    // Update should contain zero answers.
+    if (message->ancount != 0) {
+        ERROR("srp_relay: update received with ancount > 0");
+        return false;
+    }
+
+    if (message->questions[0].type != dns_rrtype_soa) {
+        ERROR("srp_relay: update received with rrtype %d instead of SOA in question section.",
+              message->questions[0].type);
+        return false;
+    }
+    update_zone = message->questions[0].name;
+
+    // What zone are we updating?
+    if (dns_names_equal_text(update_zone, "services.arpa")) {
+        updating_services_dot_arpa = true;
+    }
+
+    // Scan over the authority RRs; do the delete consistency check.  We can't do other consistency checks
+    // because we can't assume a particular order to the records other than that deletes have to come before
+    // adds.
+    for (i = 0; i < message->nscount; i++) {
+        dns_rr_t *rr = &message->authority[i];
+
+        // If this is a delete for all the RRs on a name, record it in the list of deletes.
+        if (rr->type == dns_rrtype_any && rr->qclass == dns_qclass_any && rr->ttl == 0) {
+            for (dp = deletes; dp; dp = dp->next) {
+                if (dns_names_equal(dp->name, rr->name)) {
+                    ERROR("srp_relay: two deletes for the same name: %s",
+                          dns_name_print(rr->name, namebuf, sizeof namebuf));
+                    goto out;
+                }
+            }
+            dp = calloc(sizeof *dp, 1);
+            if (!dp) {
+                ERROR("srp_relay: no memory.");
+                goto out;
+            }
+            dp->name = rr->name;
+            *dpp = dp;
+            dpp = &dp->next;
+        }
+
+        // Otherwise if it's an A or AAAA record, it's part of a hostname entry.
+        else if (rr->type == dns_rrtype_a || rr->type == dns_rrtype_aaaa || rr->type == dns_rrtype_key) {
+            // Allocate the hostname record
+            if (!host_description) {
+                host_description = calloc(sizeof *host_description, 1);
+                if (!host_description) {
+                    ERROR("srp_relay: no memory");
+                    goto out;
+                }
+            }
+
+            // Make sure it's preceded by a deletion of all the RRs on the name.
+            if (!host_description->delete) {
+                for (dp = deletes; dp; dp = dp->next) {
+                    if (dns_names_equal(dp->name, rr->name)) {
+                        break;
+                    }
+                }
+                if (dp == NULL) {
+                    ERROR("srp_relay: ADD for hostname %s without a preceding delete.",
+                          dns_name_print(rr->name, namebuf, sizeof namebuf));
+                    goto out;
+                }
+                host_description->delete = dp;
+                host_description->name = dp->name;
+            }
+                          
+            if (rr->type == dns_rrtype_a) {
+                if (host_description->a != NULL) {
+                    ERROR("srp_relay: more than one A rrset received for name: %s",
+                          dns_name_print(rr->name, namebuf, sizeof namebuf));
+                    goto out;
+                }
+                host_description->a = rr;
+            } else if (rr->type == dns_rrtype_aaaa) {
+                if (host_description->aaaa != NULL) {
+                    ERROR("srp_relay: more than one AAAA rrset received for name: %s",
+                          dns_name_print(rr->name, namebuf, sizeof namebuf));
+                    goto out;
+                }
+                host_description->aaaa = rr;
+            } else if (rr->type == dns_rrtype_key) {
+                if (host_description->key != NULL) {
+                    ERROR("srp_relay: more than one KEY rrset received for name: %s",
+                          dns_name_print(rr->name, namebuf, sizeof namebuf));
+                    goto out;
+                }
+                host_description->key =  rr;
+            }
+        }
+
+        // Otherwise if it's an SRV entry, that should be a service instance name.
+        else if (rr->type == dns_rrtype_srv || rr->type == dns_rrtype_txt) {
+            // Should be a delete that precedes this service instance.
+            for (dp = deletes; dp; dp = dp->next) {
+                if (dns_names_equal(dp->name, rr->name)) {
+                    break;
+                }
+            }
+            if (dp == NULL) {
+                ERROR("srp_relay: ADD for service instance not preceded by delete: %s",
+                      dns_name_print(rr->name, namebuf, sizeof namebuf));
+                goto out;
+            }
+            for (sip = service_instances; sip; sip = sip->next) {
+                if (dns_names_equal(sip->name, rr->name)) {
+                    break;
+                }
+            }
+            if (!sip) {
+                sip = calloc(sizeof *sip, 1);
+                if (sip == NULL) {
+                    ERROR("srp_relay: no memory");
+                    goto out;
+                }
+                sip->delete = dp;
+                sip->name = dp->name;
+                *sipp = sip;
+                sipp = &sip->next;
+            }
+            if (rr->type == dns_rrtype_srv) {
+                if (sip->srv != NULL) {
+                    ERROR("srp_relay: more than one SRV rr received for service instance: %s",
+                          dns_name_print(rr->name, namebuf, sizeof namebuf));
+                    goto out;
+                }
+                sip->srv = rr;
+            } else if (rr->type == dns_rrtype_txt) {
+                if (sip->txt != NULL) {
+                    ERROR("srp_relay: more than one SRV rr received for service instance: %s",
+                          dns_name_print(rr->name, namebuf, sizeof namebuf));
+                }
+                sip->txt = rr;
+            }
+        }
+
+        // Otherwise if it's a PTR entry, that should be a service name
+        else if (rr->type == dns_rrtype_ptr) {
+            sp = calloc(sizeof *sp, 1);
+            if (sp == NULL) {
+                ERROR("srp_relay: no memory");
+                goto out;
+            }
+            sp->rr = rr;
+            *spp = sp;
+            spp = &sp->next;
+        }            
+
+        // Otherwise it's not a valid update
+        else {
+            ERROR("srp_relay: unexpected rrtype %d on %s in update.", rr->type,
+                      dns_name_print(rr->name, namebuf, sizeof namebuf));
+            goto out;
+        }
+    }
+
+    // Now that we've scanned the whole update, do the consistency checks for updates that might
+    // not have come in order.
+    
+    // First, make sure there's a host description.
+    if (host_description == NULL) {
+        ERROR("srp_relay: SRP update does not include a host description.");
+        goto out;
+    }
+
+    // Make sure that each service add references a service instance that's in the same update.
+    for (sp = services; sp; sp = sp->next) {
+        for (sip = service_instances; sip; sip = sip->next) {
+            if (dns_names_equal(sip->name, sp->rr->data.ptr.name)) {
+                // Note that we have already verified that there is only one service instance
+                // with this name, so this could only ever happen once in this loop even without
+                // the break statement.
+                sp->instance = sip;
+                sip->num_instances++;
+                break;
+            }
+        }
+        // If this service doesn't point to a service instance that's in the update, then the
+        // update fails validation.
+        if (sip == NULL) {
+            ERROR("srp_relay: service %s points to an instance that's not included: %s",
+                  dns_name_print(sp->name, namebuf, sizeof namebuf),
+                  dns_name_print(sip->name, namebuf1, sizeof namebuf1));
+            goto out;
+        }
+    }
+
+    for (sip = service_instances; sip; sip = sip->next) {
+        // For each service instance, make sure that at least one service references it
+        if (sip->num_instances == 0) {
+            ERROR("srp_relay: service instance update for %s is not referenced by a service update.",
+                  dns_name_print(sip->name, namebuf, sizeof namebuf));
+            goto out;
+        }
+
+        // For each service instance, make sure that it references the host description
+        if (dns_names_equal(host_description->name, sip->srv->data.srv.name)) {
+            sip->host_description = host_description;
+            host_description->num_instances++;
+        }
+    }
+
+    // Make sure that at least one service instance references the host description
+    if (host_description->num_instances == 0) {
+        ERROR("srp_relay: host description %s is not referenced by any service instances.",
+              dns_name_print(host_description->name, namebuf, sizeof namebuf));
+        goto out;
+    }
+
+    // Make sure the host description has at least one address record.
+    if (host_description->a == NULL && host_description->aaaa == NULL) {
+        ERROR("srp_relay: host description %s doesn't contain any IP addresses.",
+              dns_name_print(host_description->name, namebuf, sizeof namebuf));
+        goto out;
+    }
+    // And make sure it has a key record
+    if (host_description->key == NULL) {
+        ERROR("srp_relay: host description %s doesn't contain a key.",
+              dns_name_print(host_description->name, namebuf, sizeof namebuf));
+        goto out;
+    }
+
+    // The signature should be the last thing in the additional section.   Even if the signature
+    // is valid, if it's not at the end we reject it.   Note that we are just checking for SIG(0)
+    // so if we don't find what we're looking for, we forward it to the DNS auth server which
+    // will either accept or reject it.
+    if (message->arcount < 1) {
+        ERROR("srp_relay: signature not present");
+        goto out;
+    }
+    signature = &message->additional[message->arcount -1];
+    if (signature->type != dns_rrtype_sig) {
+        ERROR("srp_relay: signature is not at the end or is not present");
+        goto out;
+    }
+
+    // Make sure that the signer name is the hostname.   If it's not, it could be a legitimate
+    // update with a different key, but it's not an SRP update, so we pass it on.
+    if (!dns_names_equal(signature->data.sig.signer, host_description->name)) {
+        ERROR("srp_relay: signer %s doesn't match host %s", 
+              dns_name_print(signature->data.sig.signer, namebuf, sizeof namebuf),
+              dns_name_print(host_description->name, namebuf1, sizeof namebuf1));
+        goto out;
+    }
+    
+    // Make sure we're in the time limit for the signature.   Zeroes for the inception and expiry times
+    // mean the host that send this doesn't have a working clock.   One being zero and the other not isn't
+    // valid unless it's 1970.
+    if (signature->data.sig.inception != 0 || signature->data.sig.expiry != 0) {
+        gettimeofday(&now, NULL);
+        // The sender does the bracketing, so we can just do a simple comparison.
+        if (now.tv_sec > signature->data.sig.expiry || now.tv_sec < signature->data.sig.inception) {
+            ERROR("signature is not timely: %lu < %lu < %lu does not hold",
+                  (unsigned long)signature->data.sig.inception, (unsigned long)now.tv_sec,
+                  (unsigned long)signature->data.sig.expiry);
+            goto badsig;
+        }
+    }
+
+    // Now that we have the key, we can validate the signature.   If the signature doesn't validate,
+    // there is no need to pass the message on.
+    if (!srp_sig0_verify(message->wire, host_description->key, signature)) {
+        ERROR("signature is not valid");
+        goto badsig;
+    }
+
+badsig:
+    // True means we consumed it, not that it was valid.
+    ret = true;
+
+out:
+    // free everything we allocated but (it turns out) aren't going to use
+    for (dp = deletes; dp; ) {
+        delete_t *next = dp->next;
+        free(dp);
+        dp = next;
+    }
+    for (sip = service_instances; sip; ) {
+        service_instance_t *next = sip->next;
+        free(sip);
+        sip = next;
+    }
+    for (sp = services; sp; ) {
+        service_t *next = sp->next;
+        free(sp);
+        sp = next;
+    }
+    if (host_description != NULL) {
+        free(host_description);
+    }
+    return ret;
+}
+
+void
+dns_evaluate(comm_t *comm)
+{
+    dns_message_t *message;
+
+    // Drop incoming responses--we're a server, so we only accept queries.
+    if (dns_qr_get(&comm->message->wire) == dns_qr_response) {
+        return;
+    }
+
+    // Forward incoming messages that are queries but not updates.
+    // XXX do this later--for now we operate only as a translator, not a proxy.
+    if (dns_opcode_get(&comm->message->wire) != dns_opcode_update) {
+        return;
+    }
+    
+    // Parse the UPDATE message.
+    if (!dns_wire_parse(&message, &comm->message->wire, comm->message->length)) {
+        ERROR("dns_wire_parse failed.");
+        return;
+    }
+    
+    // We need the wire message to validate the signature...
+    message->wire = &comm->message->wire;
+    if (!srp_relay(comm, message)) {
+        // The message wasn't invalid, but wasn't an SRP message.
+        // dns_forward(comm)
+    }
+    // But we don't save it.
+    message->wire = NULL;
+
+    //dns_message_free(message);
+}
+
+void dns_input(comm_t *comm)
+{
+    dns_evaluate(comm);
+    message_free(comm->message);
+    comm->message = NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+    int i;
+    subnet_t *tcp_validators = NULL;
+    udp_validator_t *udp_validators = NULL;
+    udp_validator_t *NULLABLE *NONNULL up = &udp_validators;
+    subnet_t *NULLABLE *NONNULL nt = &tcp_validators;
+    subnet_t *NULLABLE *NONNULL sp;
+    addr_t server, pref;
+    uint16_t port;
+    socklen_t len, prefalen;
+    char *s, *p;
+    int width;
+    uint16_t listen_port;
+
+    listen_port = htons(53);
+
+    // Read the configuration from the command line.
+    for (i = 1; i < argc; i++) {
+        if (!strcmp(argv[i], "-s")) {
+            if (i++ == argc) {
+                ERROR("-s is missing server IP address.");
+                return usage(argv[0]);
+            }
+            len = getipaddr(&server, argv[i]);
+            if (!len) {
+                ERROR("Invalid IP address: %s.", argv[i]);
+                return usage(argv[0]);
+            }
+            server.sa.sa_len = len;
+            if (i++ == argc) {
+                ERROR("-s is missing server port.");
+                return usage(argv[0]);
+            }
+            port = strtol(argv[i], &s, 10);
+            if (s == argv[i] || s[0] != '\0') {
+                ERROR("Invalid port number: %s", argv[i]);
+                return usage(argv[0]);
+            }
+            if (server.sa.sa_family == AF_INET) {
+                server.sin.sin_port = htons(port);
+            } else {
+                server.sin6.sin6_port = htons(port);
+            }
+            i += 2;
+        } else if (!strcmp(argv[i], "-t") || !strcmp(argv[i], "-u")) {
+            if (!strcmp(argv[i], "-u")) {
+                if (i++ == argc) {
+                    ERROR("-u is missing interface name.");
+                    return usage(argv[0]);
+                }
+                *up = calloc(1, sizeof **up);
+                if (*up == NULL) {
+                    ERROR("udp_validators: out of memory.");
+                    return usage(argv[0]);
+                }
+                (*up)->ifname = strdup(argv[i]);
+                if ((*up)->ifname == NULL) {
+                    ERROR("udp validators: ifname: out of memory.");
+                    return usage(argv[0]);
+                }
+                sp = &((*up)->subnets);
+            } else {
+                sp = nt;
+            }
+
+            if (i++ == argc) {
+                ERROR("%s requires at least one prefix.", argv[i - 1]);
+                return usage(argv[0]);
+            }
+            s = strchr(argv[i], '/');
+            if (s == NULL) {
+                ERROR("%s is not a prefix.", argv[i]);
+                return usage(argv[0]);
+            }
+            *s = 0;
+            ++s;
+            prefalen = getipaddr(&pref, argv[i]);
+            if (!prefalen) {
+                ERROR("%s is not a valid prefix address.", argv[i]);
+                return usage(argv[0]);
+            }
+            width = strtol(s, &p, 10);
+            if (s == p || p[0] != '\0') {
+                ERROR("%s (prefix width) is not a number.", p);
+                return usage(argv[0]);
+            }
+            if (width < 0 ||
+                (pref.sa.sa_family == AF_INET && width > 32) ||
+                (pref.sa.sa_family == AF_INET6 && width > 64)) {
+                ERROR("%s is not a valid prefix length for %s", p,
+                        pref.sa.sa_family == AF_INET ? "IPv4" : "IPv6");
+                return usage(argv[0]);
+            }
+
+            *nt = calloc(1, sizeof **nt);
+            if (!*nt) {
+                ERROR("tcp_validators: out of memory.");
+                return 1;
+            }
+
+            (*nt)->preflen = width;
+            (*nt)->family = pref.sa.sa_family;
+            if (pref.sa.sa_family == AF_INET) {
+                memcpy((*nt)->bytes, &pref.sin.sin_addr, 4);
+            } else {
+                memcpy((*nt)->bytes, &pref.sin6.sin6_addr, 8);
+            }
+
+            // *up will be non-null for -u and null for -t.
+            if (*up) {
+                up = &((*up)->next);
+            } else {
+                nt = sp;
+            }
+        }
+    }
+
+    if (!ioloop_init()) {
+        return 1;
+    }
+
+    // Set up listeners
+    if (!setup_listener_socket(AF_INET, IPPROTO_UDP, listen_port, "UDPv4 listener", dns_input, 0, 0)) {
+        ERROR("UDPv4 listener: fail.");
+        return 1;
+    }
+    if (!setup_listener_socket(AF_INET6, IPPROTO_UDP, listen_port, "UDPv6 listener", dns_input, 0, 0)) {
+        ERROR("UDPv6 listener: fail.");
+        return 1;
+    }
+    if (!setup_listener_socket(AF_INET, IPPROTO_TCP, listen_port, "TCPv4 listener", dns_input, 0, 0)) {
+        ERROR("TCPv4 listener: fail.");
+        return 1;
+    }
+    if (!setup_listener_socket(AF_INET6, IPPROTO_TCP, listen_port, "TCPv6 listener", dns_input, 0, 0)) {
+        ERROR("TCPv4 listener: fail.");
+        return 1;
+    }
+    
+    do {
+        int something = 0;
+        something = ioloop_events(0);
+        INFO("dispatched %d events.", something);
+    } while (1);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/srp-simple.c b/ServiceRegistration/srp-simple.c
new file mode 100644 (file)
index 0000000..3590dcf
--- /dev/null
@@ -0,0 +1,272 @@
+/* srp-simple.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Simple Service Registration Protocol Client
+ *
+ * This is intended for the constrained node solution for SRP.   It's intended to be flexible and
+ * understandable while linking in the minimum possible support code to reduce code size.  It does
+ * no mallocs, does not put anything big on the stack, and doesn't require an event loop.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+static void
+dns_response_callback(dns_transaction_t *txn)
+{
+}
+
+int
+main(int argc, char **argv)
+{
+    const char *host_name = "thread-demo";
+    const char *zone_name = "default.service.arpa";
+    const char *host_fqdn = "thread-demo.default.service.arpa";
+    const char *service_type = "_ipps._tcp";
+    const char *a_record = "127.0.0.1";
+    const char *aaaa_record = "::1";
+    const char *txt_record = "0";
+    const char *anycast_address = "127.0.0.1";
+//    const char *anycast_address = "73.186.137.119"; // cer.fugue.com
+    const char *keyfile_name = "srp-simple.key";
+    int port = 9992;
+    srp_key_t *key;
+    dns_wire_t message, response;
+    uint16_t key_tag;
+    static dns_transaction_t txn;
+    dns_towire_state_t *towire = &txn.towire;
+    dns_name_pointer_t p_host_name;
+    dns_name_pointer_t p_zone_name;
+    dns_name_pointer_t p_service_name;
+    dns_name_pointer_t p_service_instance_name;
+    int line;
+
+    key = srp_load_keypair(keyfile_name);
+    if (key == NULL) {
+        key = srp_generate_key();
+        if (key == NULL) {
+            printf("Unable to load or generate a key.");
+            exit(1);
+        }
+        if (!srp_write_key_to_file(keyfile_name, key)) {
+            printf("Unable to safe generated key.");
+            exit(1);
+        }
+    }
+
+#define CH if (towire->error) { line = __LINE__; goto fail; }
+
+    // Generate a random UUID.
+#ifdef NOTYET
+    message.id = srp_random16();
+#else
+    srandomdev();
+    message.id = (uint32_t)(random()) & 65535;
+#endif
+    message.bitfield = 0;
+    dns_qr_set(&message, dns_qr_query);
+    dns_opcode_set(&message, dns_opcode_update);
+
+    // Message data...
+    memset(&txn, 0, sizeof txn);
+    towire->p = &message.data[0];  // We start storing RR data here.
+    towire->lim = &message.data[DNS_DATA_SIZE]; // This is the limit to how much we can store.
+    towire->message = &message;
+    txn.response = &response;
+    txn.response_length = (int)(sizeof response);
+
+    message.qdcount = htons(1); // ZOCOUNT = 1
+    // Copy in Zone name (and save pointer)
+    // ZTYPE = SOA
+    // ZCLASS = IN
+    dns_full_name_to_wire(&p_zone_name, towire, zone_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_soa); CH;
+    dns_u16_to_wire(towire, dns_qclass_in); CH;
+
+    message.ancount = 0;
+    // PRCOUNT = 0
+
+    message.nscount = 0;
+    // UPCOUNT = ...
+
+    // Host Description:
+    //  * Delete all RRsets from <hostname>; remember the pointer to hostname
+    //      NAME = hostname label followed by pointer to SOA name.
+    //      TYPE = ANY
+    //      CLASS = ANY
+    //      TTL = 0
+    //      RDLENGTH = 0
+    dns_name_to_wire(&p_host_name, towire, host_name); CH;
+    dns_pointer_to_wire(&p_host_name, towire, &p_zone_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_any); CH;
+    dns_u16_to_wire(towire, dns_qclass_any); CH;
+    dns_ttl_to_wire(towire, 0); CH;
+    dns_u16_to_wire(towire, 0); CH;
+    message.nscount++;
+    //  * Add either or both of an A or AAAA RRset, each of which contains one
+    //    or more A or AAAA RRs.
+    //      NAME = pointer to hostname from Delete (above)
+    //      TYPE = A or AAAA
+    //      CLASS = IN
+    //      TTL = 3600 ?
+    //      RDLENGTH = number of RRs * RR length (4 or 16)
+    //      RDATA = <the data>
+    dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_a); CH;
+    dns_u16_to_wire(towire, dns_qclass_in); CH;
+    dns_ttl_to_wire(towire, 3600); CH;
+    dns_rdlength_begin(towire); CH;
+    dns_rdata_a_to_wire(towire, a_record); CH;
+    dns_rdlength_end(towire); CH;
+    message.nscount++;
+    
+    dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_aaaa); CH;
+    dns_u16_to_wire(towire, dns_qclass_in); CH;
+    dns_ttl_to_wire(towire, 3600); CH;
+    dns_rdlength_begin(towire); CH;
+    dns_rdata_aaaa_to_wire(towire, aaaa_record); CH;
+    dns_rdlength_end(towire); CH;
+    message.nscount++;
+    
+    //  * Exactly one KEY RR:
+    //      NAME = pointer to hostname from Delete (above)
+    //      TYPE = KEY
+    //      CLASS = IN
+    //      TTL = 3600
+    //      RDLENGTH = length of key + 4 (32 bits)
+    //      RDATA = <flags(16) = 0000 0010 0000 0001, protocol(8) = 3, algorithm(8) = 8?, public key(variable)>
+    dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_key); CH;
+    dns_u16_to_wire(towire, dns_qclass_in); CH;
+    dns_ttl_to_wire(towire, 3600); CH;
+    dns_rdlength_begin(towire); CH;
+    key_tag = dns_rdata_key_to_wire(towire, 0, 2, 1, key); CH;
+    dns_rdlength_end(towire); CH;
+    message.nscount++;
+
+    // Service Discovery:
+    //   * Update PTR RR
+    //     NAME = service name (_a._b.service.arpa)
+    //     TYPE = PTR
+    //     CLASS = IN
+    //     TTL = 3600
+    //     RDLENGTH = 2
+    //     RDATA = service instance name
+    dns_name_to_wire(&p_service_name, towire, service_type); CH;
+    dns_pointer_to_wire(&p_service_name, towire, &p_zone_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_ptr); CH;
+    dns_u16_to_wire(towire, dns_qclass_in); CH;
+    dns_ttl_to_wire(towire, 3600); CH;
+    dns_rdlength_begin(towire); CH;
+    dns_name_to_wire(&p_service_instance_name, towire, host_name); CH;
+    dns_pointer_to_wire(&p_service_instance_name, towire, &p_service_name); CH;
+    dns_rdlength_end(towire); CH;
+    message.nscount++;
+
+    // Service Description:
+    //   * Delete all RRsets from service instance name
+    //      NAME = service instance name (save pointer to service name, which is the second label)
+    //      TYPE = ANY
+    //      CLASS = ANY
+    //      TTL = 0
+    //      RDLENGTH = 0
+    dns_pointer_to_wire(NULL, towire, &p_service_instance_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_any); CH;
+    dns_u16_to_wire(towire, dns_qclass_any); CH;
+    dns_ttl_to_wire(towire, 0); CH;
+    dns_u16_to_wire(towire, 0); CH;
+    message.nscount++;
+
+    //   * Add one SRV RRset pointing to Host Description
+    //      NAME = pointer to service instance name from above
+    //      TYPE = SRV
+    //      CLASS = IN
+    //      TTL = 3600
+    //      RDLENGTH = 8
+    //      RDATA = <priority(16) = 0, weight(16) = 0, port(16) = service port, target = pointer to hostname>
+    dns_pointer_to_wire(NULL, towire, &p_service_instance_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_srv); CH;
+    dns_u16_to_wire(towire, dns_qclass_in); CH;
+    dns_ttl_to_wire(towire, 3600); CH;
+    dns_rdlength_begin(towire); CH;
+    dns_u16_to_wire(towire, 0); // priority CH;
+    dns_u16_to_wire(towire, 0); // weight CH;
+    dns_u16_to_wire(towire, port); // port CH;
+    dns_pointer_to_wire(NULL, towire, &p_host_name); CH;
+    dns_rdlength_end(towire); CH;
+    message.nscount++;
+
+    //   * Add one or more TXT records
+    //      NAME = pointer to service instance name from above
+    //      TYPE = TXT
+    //      CLASS = IN
+    //      TTL = 3600
+    //      RDLENGTH = <length of text>
+    //      RDATA = <text>
+    dns_pointer_to_wire(NULL, towire, &p_service_instance_name); CH;
+    dns_u16_to_wire(towire, dns_rrtype_txt); CH;
+    dns_u16_to_wire(towire, dns_qclass_in); CH;
+    dns_ttl_to_wire(towire, 3600); CH;
+    dns_rdlength_begin(towire); CH;
+    dns_rdata_txt_to_wire(towire, txt_record); CH;
+    dns_rdlength_end(towire); CH;
+    message.nscount++;
+    message.nscount = htons(message.nscount);
+    
+    // What about services with more than one name?   Are these multiple service descriptions?
+
+    // ARCOUNT = 2
+    //   EDNS(0) options
+    //     ...
+    //   SIG(0)
+    
+    message.arcount = htons(1);
+    dns_edns0_header_to_wire(towire, DNS_MAX_UDP_PAYLOAD, 0, 0, 1); CH;   // XRCODE = 0; VERSION = 0; DO=1
+    dns_rdlength_begin(towire); CH;
+    dns_u16_to_wire(towire, dns_opt_update_lease); CH;  // OPTION-CODE
+    dns_edns0_option_begin(towire); CH;                 // OPTION-LENGTH
+    dns_u32_to_wire(towire, 3600); CH;                  // LEASE (1 hour)
+    dns_u32_to_wire(towire, 604800); CH;                // KEY-LEASE (7 days)
+    dns_edns0_option_end(towire); CH;                   // Now we know OPTION-LENGTH
+    dns_rdlength_end(towire); CH;
+
+    dns_sig0_signature_to_wire(towire, key, key_tag, &p_host_name, host_fqdn); CH;
+    // The signature is computed before counting the signature RR in the header counts.
+    message.arcount = htons(ntohs(message.arcount) + 1);
+
+    // Send the update
+    if (dns_send_to_server(&txn, anycast_address, 53, dns_response_callback) < 0) {
+        line = __LINE__;
+    fail:
+        printf("dns_send_to_server failed: %s at line %d\n", strerror(towire->error), line);
+    }
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/srp.c b/ServiceRegistration/srp.c
new file mode 100644 (file)
index 0000000..259654d
--- /dev/null
@@ -0,0 +1,77 @@
+/* srp.c
+ *
+ * Service Registration Protocol Client
+ *
+ * Discover the service registration domain
+ * Construct a DNS update
+ * Include:
+ *  Service Name: PTR Record
+ *  Service Instance Name: SRV record
+ *  Hostname: A, AAAA, KEY records
+ * Sign with key using SIG(0)
+ */
+
+int
+main(int argc, char *argv)
+{
+    char *host_name = "thread-demo";
+    char *service_type "_printer._tcp";
+    char *a_record = "127.0.0.1";
+    char *aaaa_Record = "::1";
+    int prKeyLen = 0;
+    int puKeyLen = 0;
+    uint8_t *prKey = NULL;
+    uint8_t *puKey = NULL;
+    dns_message_t *update;
+    dns_name_t *hostname;
+    dns_name_t *service_name;
+    dns_name_t *service_instance_name;
+    dns_wire_t message;
+
+    message.id = srp_random16();
+    message.bitfield = 0;
+    dns_qr_set(message, dns_qr_query);
+    dns_opcode_set(message, dns_opcode_update);
+    message.qdcount = message.ancount = message.nscount = message.arcount = 0;
+
+    update = dns_message_create();
+    tld = dns_make_fqdn(update, "services.arpa");
+    dns_update_initialize(update, tld, "2001:1::3");
+    hostname = dns_make_fqdn(update, service_name, "services.arpa.");
+    service_name = dns_make_fqdn(message, service_type, "services.arpa.");
+    service_instance_name = dns_make_fqdn(message, service_name, service_name);
+
+    // _printer._tcp.services.arpa IN PTR thread-demo._printer._tcp.services.arpa
+    // thread-demo._printer._tcp.services.arpa IN SRV 0 0 80 thread-demo.services.arpa
+    // thread-demo.services.arpa IN A    127.0.0.1
+    //                           IN AAAA ::1
+    //                           IN KEY ojwefoijweojfwoeijfoiwejfoiwejfoiejf
+
+    dns_update_add(update, hostname, dns_make_a_rr(a_record));
+    dns_update_add(update, hostname, dns_make_a_rr(aaaa_record));
+    dns_update_add(update, service_instance_name, dns_make_srv_rr(0, 0, 80, hostname));
+    dns_update_add(update, service_name, dns_make_ptr_rr(service_instance_name));
+    dns_update_add(update, service_name, dns_make_key_rr(puKey, puKeyLen));
+    dns_message_to_wire(update);
+    dns_message_sign(update, prKey, prKeyLen, puKey, puKeyLen);
+    dns_message_send(update);
+    dns_message_await_response(update);
+
+    // Get the service name and type
+    // Get the hostname
+    // Get the key
+    // Discover the registration domain (not for Thread)
+    // Discover the SRP server (not for Thread)
+    // Generate the update
+    // Sign the update
+    // Send the update
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/srp.h b/ServiceRegistration/srp.h
new file mode 100644 (file)
index 0000000..de89d82
--- /dev/null
@@ -0,0 +1,48 @@
+/* srp.h
+ *
+ * Copyright (c) 2018 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.
+ *
+ * Service Registration Protocol common definitions
+ */
+
+#ifndef __SRP_H
+#define __SRP_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#ifdef __clang__
+#define NULLABLE _Nullable
+#define NONNULL _Nonnull
+#else
+#define NULLABLE
+#define NONNULL
+#endif
+
+#define ERROR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+#define INFO(fmt, ...)  fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+#define DEBUG(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
+
+typedef struct srp_key srp_key_t;
+#endif
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/towire.c b/ServiceRegistration/towire.c
new file mode 100644 (file)
index 0000000..1d82ef2
--- /dev/null
@@ -0,0 +1,564 @@
+/* wire.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS wire-format functions.
+ *
+ * These are really simple functions for constructing DNS messages wire format.
+ * The flow is that there is a transaction structure which contains pointers to both
+ * a message output buffer and a response input buffer.   The structure is initialized,
+ * and then the various wire format functions are called repeatedly to store data.
+ * If an error occurs during this process, it's okay to just keep going, because the
+ * error is recorded in the transaction; once all of the copy-in functions have been
+ * called, the error status can be checked once at the end.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include "srp.h"
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+#ifndef NO_CLOCK
+#include <sys/time.h>
+#endif
+
+// Convert a name to wire format.   Does not store the root label (0) at the end.   Does not support binary labels.
+void
+dns_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+                 dns_towire_state_t *NONNULL txn,
+                 const char *NONNULL name)
+{
+    const char *next, *cur, *end;
+    dns_name_pointer_t np;
+    if (!txn->error) {
+        memset(&np, 0, sizeof np);
+        np.message_start = (u_int8_t *)txn->message;
+        np.name_start = txn->p;
+
+        cur = name;
+        do {
+            end = strchr(cur, '.');
+            if (end == NULL) {
+                end = cur + strlen(cur);
+                if (end == cur) {
+                    break;
+                }
+                next = NULL;
+            } else {
+                if (end == cur) {
+                    break;
+                }
+                next = end + 1;
+            }
+
+            // Is there no space?
+            if (txn->p + (1 + end - cur) >= txn->lim) {
+                txn->error = ENOBUFS;
+                return;
+            }
+
+            // Is the label too long?
+            if (end - cur > DNS_MAX_LABEL_SIZE) {
+                txn->error = ENAMETOOLONG;
+                return;
+            }
+
+            // Store the label length
+            *txn->p++ = (uint8_t)(end - cur);
+
+            // Store the label.
+            memcpy(txn->p, cur, end - cur);
+            txn->p += (end - cur);
+            np.num_labels++;
+            np.length += 1 + (end - cur);
+
+            cur = next;
+        } while (next != NULL);
+
+        if (np.length > DNS_MAX_NAME_SIZE) {
+            txn->error = ENAMETOOLONG;
+            return;
+        }
+        if (r_pointer != NULL) {
+            *r_pointer = np;
+        }
+    }
+}
+
+// Like dns_name_to_wire, but includes the root label at the end.
+void
+dns_full_name_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+                      dns_towire_state_t *NONNULL txn,
+                      const char *NONNULL name)
+{
+    dns_name_pointer_t np;
+    if (!txn->error) {
+        memset(&np, 0, sizeof np);
+        dns_name_to_wire(&np, txn, name);
+        if (!txn->error) {
+            if (txn->p + 1 >= txn->lim) {
+                txn->error = ENOBUFS;
+                return;
+            }
+            *txn->p++ = 0;
+            np.num_labels++;
+            np.length += 1;
+            if (np.length > DNS_MAX_NAME_SIZE) {
+                txn->error = ENAMETOOLONG;
+                return;
+            }
+            if (r_pointer) {
+                *r_pointer = np;
+            }
+        }
+    }
+}
+
+// Store a pointer to a name that's already in the message.
+void
+dns_pointer_to_wire(dns_name_pointer_t *NULLABLE r_pointer,
+                    dns_towire_state_t *NONNULL txn,
+                    dns_name_pointer_t *NONNULL pointer)
+{
+    if (!txn->error) {
+        u_int16_t offset = pointer->name_start - pointer->message_start;
+        if (offset > DNS_MAX_POINTER) {
+            txn->error = ETOOMANYREFS;
+            return;
+        }
+        if (txn->p + 2 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        *txn->p++ = 0xc0 | (offset >> 8);
+        *txn->p++ = offset & 0xff;
+        if (r_pointer) {
+            r_pointer->num_labels += pointer->num_labels;
+            r_pointer->length += pointer->length + 1;
+            if (r_pointer->length > DNS_MAX_NAME_SIZE) {
+                txn->error = ENAMETOOLONG;
+                return;
+            }
+        }
+    }
+}
+
+void
+dns_u8_to_wire(dns_towire_state_t *NONNULL txn,
+                 uint8_t val)
+{
+    if (!txn->error) {
+        if (txn->p + 1 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        *txn->p++ = val;
+    }
+}
+
+// Store a 16-bit integer in network byte order
+void
+dns_u16_to_wire(dns_towire_state_t *NONNULL txn,
+                 uint16_t val)
+{
+    if (!txn->error) {
+        if (txn->p + 2 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        *txn->p++ = val >> 8;
+        *txn->p++ = val & 0xff;
+    }
+}
+
+void
+dns_u32_to_wire(dns_towire_state_t *NONNULL txn,
+                 uint32_t val)
+{
+    if (!txn->error) {
+        if (txn->p + 4 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        *txn->p++ = val >> 24;
+        *txn->p++ = (val >> 16) & 0xff;
+        *txn->p++ = (val >> 8) & 0xff;
+        *txn->p++ = val & 0xff;
+    }
+}
+
+void
+dns_ttl_to_wire(dns_towire_state_t *NONNULL txn,
+                int32_t val)
+{
+    if (!txn->error) {
+        if (val < 0) {
+            txn->error = EINVAL;
+            return;
+        }
+        dns_u32_to_wire(txn, (uint32_t)val);
+    }
+}
+
+void
+dns_rdlength_begin(dns_towire_state_t *NONNULL txn)
+{
+    if (!txn->error) {
+        if (txn->p + 2 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        if (txn->p_rdlength != NULL) {
+            txn->error = EINVAL;
+            return;
+        }
+        txn->p_rdlength = txn->p;
+        txn->p += 2;
+    }
+}
+
+void
+dns_rdlength_end(dns_towire_state_t *NONNULL txn)
+{
+    int rdlength;
+    if (!txn->error) {
+        if (txn->p_rdlength == NULL) {
+            txn->error = EINVAL;
+            return;
+        }
+        rdlength = txn->p - txn->p_rdlength - 2;
+        txn->p_rdlength[0] = rdlength >> 8;
+        txn->p_rdlength[1] = rdlength & 0xff;
+        txn->p_rdlength = NULL;
+    }
+}
+
+void
+dns_rdata_a_to_wire(dns_towire_state_t *NONNULL txn,
+                    const char *NONNULL ip_address)
+{
+    if (!txn->error) {
+        if (txn->p + 4 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        if (!inet_pton(AF_INET, ip_address, txn->p)) {
+            txn->error = EINVAL;
+        }
+        txn->p += 4;
+    }
+}
+
+void
+dns_rdata_aaaa_to_wire(dns_towire_state_t *NONNULL txn,
+                       const char *NONNULL ip_address)
+{
+    if (!txn->error) {
+        if (txn->p + 16 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        if (!inet_pton(AF_INET6, ip_address, txn->p)) {
+            txn->error = EINVAL;
+        }
+        txn->p += 16;
+    }
+}
+
+uint16_t
+dns_rdata_key_to_wire(dns_towire_state_t *NONNULL txn,
+                      unsigned key_type,
+                      unsigned name_type,
+                      unsigned signatory,
+                      srp_key_t *key)
+{
+    int key_len = srp_pubkey_length(key);
+    uint8_t *rdata = txn->p;
+    uint32_t key_tag;
+    int i, rdlen;
+    
+    if (!txn->error) {
+        if (key_type > 3 || name_type > 3 || signatory > 15) {
+            txn->error = EINVAL;
+            return 0;
+        }
+        if (txn->p + key_len + 4 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return 0;
+        }
+        *txn->p++ = (key_type << 6) | name_type;
+        *txn->p++ = signatory;
+        *txn->p++ = 3; // protocol type is always 3
+        *txn->p++ = srp_key_algorithm(key);
+        srp_pubkey_copy(txn->p, key_len, key);
+        txn->p += key_len;
+    }
+    rdlen = txn->p - rdata;
+
+    // Compute the key tag
+    key_tag = 0;
+    for (i = 0; i < rdlen; i++) {
+        key_tag += (i & 1) ? rdata[i] : rdata[i] << 8;
+    }
+    key_tag += (key_tag >> 16) & 0xFFFF;
+    return (uint16_t)(key_tag & 0xFFFF);
+}
+
+void
+dns_rdata_txt_to_wire(dns_towire_state_t *NONNULL txn,
+                      const char *NONNULL txt_record)
+{
+    if (!txn->error) {
+        unsigned len = strlen(txt_record);
+        if (txn->p + len + 1 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        if (len > 255) {
+            txn->error = ENAMETOOLONG;
+            return;
+        }
+        *txn->p++ = (u_int8_t)len;
+        memcpy(txn->p, txt_record, len);
+        txn->p += len;
+    }
+}
+
+void
+dns_rdata_raw_data_to_wire(dns_towire_state_t *NONNULL txn, const void *NONNULL raw_data, size_t length)
+{
+    if (!txn->error) {
+        if (txn->p + length >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        memcpy(txn->p, raw_data, length);
+        txn->p += length;
+    }
+}
+
+void
+dns_edns0_header_to_wire(dns_towire_state_t *NONNULL txn,
+                         int mtu,
+                         int xrcode,
+                         int version,
+                         int DO)
+{
+    if (!txn->error) {
+        if (txn->p + 9 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        *txn->p++ = 0; // root label
+        dns_u16_to_wire(txn, dns_rrtype_opt);
+        dns_u16_to_wire(txn, mtu);
+        *txn->p++ = xrcode;
+        *txn->p++ = version;
+        *txn->p++ = DO << 7;   // flags (usb)
+        *txn->p++ = 0;                 // flags (lsb, mbz)
+    }
+}
+
+void
+dns_edns0_option_begin(dns_towire_state_t *NONNULL txn)
+{
+    if (!txn->error) {
+        if (txn->p + 2 >= txn->lim) {
+            txn->error = ENOBUFS;
+            return;
+        }
+        if (txn->p_opt != NULL) {
+            txn->error = EINVAL;
+            return;
+        }
+        txn->p_opt = txn->p;
+        txn->p += 2;
+    }
+}
+
+void
+dns_edns0_option_end(dns_towire_state_t *NONNULL txn)
+{
+    int opt_length;
+    if (!txn->error) {
+        if (txn->p_opt == NULL) {
+            txn->error = EINVAL;
+            return;
+        }
+        opt_length = txn->p - txn->p_opt - 2;
+        txn->p_opt[0] = opt_length >> 8;
+        txn->p_opt[1] = opt_length & 0xff;
+        txn->p_opt = NULL;
+    }
+}
+
+void
+dns_sig0_signature_to_wire(dns_towire_state_t *NONNULL txn,
+                           srp_key_t *key,
+                           uint16_t key_tag,
+                           dns_name_pointer_t *NONNULL signer,
+                           const char *NONNULL signer_fqdn)
+{
+    int siglen = srp_signature_length(key);
+    uint8_t *start, *p_signer, *p_signature, *rrstart = txn->p;
+#ifndef NO_CLOCK
+    struct timeval now;
+#endif
+
+    // 1 name (root)
+    // 2 type (SIG)
+    // 2 class (0)
+    // 4 TTL (0)
+    // 18 SIG RDATA up to signer name
+    // 2 signer name (always a pointer)
+    // 29 bytes so far
+    // signature data (depends on algorithm, e.g. 64 for ECDSASHA256)
+    // so e.g. 93 bytes total
+    
+    if (!txn->error) {
+        dns_u8_to_wire(txn, 0);        // root label
+        dns_u16_to_wire(txn, dns_rrtype_sig);
+        dns_u16_to_wire(txn, 0); // class
+        dns_ttl_to_wire(txn, 0); // SIG RR TTL
+        dns_rdlength_begin(txn);
+        start = txn->p;
+        dns_u16_to_wire(txn, 0); // type = 0 for transaction signature
+        dns_u8_to_wire(txn, srp_key_algorithm(key));
+        dns_u8_to_wire(txn, 0); // labels field doesn't apply for transaction signature
+        dns_ttl_to_wire(txn, 0); // original ttl doesn't apply
+#ifdef NO_CLOCK
+        dns_u32_to_wire(txn, 0); // Indicate that we have no clock: set expiry and inception times to zero
+        dns_u32_to_wire(txn, 0);
+#else        
+        gettimeofday(&now, NULL);
+        dns_u32_to_wire(txn, now.tv_sec + 300); // signature expiration time is five minutes from now
+        dns_u32_to_wire(txn, now.tv_sec - 300); // signature inception time, five minutes in the past
+#endif
+        dns_u16_to_wire(txn, key_tag);
+        p_signer = txn->p;
+        // We store the name in uncompressed form because that's what we have to sign
+        dns_full_name_to_wire(NULL, txn, signer_fqdn);
+        // And that means we're going to have to copy the signature back earlier in the packet.
+        p_signature = txn->p;
+
+        // Sign the message, signature RRDATA (less signature) first.
+        srp_sign(txn->p, siglen, (uint8_t *)txn->message, rrstart - (uint8_t *)txn->message,
+                 start, txn->p - start, key);
+
+        // Now that it's signed, back up and store the pointer to the name, because we're trying
+        // to be as compact as possible.
+        txn->p = p_signer;
+        dns_pointer_to_wire(NULL, txn, signer); // Pointer to the owner name the key is attached to
+        // And move the signature earlier in the packet.
+        memmove(txn->p, p_signature, siglen);
+
+        txn->p += siglen;
+        dns_rdlength_end(txn);
+    }
+}
+
+int
+dns_send_to_server(dns_transaction_t *NONNULL txn,
+                   const char *NONNULL anycast_address, uint16_t port,
+                   dns_response_callback_t NONNULL callback)
+{
+    union {
+        struct sockaddr_storage s;
+        struct sockaddr sa;
+        struct sockaddr_in sin;
+        struct sockaddr_in6 sin6;
+    } addr, from;
+    socklen_t len, fromlen;
+    ssize_t rv, datasize;
+
+    if (!txn->towire.error) {
+        memset(&addr, 0, sizeof addr);
+
+        // Try IPv4 first because IPv6 addresses are never valid IPv4 addresses
+        if (inet_pton(AF_INET, anycast_address, &addr.sin.sin_addr)) {
+            addr.sin.sin_family = AF_INET;
+            addr.sin.sin_port = htons(port);
+            len = sizeof addr.sin;
+        } else if (inet_pton(AF_INET6, anycast_address, &addr.sin6.sin6_addr)) {
+            addr.sin6.sin6_family = AF_INET6;
+            addr.sin6.sin6_port = htons(port);
+            len = sizeof addr.sin6;
+        } else {
+            txn->towire.error = EPROTONOSUPPORT;
+            return -1;
+        }
+//#ifdef HAVE_SA_LEN
+        addr.sa.sa_len = len;
+//#endif
+
+        txn->sock = socket(addr.sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
+        if (txn->sock < 0) {
+            txn->towire.error = errno;
+            return -1;
+        }
+
+#if 0
+        memset(&myaddr, 0, sizeof myaddr);
+        myaddr.sin.sin_port = htons(9999);
+        myaddr.sa.sa_len = len;
+        myaddr.sa.sa_family = addr.sa.sa_family;
+        rv = bind(txn->sock, &myaddr.sa, len);
+        if (rv < 0) {
+            txn->towire.error = errno;
+            return -1;
+        }
+#endif
+
+        datasize = txn->towire.p - ((u_int8_t *)txn->towire.message);
+        rv = sendto(txn->sock, txn->towire.message, datasize, 0, &addr.sa, len);
+        if (rv < 0) {
+            txn->towire.error = errno;
+            goto out;
+        }
+        if (rv != datasize) {
+            txn->towire.error = EMSGSIZE;
+            goto out;
+        }
+        fromlen = sizeof from;
+        rv = recvfrom(txn->sock, txn->response, sizeof *txn->response, 0, &from.sa, &fromlen);
+        if (rv < 0) {
+            txn->towire.error = errno;
+            goto out;
+        }
+        txn->response_length = rv;
+    }
+out:
+    close(txn->sock);
+    txn->sock = 0;
+
+    if (txn->towire.error) {
+        return -1;
+    }
+    return 0;
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
diff --git a/ServiceRegistration/verify-mbedtls.c b/ServiceRegistration/verify-mbedtls.c
new file mode 100644 (file)
index 0000000..58205d9
--- /dev/null
@@ -0,0 +1,176 @@
+/* verify_mbedtls.c
+ *
+ * Copyright (c) 2018 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.
+ *
+ * DNS SIG(0) signature verification for DNSSD SRP using mbedtls.
+ *
+ * Provides functions for generating a public key validating context based on SIG(0) KEY RR data, and
+ * validating a signature using a context generated with that public key.  Currently only ECDSASHA256 is
+ * supported.
+ */
+
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "srp.h"
+#define SRP_CRYPTO_MBEDTLS_INTERNAL
+#include "dns-msg.h"
+#include "srp-crypto.h"
+
+
+// Given a DNS message, a signature, and a public key, validate the message
+bool
+srp_sig0_verify(dns_wire_t *message, dns_rr_t *key, dns_rr_t *signature)
+{
+    mbedtls_ecp_point pubkey;
+    mbedtls_ecp_group group;
+    mbedtls_sha256_context sha;
+    int status;
+    char errbuf[128];
+    uint8_t hash[ECDSA_SHA256_HASH_SIZE];
+    mbedtls_mpi r, s;
+    uint8_t *rdata;
+    size_t rdlen;
+
+    // The key algorithm and the signature algorithm have to match or we can't validate the signature.
+    if (key->data.key.algorithm != signature->data.sig.algorithm) {
+        return false;
+    }
+
+    // Key must be the right length (DNS ECDSA KEY isn't compressed).
+    if (key->data.key.len != ECDSA_KEY_SIZE) {
+        return false;
+    }
+
+    // Currently only support ecdsa
+    if (signature->data.sig.algorithm != dnssec_keytype_ecdsa) {
+        return false;
+    }
+
+    // Make sure the signature is the right size.
+    if (signature->data.sig.len != ECDSA_SHA256_SIG_SIZE) {
+        return false;
+    }
+
+    // Take the KEY RR and turn it into a public key we can use to check the signature.
+    // Initialize the ECP group (SECP256).
+    mbedtls_ecp_point_init(&pubkey);
+    mbedtls_ecp_group_init(&group);
+    mbedtls_ecp_group_load(&group, MBEDTLS_ECP_DP_SECP256R1);
+    mbedtls_mpi_init(&r);
+    mbedtls_mpi_init(&s);
+    mbedtls_sha256_init(&sha);
+    memset(hash, 0, sizeof hash);
+    
+    if ((status = mbedtls_mpi_read_binary(&pubkey.X, key->data.key.key, ECDSA_KEY_PART_SIZE)) != 0 ||
+        (status = mbedtls_mpi_read_binary(&pubkey.Y, key->data.key.key + ECDSA_KEY_PART_SIZE, ECDSA_KEY_PART_SIZE)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_mpi_read_binary: reading key: %s", errbuf);
+    }
+    mbedtls_mpi_lset(&pubkey.Z, 1);
+
+    if ((status = mbedtls_mpi_read_binary(&r, signature->data.sig.signature, ECDSA_SHA256_SIG_PART_SIZE)) != 0 ||
+        (status = mbedtls_mpi_read_binary(&s, signature->data.sig.signature + ECDSA_SHA256_SIG_PART_SIZE,
+                                          ECDSA_SHA256_SIG_PART_SIZE)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_mpi_read_binary: reading signature: %s", errbuf);
+    }
+    
+    // The hash is across the message _before_ the SIG RR is added, so we have to decrement arcount before
+       // computing it.
+    message->arcount = htons(ntohs(message->arcount) - 1);
+
+    // And the SIG RRDATA that we hash includes the canonical version of the name, not whatever bits
+    // are in the actual wire format message, so we have to just make a copy of it.
+    rdlen = SIG_STATIC_RDLEN + dns_name_wire_length(signature->data.sig.signer);
+    rdata = malloc(rdlen);
+    if (rdata == NULL) {
+        ERROR("no memory for SIG RR canonicalization");
+        return 0;
+    }
+    memcpy(rdata, &message->data[signature->data.sig.start + SIG_HEADERLEN], SIG_STATIC_RDLEN);
+    if (!dns_name_to_wire_canonical(rdata + SIG_STATIC_RDLEN, rdlen - SIG_STATIC_RDLEN,
+                                    signature->data.sig.signer)) {
+        // Should never happen.
+        ERROR("dns_name_wire_length and dns_name_to_wire_canonical got different lengths!");
+        return 0;
+    }
+
+    // First compute the hash across the SIG RR, then hash the message up to the SIG RR
+    if ((status = mbedtls_sha256_starts_ret(&sha, 0)) != 0 ||
+        (status = srp_mbedtls_sha256_update_ret(&sha, rdata, rdlen)) != 0 ||
+        (status = srp_mbedtls_sha256_update_ret(&sha, (uint8_t *)message,
+                                                signature->data.sig.start +
+                                                (sizeof *message) - DNS_DATA_SIZE)) != 0 ||
+        (status = srp_mbedtls_sha256_finish_ret(&sha, hash)) != 0) {
+        // Put it back
+        message->arcount = htons(ntohs(message->arcount) + 1);
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_sha_256 hash failed: %s", errbuf);
+        return 0;
+    }
+    message->arcount = htons(ntohs(message->arcount) + 1);
+    free(rdata);
+    
+    // Now check the signature against the hash
+    status = mbedtls_ecdsa_verify(&group, hash, sizeof hash, &pubkey, &r, &s);
+    if (status != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_ecdsa_verify failed: %s", errbuf);
+        return 0;
+    }
+    return 1;
+}
+
+// Function to copy out the public key as binary data
+void
+srp_print_key(srp_key_t *key)
+{
+    mbedtls_ecp_keypair *ecp = mbedtls_pk_ec(key->key);
+    char errbuf[64];
+    uint8_t buf[ECDSA_KEY_SIZE];
+    uint8_t b64buf[((ECDSA_KEY_SIZE * 4) / 3) + 6];
+    size_t b64len;
+    int status;
+
+    // Currently ECP only.
+    if ((status = mbedtls_mpi_write_binary(&ecp->Q.X, buf, ECDSA_KEY_PART_SIZE)) != 0 ||
+        (status = mbedtls_mpi_write_binary(&ecp->Q.Y, buf + ECDSA_KEY_PART_SIZE, ECDSA_KEY_PART_SIZE)) != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_mpi_write_binary: %s", errbuf);
+        return;
+    }
+
+    status = mbedtls_base64_encode(b64buf, sizeof b64buf, &b64len, buf, ECDSA_KEY_SIZE);
+    if (status != 0) {
+        mbedtls_strerror(status, errbuf, sizeof errbuf);
+        ERROR("mbedtls_mpi_write_binary: %s", errbuf);
+        return;
+    }
+    fputs("thread-demo.default.service.arpa. IN KEY 513 3 13 ", stdout);
+    fwrite(b64buf, b64len, 1, stdout);
+    putc('\n', stdout);
+}
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
index 0008405ddd082044410f281ede9f1c7fa1e2c204..aeca5519a91d90891c8914a8259bf3b84426bc7d 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2012 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2011-2019 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.
@@ -119,7 +118,7 @@ mDNSexport AlgContext *AlgCreate(AlgType type, mDNSu8 alg)
     if (func->Create)
     {
         mStatus err;
-        ctx = mDNSPlatformMemAllocate(sizeof(AlgContext));
+        ctx = (AlgContext *) mDNSPlatformMemAllocateClear(sizeof(*ctx));
         if (!ctx) return mDNSNULL;
         // Create expects ctx->alg to be initialized
         ctx->alg = alg;
index 15a9220098832303be417a6b27dc1a5ac98038cb..2c4e97e9f2aaf80af14e1feff7c0a20dd13e8bdb 100644 (file)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
 #define mDNS_InstantiateInlines 1
 #include "DNSCommon.h"
 #include "CryptoAlg.h"
-#include "anonymous.h"
-
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
 
 // Disable certain benign warnings with Microsoft compilers
 #if (defined(_MSC_VER))
 mDNSexport const mDNSInterfaceID mDNSInterface_Any       = 0;
 mDNSexport const mDNSInterfaceID mDNSInterfaceMark       = (mDNSInterfaceID)-1;
 mDNSexport const mDNSInterfaceID mDNSInterface_LocalOnly = (mDNSInterfaceID)-2;
-mDNSexport const mDNSInterfaceID mDNSInterface_Unicast   = (mDNSInterfaceID)-3;
-mDNSexport const mDNSInterfaceID mDNSInterface_P2P       = (mDNSInterfaceID)-4;
-mDNSexport const mDNSInterfaceID uDNSInterfaceMark       = (mDNSInterfaceID)-5;
-mDNSexport const mDNSInterfaceID mDNSInterface_BLE       = (mDNSInterfaceID)-6;
+mDNSexport const mDNSInterfaceID mDNSInterface_P2P       = (mDNSInterfaceID)-3;
+mDNSexport const mDNSInterfaceID uDNSInterfaceMark       = (mDNSInterfaceID)-4;
+mDNSexport const mDNSInterfaceID mDNSInterface_BLE       = (mDNSInterfaceID)-5;
 
 // 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
@@ -112,12 +106,12 @@ mDNSexport const mDNSOpaque16 DNSSecQFlags    = { { kDNSFlag0_QR_Query    | kDNS
 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 mDNSOpaque16 SubscribeFlags  = { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_Subscribe, 0 } };
-mDNSexport const mDNSOpaque16 UnSubscribeFlags= { { kDNSFlag0_QR_Query    | kDNSFlag0_OP_UnSubscribe, 0 } };
 
 mDNSexport const mDNSOpaque64  zeroOpaque64     = { { 0 } };
 mDNSexport const mDNSOpaque128 zeroOpaque128    = { { 0 } };
 
+extern mDNS mDNSStorage;
+
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -132,6 +126,21 @@ mDNSexport mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr)
             (addr->b[0] == 192 && addr->b[1] == 168));            // 192.168/16
 }
 
+mDNSexport const char *DNSScopeToString(mDNSu32 scope)
+{
+    switch (scope)
+    {
+        case kScopeNone:
+            return "Unscoped";
+        case kScopeInterfaceID:
+            return "InterfaceScoped";
+        case kScopeServiceID:
+            return "ServiceScoped";
+        default:
+            return "Unknown";
+    }
+}
+
 mDNSexport void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out)
 {
     out->l[0] = 0;
@@ -994,7 +1003,7 @@ mDNSexport mDNSu8 *ConstructServiceName(domainname *const fqdn,
 
     // In the case where there is no name (and ONLY in that case),
     // a single-label subtype is allowed as the first label of a three-part "type"
-    if (!name && type)
+    if (!name)
     {
         const mDNSu8 *s0 = type->c;
         if (s0[0] && s0[0] < 0x40)      // If legal first label (at least one character, and no more than 63)
@@ -1160,57 +1169,6 @@ mDNSexport mStatus DNSNameToLowerCase(domainname *d, domainname *result)
     return mStatus_NoError;
 }
 
-mDNSexport const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 *AnonData, int AnonDataLen,
-    const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen)
-{
-    AlgContext *ctx;
-    unsigned int i;
-    unsigned int iterations;
-    domainname lname;
-    mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
-    const mDNSu8 *digest;
-    int digestlen;
-    mDNSBool first = mDNStrue;
-
-    if (DNSNameToLowerCase((domainname *)name, &lname) != mStatus_NoError)
-    {
-        LogMsg("NSEC3HashName: ERROR!! DNSNameToLowerCase failed");
-        return mDNSNULL;
-    }
-
-    digest = lname.c;
-    digestlen = DomainNameLength(&lname);
-
-    // Note that it is "i <=". The first iteration is for digesting the name and salt.
-    // The iteration count does not include that.
-    iterations = swap16(nsec3->iterations);
-    for (i = 0; i <= iterations; i++)
-    {
-        ctx = AlgCreate(DIGEST_ALG, nsec3->alg);
-        if (!ctx)
-        {
-            LogMsg("NSEC3HashName: ERROR!! Cannot allocate context");
-            return mDNSNULL;
-        }
-
-        AlgAdd(ctx, digest, digestlen);
-        if (nsec3->saltLength)
-            AlgAdd(ctx, p, nsec3->saltLength);
-        if (AnonDataLen)
-            AlgAdd(ctx, AnonData, AnonDataLen);
-        if (first)
-        {
-            first = mDNSfalse;
-            digest = hash;
-            digestlen = AlgLength(ctx);
-        }
-        AlgFinal(ctx, (void *)digest, digestlen);
-        AlgDestroy(ctx);
-    }
-    *dlen = digestlen;
-    return digest;
-}
-
 // Notes on UTF-8:
 // 0xxxxxxx represents a 7-bit ASCII value from 0x00 to 0x7F
 // 10xxxxxx is a continuation byte of a multi-byte character
@@ -1392,7 +1350,6 @@ mDNSexport void mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mD
     rr->resrec.rrclass           = kDNSClass_IN;
     rr->resrec.rroriginalttl     = ttl;
     rr->resrec.rDNSServer        = mDNSNULL;
-    rr->resrec.AnonInfo          = mDNSNULL;
 //     rr->resrec.rdlength          = MUST set by client and/or in mDNS_Register_internal
 //     rr->resrec.rdestimate        = set in mDNS_Register_internal
 //     rr->resrec.rdata             = MUST be set by client
@@ -1456,7 +1413,6 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
 {
     q->InterfaceID         = InterfaceID;
     q->flags               = 0;
-    q->Target              = zeroAddr;
     AssignDomainName(&q->qname, name);
     q->qtype               = qtype;
     q->qclass              = kDNSClass_IN;
@@ -1465,20 +1421,16 @@ mDNSexport void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID I
     q->ForceMCast          = mDNSfalse;
     q->ReturnIntermed      = mDNSfalse;
     q->SuppressUnusable    = mDNSfalse;
-    q->SearchListIndex     = 0;
     q->AppendSearchDomains = 0;
-    q->RetryWithSearchDomains = mDNSfalse;
     q->TimeoutQuestion     = 0;
     q->WakeOnResolve       = 0;
-    q->UseBackgroundTrafficClass = mDNSfalse;
+    q->UseBackgroundTraffic = mDNSfalse;
     q->ValidationRequired  = 0;
     q->ValidatingResponse  = 0;
     q->ProxyQuestion       = 0;
-    q->qnameOrig           = mDNSNULL;
-    q->AnonInfo            = mDNSNULL;
     q->pid                 = mDNSPlatformGetPID();
     q->euid                = 0;
-    q->DisallowPID         = mDNSfalse;
+    q->BlockedByPolicy     = mDNSfalse;
     q->ServiceID           = -1;
     q->QuestionCallback    = callback;
     q->QuestionContext     = context;
@@ -1532,6 +1484,7 @@ mDNSexport mDNSu32 RDataHashValue(const ResourceRecord *const rr)
         sum = DomainNameHashValue((domainname *)rdb->data);
         ptr += dlen;
         len -= dlen;
+        fallthrough();
         /* FALLTHROUGH */
     }
 
@@ -1769,7 +1722,7 @@ mDNSlocal mDNSBool DNSSECRecordAnswersQuestion(const ResourceRecord *const rr, c
 // 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)
+mDNSlocal mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
 {
     mDNSBool checkType = mDNStrue;
 
@@ -1780,7 +1733,7 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
         LogMsg("SameNameRecordAnswersQuestion: ERROR!! called with LocalOnly ResourceRecord %p, Question %p", rr->InterfaceID, q->InterfaceID);
         return mDNSfalse;
     }
-    if (QuerySuppressed(q))
+    if (q->Suppressed)
         return mDNSfalse;
 
     if (rr->InterfaceID &&
@@ -1788,8 +1741,9 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
         rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
 
     // Resource record received via unicast, the resolver group ID should match ?
-    if (!rr->InterfaceID)
+    if (!isAuthRecord && !rr->InterfaceID)
     {
+        if (mDNSOpaque16IsZero(q->TargetQID)) return(mDNSfalse);
         const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
         const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
         if (idr != idq) return(mDNSfalse);
@@ -1813,20 +1767,37 @@ mDNSexport mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr
         return mDNSfalse;
 #endif // APPLE_OSX_mDNSResponder
 
-    if (!AnonInfoAnswersQuestion(rr, q))
-        return mDNSfalse;
-
     return(mDNStrue);
 }
 
-mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSexport mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
+{
+    return SameNameRecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
+}
+
+mDNSlocal mDNSBool RecordAnswersQuestion(const ResourceRecord *const rr, mDNSBool isAuthRecord, const DNSQuestion *const q)
 {
-    if (!SameNameRecordAnswersQuestion(rr, q))
+    if (!SameNameRecordAnswersQuestion(rr, isAuthRecord, q))
         return mDNSfalse;
 
     return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
 }
 
+mDNSexport mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+{
+    return RecordAnswersQuestion(rr, mDNSfalse, q);
+}
+
+mDNSexport mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
+{
+    return RecordAnswersQuestion(&ar->resrec, mDNStrue, q);
+}
+
+mDNSexport mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q)
+{
+    return RecordAnswersQuestion(&cr->resrec, mDNSfalse, q);
+}
+
 // We have a separate function to handle LocalOnly AuthRecords because they can be created with
 // a valid InterfaceID (e.g., scoped /etc/hosts) and can be used to answer unicast questions unlike
 // multicast resource records (which has a valid InterfaceID) which can't be used to answer
@@ -1852,12 +1823,11 @@ mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const D
     // *local* to the machine. These include resource records that have InterfaceID set to mDNSInterface_LocalOnly,
     // mDNSInterface_Any and any other real InterfaceID. Hence, LocalOnly questions should not be checked against
     // the InterfaceID in the resource record.
-    //
-    // mDNSInterface_Unicast does not indicate any scope and hence treat them like mDNSInterface_Any.
 
     if (rr->InterfaceID &&
-        q->InterfaceID && q->InterfaceID != mDNSInterface_LocalOnly && q->InterfaceID != mDNSInterface_Unicast &&
-        rr->InterfaceID != q->InterfaceID) return(mDNSfalse);
+        q->InterfaceID != mDNSInterface_LocalOnly &&
+        ((q->InterfaceID && rr->InterfaceID != q->InterfaceID) ||
+        (!q->InterfaceID && rr->InterfaceID != mDNSInterface_LocalOnly))) return(mDNSfalse);
 
     // Entries in /etc/hosts are added as LocalOnly resource records. The LocalOnly resource records
     // may have a scope e.g., fe80::1%en0. The question may be scoped or not: the InterfaceID may be set
@@ -1900,14 +1870,12 @@ mDNSexport mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const ar, const D
     if (!RRTypeAnswersQuestionType(rr,q->qtype)) return(mDNSfalse);
     if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
 
-    if (!AnonInfoAnswersQuestion(rr, q))
-        return mDNSfalse;
-
     return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
 }
 
-mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
+mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q)
 {
+    const ResourceRecord *const rr = &ar->resrec;
     // LocalOnly/P2P questions can be answered with AuthRecordAny in this function. LocalOnly/P2P records
     // are handled in LocalOnlyRecordAnswersQuestion
     if (LocalOnlyOrP2PInterface(rr->InterfaceID))
@@ -1927,6 +1895,9 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
         const mDNSu32 idr = rr->rDNSServer ? rr->rDNSServer->resGroupID : 0;
         const mDNSu32 idq = q->qDNSServer ? q->qDNSServer->resGroupID : 0;
         if (idr != idq) return(mDNSfalse);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+        if (!mDNSPlatformValidRecordForInterface(ar, q->InterfaceID)) return(mDNSfalse);
+#endif
     }
 
     // If ResourceRecord received via multicast, but question was unicast, then shouldn't use record to answer this question
@@ -1934,9 +1905,6 @@ mDNSexport mDNSBool AnyTypeRecordAnswersQuestion(const ResourceRecord *const rr,
 
     if (rr->rrclass != q->qclass && q->qclass != kDNSQClass_ANY) return(mDNSfalse);
 
-    if (!AnonInfoAnswersQuestion(rr, q))
-        return mDNSfalse;
-
     return(rr->namehash == q->qnamehash && SameDomainName(rr->name, &q->qname));
 }
 
@@ -1949,7 +1917,7 @@ mDNSexport mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *c
 {
     mDNSBool checkType = mDNStrue;
 
-    if (QuerySuppressed(q))
+    if (q->Suppressed)
         return mDNSfalse;
 
     // For resource records created using multicast, the InterfaceIDs have to match
@@ -2646,30 +2614,6 @@ mDNSexport mDNSu8 *putDNSSECOption(DNSMessage *msg, mDNSu8 *end, mDNSu8 *limit)
     return end;
 }
 
-mDNSexport mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *end, DomainAuthInfo *authInfo, mDNSu8 *limit)
-{
-    if (authInfo && authInfo->AutoTunnel)
-    {
-        AuthRecord hinfo;
-        mDNSu8 *h = hinfo.rdatastorage.u.data;
-        mDNSu16 len = 2 + m->HIHardware.c[0] + m->HISoftware.c[0];
-        mDNSu8 *newptr;
-        mDNS_SetupResourceRecord(&hinfo, mDNSNULL, mDNSInterface_Any, kDNSType_HINFO, 0, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
-        AppendDomainLabel(&hinfo.namestorage, &m->hostlabel);
-        AppendDomainName (&hinfo.namestorage, &authInfo->domain);
-        hinfo.resrec.rroriginalttl = 0;
-        mDNSPlatformMemCopy(h, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
-        h += 1 + (int)h[0];
-        mDNSPlatformMemCopy(h, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
-        hinfo.resrec.rdlength   = len;
-        hinfo.resrec.rdestimate = len;
-        newptr = PutResourceRecordTTLWithLimit(msg, end, &msg->h.numAdditionals, &hinfo.resrec, 0, limit);
-        return newptr;
-    }
-    else
-        return end;
-}
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -2837,7 +2781,7 @@ mDNSlocal mDNSu8 *SanityCheckBitMap(const mDNSu8 *bmap, const mDNSu8 *end, int l
 
 // This function is called with "msg" when we receive a DNS message and needs to parse a single resource record
 // pointed to by "ptr". Some resource records like SOA, SRV are converted to host order and also expanded
-// (domainnames are expanded to 255 bytes) when stored in memory.
+// (domainnames are expanded to 256 bytes) when stored in memory.
 //
 // This function can also be called with "NULL" msg to parse a single resource record pointed to by ptr.
 // The caller can do this only if the names in the resource records are not compressed and validity of the
@@ -3439,6 +3383,7 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
 {
     CacheRecord *const rr = &largecr->r;
     mDNSu16 pktrdlength;
+    mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds;
 
     if (largecr == &m->rec && m->rec.r.resrec.RecordType)
         LogFatalError("GetLargeResourceRecord: m->rec appears to be already in use for %s", CRDisplayString(m, &m->rec.r));
@@ -3467,8 +3412,8 @@ mDNSexport const mDNSu8 *GetLargeResourceRecord(mDNS *const m, const DNSMessage
     rr->resrec.rrtype            = (mDNSu16) ((mDNSu16)ptr[0] <<  8 | ptr[1]);
     rr->resrec.rrclass           = (mDNSu16)(((mDNSu16)ptr[2] <<  8 | ptr[3]) & kDNSClass_Mask);
     rr->resrec.rroriginalttl     = (mDNSu32) ((mDNSu32)ptr[4] << 24 | (mDNSu32)ptr[5] << 16 | (mDNSu32)ptr[6] << 8 | ptr[7]);
-    if (rr->resrec.rroriginalttl > mDNSMaximumTTLSeconds && (mDNSs32)rr->resrec.rroriginalttl != -1)
-        rr->resrec.rroriginalttl = mDNSMaximumTTLSeconds;
+    if (rr->resrec.rroriginalttl > maxttl && (mDNSs32)rr->resrec.rroriginalttl != -1)
+        rr->resrec.rroriginalttl = maxttl;
     // 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]);
@@ -3636,23 +3581,23 @@ mDNSexport mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, cons
         (X) == kDNSFlag0_OP_Unused3  ? "Unused3 " :       \
         (X) == kDNSFlag0_OP_Notify   ? "Notify "  :       \
         (X) == kDNSFlag0_OP_Update   ? "Update "  :       \
-        (X) == kDNSFlag0_OP_Subscribe? "Subscribe":       \
-        (X) == kDNSFlag0_OP_UnSubscribe? "UnSubscribe" : "?? " )
+        (X) == kDNSFlag0_OP_DSO      ? "DSO "  : "?? " )
 
 #define DNS_RC_Name(X) (                             \
-        (X) == kDNSFlag1_RC_NoErr    ? "NoErr"    :      \
-        (X) == kDNSFlag1_RC_FormErr  ? "FormErr"  :      \
-        (X) == kDNSFlag1_RC_ServFail ? "ServFail" :      \
-        (X) == kDNSFlag1_RC_NXDomain ? "NXDomain" :      \
-        (X) == kDNSFlag1_RC_NotImpl  ? "NotImpl"  :      \
-        (X) == kDNSFlag1_RC_Refused  ? "Refused"  :      \
-        (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"  : "??" )
-
-mDNSlocal void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
+        (X) == kDNSFlag1_RC_NoErr     ? "NoErr"    :      \
+        (X) == kDNSFlag1_RC_FormErr   ? "FormErr"  :      \
+        (X) == kDNSFlag1_RC_ServFail  ? "ServFail" :      \
+        (X) == kDNSFlag1_RC_NXDomain  ? "NXDomain" :      \
+        (X) == kDNSFlag1_RC_NotImpl   ? "NotImpl"  :      \
+        (X) == kDNSFlag1_RC_Refused   ? "Refused"  :      \
+        (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"  :      \
+        (X) == kDNSFlag1_RC_DSOTypeNI ? "DSOTypeNI" : "??" )
+
+mDNSexport void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
 {
     va_list args;
     mDNSu32 buflen, n;
@@ -3678,34 +3623,17 @@ mDNSlocal void mDNS_snprintf_add(char **ptr, const char *lim, const char *fmt, .
         (((mDNSu32)((mDNSu8 *)(PTR))[2]) <<  8) | \
          ((mDNSu32)((mDNSu8 *)(PTR))[3])))
 
-mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const end, char *buffer, mDNSu32 buflen)
+mDNSlocal void DNSMessageDumpToLog(const DNSMessage *const msg, const mDNSu8 *const end)
 {
-    domainname *name;
-    const mDNSu8 *ptr;
+    domainname *name = mDNSNULL;
+    const mDNSu8 *ptr = msg->data;
     domainname nameStorage[2];
-    char *dst = buffer;
-    const char *const lim = &buffer[buflen];
-    mDNSu32 i;
-    const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals;
 
-    mDNS_snprintf_add(&dst, lim, "DNS %s%s (%lu) (flags %02X%02X) RCODE: %s (%d)%s%s%s%s%s%s ID: %u:",
-           DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
-           (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query",
-           (unsigned long)(end - (const mDNSu8 *)msg),
-           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));
-
-    name = mDNSNULL;
-    ptr  = msg->data;
-    for (i = 0; i < msg->h.numQuestions; i++)
+    char questions[512];
+    questions[0] = '\0';
+    char *questions_dst = questions;
+    const char *const questions_lim = &questions[512];
+    for (mDNSu32 i = 0; i < msg->h.numQuestions; i++)
     {
         mDNSu16 qtype, qclass;
 
@@ -3718,13 +3646,17 @@ mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const e
         qclass = ReadField16(&ptr[2]);
         ptr += 4;
 
-        mDNS_snprintf_add(&dst, lim, " %##s %s", name->c, DNSTypeString(qtype));
-        if (qclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", qclass);
-        mDNS_snprintf_add(&dst, lim, "?");
+        mDNS_snprintf_add(&questions_dst, questions_lim, " %##s %s", name->c, DNSTypeString(qtype));
+        if (qclass != kDNSClass_IN) mDNS_snprintf_add(&questions_dst, questions_lim, "/%u", qclass);
+        mDNS_snprintf_add(&questions_dst, questions_lim, "?");
     }
 
-    mDNS_snprintf_add(&dst, lim, " %u/%u/%u", msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals);
-    for (i = 0; i < rrcount; i++)
+    char rrs[512];
+    rrs[0] = '\0';
+    char *rrs_dst = rrs;
+    const char *const rrs_lim = &rrs[512];
+    const mDNSu32 rrcount = msg->h.numAnswers + msg->h.numAuthorities + msg->h.numAdditionals;
+    for (mDNSu32 i = 0; i < rrcount; i++)
     {
         mDNSu16 rrtype, rrclass, rdlength;
         mDNSu32 ttl;
@@ -3746,104 +3678,118 @@ mDNSlocal void DNSMessageDump(const DNSMessage *const msg, const mDNSu8 *const e
         if ((end - ptr) < rdlength) goto exit;
         rdata = ptr;
 
-        if (i > 0) mDNS_snprintf_add(&dst, lim, ",");
-        if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&dst, lim, " %##s", name);
+        if (i > 0) mDNS_snprintf_add(&rrs_dst, rrs_lim, ",");
+        if (!previousName || !SameDomainName(name, previousName)) mDNS_snprintf_add(&rrs_dst, rrs_lim, " %##s", name);
 
-        mDNS_snprintf_add(&dst, lim, " %s", DNSTypeString(rrtype));
-        if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&dst, lim, "/%u", rrclass);
-        mDNS_snprintf_add(&dst, lim, " ");
+        mDNS_snprintf_add(&rrs_dst, rrs_lim, " %s", DNSTypeString(rrtype));
+        if (rrclass != kDNSClass_IN) mDNS_snprintf_add(&rrs_dst, rrs_lim, "/%u", rrclass);
+        mDNS_snprintf_add(&rrs_dst, rrs_lim, " ");
 
         handled = mDNSfalse;
         switch (rrtype)
         {
-        case kDNSType_A:
-            if (rdlength == 4)
-            {
-                mDNS_snprintf_add(&dst, lim, "%.4a", rdata);
-                handled = mDNStrue;
-            }
-            break;
+            case kDNSType_A:
+                if (rdlength == 4)
+                {
+                    mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.4a", rdata);
+                    handled = mDNStrue;
+                }
+                break;
 
-        case kDNSType_AAAA:
-            if (rdlength == 16)
-            {
-                mDNS_snprintf_add(&dst, lim, "%.16a", rdata);
-                handled = mDNStrue;
-            }
-            break;
+            case kDNSType_AAAA:
+                if (rdlength == 16)
+                {
+                    mDNS_snprintf_add(&rrs_dst, rrs_lim, "%.16a", rdata);
+                    handled = mDNStrue;
+                }
+                break;
 
-        case kDNSType_CNAME:
-            ptr = getDomainName(msg, rdata, end, name);
-            if (!ptr) goto exit;
+            case kDNSType_CNAME:
+                ptr = getDomainName(msg, rdata, end, name);
+                if (!ptr) goto exit;
 
-            mDNS_snprintf_add(&dst, lim, "%##s", name);
-            handled = mDNStrue;
-            break;
+                mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s", name);
+                handled = mDNStrue;
+                break;
 
-        case kDNSType_SOA:
-        {
-            mDNSu32 serial, refresh, retry, expire, minimum;
-            domainname *const mname = &nameStorage[0];
-            domainname *const rname = &nameStorage[1];
-            name = mDNSNULL;
+            case kDNSType_SOA:
+            {
+                mDNSu32 serial, refresh, retry, expire, minimum;
+                domainname *const mname = &nameStorage[0];
+                domainname *const rname = &nameStorage[1];
+                name = mDNSNULL;
 
-            ptr = getDomainName(msg, rdata, end, mname);
-             if (!ptr) goto exit;
+                ptr = getDomainName(msg, rdata, end, mname);
+                if (!ptr) goto exit;
 
-            ptr = getDomainName(msg, ptr, end, rname);
-            if (!ptr) goto exit;
+                ptr = getDomainName(msg, ptr, end, rname);
+                if (!ptr) goto exit;
 
-            if ((end - ptr) < 20) goto exit;
-            serial  = ReadField32(&ptr[0]);
-            refresh = ReadField32(&ptr[4]);
-            retry   = ReadField32(&ptr[8]);
-            expire  = ReadField32(&ptr[12]);
-            minimum = ReadField32(&ptr[16]);
+                if ((end - ptr) < 20) goto exit;
+                serial  = ReadField32(&ptr[0]);
+                refresh = ReadField32(&ptr[4]);
+                retry   = ReadField32(&ptr[8]);
+                expire  = ReadField32(&ptr[12]);
+                minimum = ReadField32(&ptr[16]);
 
-            mDNS_snprintf_add(&dst, lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial,
-                (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum);
+                mDNS_snprintf_add(&rrs_dst, rrs_lim, "%##s %##s %lu %lu %lu %lu %lu", mname, rname, (unsigned long)serial,
+                                  (unsigned long)refresh, (unsigned long)retry, (unsigned long)expire, (unsigned long)minimum);
 
-            handled = mDNStrue;
-            break;
-        }
+                handled = mDNStrue;
+                break;
+            }
 
-        default:
-            break;
+            default:
+                break;
         }
-        if (!handled) mDNS_snprintf_add(&dst, lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata);
-        mDNS_snprintf_add(&dst, lim, " (%lu)", (unsigned long)ttl);
+        if (!handled) mDNS_snprintf_add(&rrs_dst, rrs_lim, "RDATA[%u]: %.*H", rdlength, rdlength, rdata);
+        mDNS_snprintf_add(&rrs_dst, rrs_lim, " (%lu)", (unsigned long)ttl);
         ptr = rdata + rdlength;
     }
 
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+        "[Q%u] DNS " PUB_S PUB_S " (%lu) (flags %02X%02X) RCODE: " PUB_S " (%d)" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S ":"
+        PRI_S " %u/%u/%u " PRI_S,
+        mDNSVal16(msg->h.id),
+        DNS_OP_Name(msg->h.flags.b[0] & kDNSFlag0_OP_Mask),
+        (msg->h.flags.b[0] & kDNSFlag0_QR_Response) ? "Response" : "Query",
+        (unsigned long)(end - (const mDNSu8 *)msg),
+        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" : "",
+        questions, msg->h.numAnswers, msg->h.numAuthorities, msg->h.numAdditionals, rrs);
+
 exit:
     return;
 }
 
 // Note: DumpPacket expects the packet header fields in host byte order, not network byte order
-mDNSexport void DumpPacket(mStatus status, mDNSBool sent, char *transport,
-                           const mDNSAddr *srcaddr, mDNSIPPort srcport,
-                           const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end)
+mDNSexport void DumpPacket(mStatus status, mDNSBool sent, const char *transport,
+    const mDNSAddr *srcaddr, mDNSIPPort srcport,const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg,
+    const mDNSu8 *const end, mDNSInterfaceID interfaceID)
 {
-    char buffer[512];
-    char *dst = buffer;
-    const char *const lim = &buffer[512];
-
-    buffer[0] = '\0';
-    if (!status) mDNS_snprintf_add(&dst, lim, sent ? "Sent" : "Received");
-    else         mDNS_snprintf_add(&dst, lim, "ERROR %d %sing", status, sent ? "Send" : "Receiv");
-
-    mDNS_snprintf_add(&dst, lim, " %s DNS Message %u bytes from ", transport, (unsigned long)(end - (const mDNSu8 *)msg));
-
-    if (sent) mDNS_snprintf_add(&dst, lim, "port %d", mDNSVal16(srcport));
-    else      mDNS_snprintf_add(&dst, lim, "%#a:%d", srcaddr, mDNSVal16(srcport));
-
-    if (dstaddr || !mDNSIPPortIsZero(dstport)) mDNS_snprintf_add(&dst, lim, " to %#a:%d", dstaddr, mDNSVal16(dstport));
-
-    LogInfo("%s", buffer);
-
-    buffer[0] = '\0';
-    DNSMessageDump(msg, end, buffer, (mDNSu32)sizeof(buffer));
-    LogInfo("%s", buffer);
+    const mDNSAddr zeroIPv4Addr = { mDNSAddrType_IPv4, {{{ 0 }}} };
+    char action[32];
+    if (!status) mDNS_snprintf(action, sizeof(action), sent ? "Sent" : "Received");
+    else         mDNS_snprintf(action, sizeof(action), "ERROR %d %sing", status, sent ? "Send" : "Receiv");
+
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+        "[Q%u] " PUB_S " " PUB_S " DNS Message %lu bytes from " PRI_IP_ADDR ":%d to " PRI_IP_ADDR ":%d via " PUB_S " (%p)",
+        mDNSVal16(msg->h.id), action, transport, (unsigned long)(end - (const mDNSu8 *)msg),
+        srcaddr ? srcaddr : &zeroIPv4Addr, mDNSVal16(srcport), dstaddr ? dstaddr : &zeroIPv4Addr, mDNSVal16(dstport),
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+        InterfaceNameForID(&mDNSStorage, interfaceID),
+#else
+        "interface",
+#endif
+        interfaceID);
+    DNSMessageDumpToLog(msg, end);
 }
 
 // ***************************************************************************
@@ -3852,26 +3798,19 @@ mDNSexport void DumpPacket(mStatus status, mDNSBool sent, char *transport,
 #pragma mark - Packet Sending Functions
 #endif
 
-#ifdef UNIT_TEST
-// Run the unit test of mDNSSendDNSMessage
-UNITTEST_SENDDNSMESSAGE
-#else
 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
-struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ };
 // Stub definition of UDPSocket_struct so we can access port field. (Rest of UDPSocket_struct is platform-dependent.)
 struct UDPSocket_struct { mDNSIPPort     port;  /* ... */ };
 
 // Note: When we sign a DNS message using DNSDigest_SignMessage(), the current real-time clock value is used, which
 // is why we generally defer signing until we send the message, to ensure the signature is as fresh as possible.
 mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
-                                      mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, 
-                                      mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
-                                      mDNSBool useBackgroundTrafficClass)
+                                      mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst,
+                                      mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass)
 {
     mStatus status = mStatus_NoError;
     const mDNSu16 numAdditionals = msg->h.numAdditionals;
-    mDNSu8 *newend;
-    mDNSu8 *limit = msg->data + AbsoluteMaxDNSMessageData;
 
 #if APPLE_OSX_mDNSResponder
     // maintain outbound packet statistics
@@ -3888,10 +3827,6 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
         return mStatus_BadParamErr;
     }
 
-    newend = putHINFO(m, msg, end, authInfo, limit);
-    if (!newend) LogMsg("mDNSSendDNSMessage: putHINFO failed msg %p end %p, limit %p", msg->data, end, limit); // Not fatal
-    else end = newend;
-
     // Put all the integer values in IETF byte-order (MSB first, LSB second)
     SwapDNSHeaderBytes(msg);
 
@@ -3900,8 +3835,8 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
     else
     {
         // Send the packet on the wire
-        if (!sock)
-            status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, src, dst, dstport, useBackgroundTrafficClass);
+        if (!tcpSrc)
+            status = mDNSPlatformSendUDP(m, msg, end, InterfaceID, udpSrc, dst, dstport, useBackgroundTrafficClass);
         else
         {
             mDNSu16 msglen = (mDNSu16)(end - (mDNSu8 *)msg);
@@ -3910,13 +3845,13 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
             long nsent;
 
             // Try to send them in one packet if we can allocate enough memory
-            buf = mDNSPlatformMemAllocate(msglen + 2);
+            buf = (char *) mDNSPlatformMemAllocate(msglen + 2);
             if (buf)
             {
                 buf[0] = lenbuf[0];
                 buf[1] = lenbuf[1];
                 mDNSPlatformMemCopy(buf+2, msg, msglen);
-                nsent = mDNSPlatformWriteTCP(sock, buf, msglen+2);
+                nsent = mDNSPlatformWriteTCP(tcpSrc, buf, msglen+2);
                 if (nsent != (msglen + 2))
                 {
                     LogMsg("mDNSSendDNSMessage: write message failed %d/%d", nsent, msglen);
@@ -3926,7 +3861,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
             }
             else
             {
-                nsent = mDNSPlatformWriteTCP(sock, (char*)lenbuf, 2);
+                nsent = mDNSPlatformWriteTCP(tcpSrc, (char*)lenbuf, 2);
                 if (nsent != 2)
                 {
                     LogMsg("mDNSSendDNSMessage: write msg length failed %d/%d", nsent, 2);
@@ -3934,7 +3869,7 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
                 }
                 else
                 {
-                    nsent = mDNSPlatformWriteTCP(sock, (char *)msg, msglen);
+                    nsent = mDNSPlatformWriteTCP(tcpSrc, (char *)msg, msglen);
                     if (nsent != msglen)
                     {
                         LogMsg("mDNSSendDNSMessage: write msg body failed %d/%d", nsent, msglen);
@@ -3950,14 +3885,25 @@ mDNSexport mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNS
 
     // Dump the packet with the HINFO and TSIG
     if (mDNS_PacketLoggingEnabled && !mDNSOpaque16IsZero(msg->h.id))
-        DumpPacket(status, mDNStrue, sock && (sock->flags & kTCPSocketFlags_UseTLS) ? "TLS" : sock ? "TCP" : "UDP", mDNSNULL, src ? src->port : MulticastDNSPort, dst, dstport, msg, end);
+    {
+        char *transport = "UDP";
+        mDNSIPPort portNumber = udpSrc ? udpSrc->port : MulticastDNSPort;
+        if (tcpSrc)
+        {
+            if (tcpSrc->flags)
+                transport = "TLS";
+            else
+                transport = "TCP";
+            portNumber = tcpSrc->port;
+        }
+        DumpPacket(status, mDNStrue, transport, mDNSNULL, portNumber, dst, dstport, msg, end, InterfaceID);
+    }
 
     // put the number of additionals back the way it was
     msg->h.numAdditionals = numAdditionals;
 
     return(status);
 }
-#endif // UNIT_TEST
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -4038,9 +3984,9 @@ mDNSlocal mDNSs32 GetNextScheduledEvent(const mDNS *const m)
     if (e - m->NextScheduledSPS      > 0) e = m->NextScheduledSPS;
     if (e - m->NextScheduledKA       > 0) e = m->NextScheduledKA;
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     if (m->NextBonjourDisableTime && (e - m->NextBonjourDisableTime > 0)) e = m->NextBonjourDisableTime;
-#endif // BONJOUR_ON_DEMAND
+#endif
 
     // NextScheduledSPRetry only valid when DelaySleep not set
     if (!m->DelaySleep && m->SleepLimit && e - m->NextScheduledSPRetry > 0) e = m->NextScheduledSPRetry;
@@ -4386,6 +4332,7 @@ decimal:    if (!F.havePrecision)
 
             case 'p':  F.havePrecision = F.lSize = 1;
                 F.precision = sizeof(void*) * 2;                // 8 characters on 32-bit; 16 characters on 64-bit
+                fallthrough();
             case 'X':  digits = kHexDigitsUppercase;
                 goto hexadecimal;
             case 'x':  digits = kHexDigitsLowercase;
@@ -4485,6 +4432,7 @@ hexadecimal: if (F.lSize) n = va_arg(arg, unsigned long);
 
             default:    s = mDNS_VACB;
                 i = mDNS_snprintf(mDNS_VACB, sizeof(mDNS_VACB), "<<UNKNOWN FORMAT CONVERSION CODE %%%c>>", c);
+                break;
 
             case '%':  *sbuffer++ = (char)c;
                 if (++nwritten >= buflen) goto exit;
@@ -4558,3 +4506,4 @@ mDNSexport mDNSu32 mDNS_GetNextResolverGroupID(void)
     if (++lastID == 0) lastID = 1; // Valid resolver group IDs are non-zero.
     return(lastID);
 }
+
index 4291577e88d8290ca311ba953ff2c2799f9154ec..1e422d771e8bf81d12586caa2554d34a91c57cdd 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
@@ -44,15 +44,14 @@ typedef enum
     kDNSFlag0_QR_Query       = 0x00,
     kDNSFlag0_QR_Response    = 0x80,
 
-    kDNSFlag0_OP_Mask        = 0x78,    // Operation type
-    kDNSFlag0_OP_StdQuery    = 0x00,
-    kDNSFlag0_OP_Subscribe   = 0x06,
-    kDNSFlag0_OP_UnSubscribe = 0x07,
-    kDNSFlag0_OP_Iquery      = 0x08,
-    kDNSFlag0_OP_Status      = 0x10,
-    kDNSFlag0_OP_Unused3     = 0x18,
-    kDNSFlag0_OP_Notify      = 0x20,
-    kDNSFlag0_OP_Update      = 0x28,
+    kDNSFlag0_OP_Mask        = 0xF << 3, // Operation type
+    kDNSFlag0_OP_StdQuery    = 0x0 << 3,
+    kDNSFlag0_OP_Iquery      = 0x1 << 3,
+    kDNSFlag0_OP_Status      = 0x2 << 3,
+    kDNSFlag0_OP_Unused3     = 0x3 << 3,
+    kDNSFlag0_OP_Notify      = 0x4 << 3,
+    kDNSFlag0_OP_Update      = 0x5 << 3,
+    kDNSFlag0_OP_DSO         = 0x6 << 3,
 
     kDNSFlag0_QROP_Mask   = kDNSFlag0_QR_Mask | kDNSFlag0_OP_Mask,
 
@@ -76,7 +75,8 @@ typedef enum
     kDNSFlag1_RC_YXRRSet  = 0x07,
     kDNSFlag1_RC_NXRRSet  = 0x08,
     kDNSFlag1_RC_NotAuth  = 0x09,
-    kDNSFlag1_RC_NotZone  = 0x0A
+    kDNSFlag1_RC_NotZone  = 0x0A,
+       kDNSFlag1_RC_DSOTypeNI = 0x0B
 } DNS_Flags;
 
 typedef enum
@@ -118,7 +118,8 @@ extern mDNSu32 mDNS_GetNextResolverGroupID(void);
 // We set the maximum allowable TTL to one hour.
 // With the 25% correction factor to avoid the DNS Zeno's paradox bug, that gives us an actual maximum lifetime of 75 minutes.
 
-#define mDNSMaximumTTLSeconds (mDNSu32)3600
+#define mDNSMaximumMulticastTTLSeconds  (mDNSu32)4500
+#define mDNSMaximumUnicastTTLSeconds    (mDNSu32)3600
 
 #define mDNSValidHostChar(X, notfirst, notlast) (mDNSIsLetter(X) || mDNSIsDigit(X) || ((notfirst) && (notlast) && (X) == '-') )
 
@@ -176,9 +177,11 @@ extern void AppendLabelSuffix(domainlabel *const name, mDNSu32 val, const mDNSBo
 
 extern mDNSu32 RDataHashValue(const ResourceRecord *const rr);
 extern mDNSBool SameRDataBody(const ResourceRecord *const r1, const RDataBody *const r2, DomainNameComparisonFn *samename);
-extern mDNSBool SameNameRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
+extern mDNSBool SameNameCacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q);
 extern mDNSBool ResourceRecordAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-extern mDNSBool AnyTypeRecordAnswersQuestion (const ResourceRecord *const rr, const DNSQuestion *const q);
+extern mDNSBool AuthRecordAnswersQuestion(const AuthRecord *const ar, const DNSQuestion *const q);
+extern mDNSBool CacheRecordAnswersQuestion(const CacheRecord *const cr, const DNSQuestion *const q);
+extern mDNSBool AnyTypeRecordAnswersQuestion (const AuthRecord *const ar, const DNSQuestion *const q);
 extern mDNSBool ResourceRecordAnswersUnicastResponse(const ResourceRecord *const rr, const DNSQuestion *const q);
 extern mDNSBool LocalOnlyRecordAnswersQuestion(AuthRecord *const rr, const DNSQuestion *const q);
 extern mDNSu16 GetRDLength(const ResourceRecord *const rr, mDNSBool estimate);
@@ -235,14 +238,10 @@ extern mDNSu8 *putDeleteAllRRSets(DNSMessage *msg, mDNSu8 *ptr, const domainname
 extern mDNSu8 *putUpdateLease(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease);
 extern mDNSu8 *putUpdateLeaseWithLimit(DNSMessage *msg, mDNSu8 *ptr, mDNSu32 lease, mDNSu8 *limit);
 
-extern mDNSu8 *putHINFO(const mDNS *const m, DNSMessage *const msg, mDNSu8 *ptr, DomainAuthInfo *authInfo, mDNSu8 *limit);
 extern mDNSu8 *putDNSSECOption(DNSMessage *msg, mDNSu8 *end, mDNSu8 *limit);
 extern int baseEncode(char *buffer, int blen, const mDNSu8 *data, int len, int encAlg);
 extern void NSEC3Parse(const ResourceRecord *const rr, mDNSu8 **salt, int *hashLength, mDNSu8 **nxtName, int *bitmaplen, mDNSu8 **bitmap);
 
-extern const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 *AnonData, int AnonDataLen,
-    const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen);
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -269,9 +268,9 @@ extern const mDNSu8 *LocateAdditionals(const DNSMessage *const msg, const mDNSu8
 extern const mDNSu8 *LocateOptRR(const DNSMessage *const msg, const mDNSu8 *const end, int minsize);
 extern const rdataOPT *GetLLQOptData(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end);
 extern mDNSBool GetPktLease(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *const end, mDNSu32 *const lease);
-extern void DumpPacket(mStatus status, mDNSBool sent, char *transport,
-                       const mDNSAddr *srcaddr, mDNSIPPort srcport,
-                       const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end);
+extern void DumpPacket(mStatus status, mDNSBool sent, const char *transport, const mDNSAddr *srcaddr, mDNSIPPort srcport,
+    const mDNSAddr *dstaddr, mDNSIPPort dstport, const DNSMessage *const msg, const mDNSu8 *const end,
+    mDNSInterfaceID interfaceID);
 extern mDNSBool RRAssertsNonexistence(const ResourceRecord *const rr, mDNSu16 type);
 extern mDNSBool RRAssertsExistence(const ResourceRecord *const rr, mDNSu16 type);
 extern mDNSBool BitmapTypeCheck(mDNSu8 *bmap, int bitmaplen, mDNSu16 type);
@@ -284,11 +283,9 @@ extern mDNSu32 swap32(mDNSu32 x);
 #pragma mark -
 #pragma mark - Packet Sending Functions
 #endif
-
 extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,
-                                  mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst, 
-                                  mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,
-                                  mDNSBool useBackgroundTrafficClass);
+                                  mDNSInterfaceID InterfaceID, TCPSocket *tcpSrc, UDPSocket *udpSrc, const mDNSAddr *dst,
+                                  mDNSIPPort dstport, DomainAuthInfo *authInfo, mDNSBool useBackgroundTrafficClass);
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -299,7 +296,7 @@ extern mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *
 extern void ShowTaskSchedulingError(mDNS *const m);
 extern void mDNS_Lock_(mDNS *const m, const char * const functionname);
 extern void mDNS_Unlock_(mDNS *const m, const char * const functionname);
-
+    
 #if defined(_WIN32)
  #define __func__ __FUNCTION__
 #endif
index 57a4012034672061378ecfacc6f6ee20b22cba3b..95df5fd6092c4548fdfcd9a658d180fdb3388abc 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
@@ -570,27 +569,34 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
                          l|=(((unsigned long)(*((c)++)))<< 8),      \
                          l|=(((unsigned long)(*((c)++)))    ),      \
                          l)
-#define HOST_p_c2l(c,l,n)   {                   \
-        switch (n) {                    \
+#define HOST_p_c2l(c,l,n)   {                       \
+        switch (n) {                                \
         case 0: l =((unsigned long)(*((c)++)))<<24; \
+            fallthrough();                          \
         case 1: l|=((unsigned long)(*((c)++)))<<16; \
+            fallthrough();                          \
         case 2: l|=((unsigned long)(*((c)++)))<< 8; \
+            fallthrough();                          \
         case 3: l|=((unsigned long)(*((c)++)));     \
         } }
 #define HOST_p_c2l_p(c,l,sc,len) {                  \
-        switch (sc) {                   \
+        switch (sc) {                               \
         case 0: l =((unsigned long)(*((c)++)))<<24; \
-            if (--len == 0) break;                                                 \
+            if (--len == 0) break;                  \
+            fallthrough();                          \
         case 1: l|=((unsigned long)(*((c)++)))<<16; \
-            if (--len == 0) break;                                                 \
+            if (--len == 0) break;                  \
+            fallthrough();                          \
         case 2: l|=((unsigned long)(*((c)++)))<< 8; \
         } }
 /* NOTE the pointer is not incremented at the end of this */
-#define HOST_c2l_p(c,l,n)   {                   \
-        l=0; (c)+=n;                    \
-        switch (n) {                    \
+#define HOST_c2l_p(c,l,n)   {                       \
+        l=0; (c)+=n;                                \
+        switch (n) {                                \
         case 3: l =((unsigned long)(*(--(c))))<< 8; \
+            fallthrough();                          \
         case 2: l|=((unsigned long)(*(--(c))))<<16; \
+            fallthrough();                          \
         case 1: l|=((unsigned long)(*(--(c))))<<24; \
         } }
 #define _HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)>>24)&0xff),  \
@@ -606,27 +612,34 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
                          l|=(((unsigned long)(*((c)++)))<<16),      \
                          l|=(((unsigned long)(*((c)++)))<<24),      \
                          l)
-#define HOST_p_c2l(c,l,n)   {                   \
-        switch (n) {                    \
+#define HOST_p_c2l(c,l,n)   {                       \
+        switch (n) {                                \
         case 0: l =((unsigned long)(*((c)++)));     \
+            fallthrough();                          \
         case 1: l|=((unsigned long)(*((c)++)))<< 8; \
+            fallthrough();                          \
         case 2: l|=((unsigned long)(*((c)++)))<<16; \
+            fallthrough();                          \
         case 3: l|=((unsigned long)(*((c)++)))<<24; \
         } }
 #define HOST_p_c2l_p(c,l,sc,len) {                  \
-        switch (sc) {                   \
+        switch (sc) {                               \
         case 0: l =((unsigned long)(*((c)++)));     \
-            if (--len == 0) break;                                                 \
+            if (--len == 0) break;                  \
+            fallthrough();                          \
         case 1: l|=((unsigned long)(*((c)++)))<< 8; \
-            if (--len == 0) break;                                                 \
+            if (--len == 0) break;                  \
+            fallthrough();                          \
         case 2: l|=((unsigned long)(*((c)++)))<<16; \
         } }
 /* NOTE the pointer is not incremented at the end of this */
-#define HOST_c2l_p(c,l,n)   {                   \
-        l=0; (c)+=n;                    \
-        switch (n) {                    \
+#define HOST_c2l_p(c,l,n)   {                       \
+        l=0; (c)+=n;                                \
+        switch (n) {                                \
         case 3: l =((unsigned long)(*(--(c))))<<16; \
+            fallthrough();                          \
         case 2: l|=((unsigned long)(*(--(c))))<< 8; \
+            fallthrough();                          \
         case 1: l|=((unsigned long)(*(--(c))));     \
         } }
 #define _HOST_l2c(l,c)  (*((c)++)=(unsigned char)(((l)    )&0xff),  \
@@ -644,6 +657,7 @@ void md5_block_data_order (MD5_CTX *c, const void *p,int num);
 int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
 {
     const unsigned char *data=(const unsigned char *)data_;
+    const unsigned char * const data_end=(const unsigned char *)data_;
     register HASH_LONG * p;
     register unsigned long l;
     int sw,sc,ew,ec;
@@ -667,7 +681,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
         if ((c->num+len) >= HASH_CBLOCK)
         {
             l=p[sw]; HOST_p_c2l(data,l,sc); p[sw++]=l;
-            for (; sw<HASH_LBLOCK; sw++)
+            for (; (sw < HASH_LBLOCK) && ((data_end - data) >= 4); sw++)
             {
                 HOST_c2l(data,l); p[sw]=l;
             }
@@ -691,7 +705,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
                     l=p[sw];
                 HOST_p_c2l(data,l,sc);
                 p[sw++]=l;
-                for (; sw < ew; sw++)
+                for (; (sw < ew) && ((data_end - data) >= 4); sw++)
                 {
                     HOST_c2l(data,l); p[sw]=l;
                 }
@@ -747,7 +761,7 @@ int HASH_UPDATE (HASH_CTX *c, const void *data_, unsigned long len)
         c->num = (int)len;
         ew=(int)(len>>2);   /* words to copy */
         ec=(int)(len&0x03);
-        for (; ew; ew--,p++)
+        for (; ew && ((data_end - data) >= 4); ew--,p++)
         {
             HOST_c2l(data,l); *p=l;
         }
@@ -1040,6 +1054,10 @@ void md5_block_data_order (MD5_CTX *c, const void *data_, int num)
     C=c->C;
     D=c->D;
 
+#if defined(__clang_analyzer__)
+    // Get rid of false positive analyzer warning.
+    for (const unsigned char *_ptr = data; _ptr < &data[num * HASH_CBLOCK]; ++_ptr) {}
+#endif
     for (; num--;)
     {
         HOST_c2l(data,l); X( 0)=l;      HOST_c2l(data,l); X( 1)=l;
@@ -1275,7 +1293,7 @@ mDNSlocal mDNSs32 DNSDigest_Base64ToBin(const char *src, mDNSu8 *target, mDNSu32
 #define HMAC_OPAD   0x5c
 #define MD5_LEN     16
 
-#define HMAC_MD5_AlgName (*(const domainname*) "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int")
+#define HMAC_MD5_AlgName "\010" "hmac-md5" "\007" "sig-alg" "\003" "reg" "\003" "int"
 
 // Adapted from Appendix, RFC 2104
 mDNSlocal void DNSDigest_ConstructHMACKey(DomainAuthInfo *info, const mDNSu8 *key, mDNSu32 len)
@@ -1353,10 +1371,10 @@ mDNSexport void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthI
     MD5_Update(&c, (mDNSu8 *)&tsig.resrec.rroriginalttl, sizeof(tsig.resrec.rroriginalttl));
 
     // alg name
-    AssignDomainName(&tsig.resrec.rdata->u.name, &HMAC_MD5_AlgName);
-    len = DomainNameLength(&HMAC_MD5_AlgName);
+    AssignConstStringDomainName(&tsig.resrec.rdata->u.name, HMAC_MD5_AlgName);
+    len = DomainNameLengthLimit((domainname *)HMAC_MD5_AlgName, (mDNSu8 *)HMAC_MD5_AlgName + sizeof HMAC_MD5_AlgName);
     rdata = tsig.resrec.rdata->u.data + len;
-    MD5_Update(&c, HMAC_MD5_AlgName.c, len);
+    MD5_Update(&c, (mDNSu8 *)HMAC_MD5_AlgName, len);
 
     // time
     // get UTC (universal time), convert to 48-bit unsigned in network byte order
@@ -1437,7 +1455,7 @@ mDNSexport mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeC
 
     algo = (domainname*) ptr;
 
-    if (!SameDomainName(algo, &HMAC_MD5_AlgName))
+    if (!SameDomainName(algo, (domainname *)HMAC_MD5_AlgName))
     {
         LogMsg("ERROR: DNSDigest_VerifyMessage - TSIG algorithm not supported: %##s", algo->c);
         *rcode = kDNSFlag1_RC_NotAuth;
diff --git a/mDNSCore/anonymous.c b/mDNSCore/anonymous.c
deleted file mode 100644 (file)
index 5c138d2..0000000
+++ /dev/null
@@ -1,623 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2013 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.
- */
-
-#include "mDNSEmbeddedAPI.h"
-#include "CryptoAlg.h"
-#include "anonymous.h"
-#include "DNSCommon.h"
-
-// Define ANONYMOUS_DISABLED to remove all the anonymous functionality
-// and use the stub functions implemented later in this file.
-
-#ifndef ANONYMOUS_DISABLED
-
-#define ANON_NSEC3_ITERATIONS        1 
-
-struct AnonInfoResourceRecord_struct
-{
-    ResourceRecord resrec;
-    RData          rdatastorage;
-};
-
-typedef struct AnonInfoResourceRecord_struct AnonInfoResourceRecord;
-
-mDNSlocal mDNSBool InitializeNSEC3Record(ResourceRecord *rr, const mDNSu8 *AnonData, int len, mDNSu32 salt)
-{
-    const mDNSu8 *ptr;
-    rdataNSEC3 *nsec3 = (rdataNSEC3 *)rr->rdata->u.data;
-    mDNSu8 *tmp, *nxt;
-    unsigned short iter = ANON_NSEC3_ITERATIONS;
-    int hlen;
-    const mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
-
-    // Construct the RDATA first and construct the owner name based on that.
-    ptr = (const mDNSu8 *)&salt;
-    debugf("InitializeNSEC3Record: %x%x%x%x, name %##s", ptr[0], ptr[1], ptr[2], ptr[3], rr->name->c);
-
-    // Set the RDATA
-    nsec3->alg = SHA1_DIGEST_TYPE;
-    nsec3->flags = 0;
-    nsec3->iterations = swap16(iter);
-    nsec3->saltLength = 4;
-    tmp = (mDNSu8 *)&nsec3->salt;
-    *tmp++ = ptr[0];
-    *tmp++ = ptr[1];
-    *tmp++ = ptr[2];
-    *tmp++ = ptr[3];
-
-    // hashLength, nxt, bitmap
-    *tmp++ = SHA1_HASH_LENGTH;    // hash length
-    nxt = tmp;
-    tmp += SHA1_HASH_LENGTH;
-    *tmp++ = 0; // window number
-    *tmp++ = NSEC_MCAST_WINDOW_SIZE; // window length
-    mDNSPlatformMemZero(tmp, NSEC_MCAST_WINDOW_SIZE);
-    tmp[kDNSType_PTR >> 3] |= 128 >> (kDNSType_PTR & 7);
-
-    // Hash the base service name + salt + AnonData
-    if (!NSEC3HashName(rr->name, nsec3, AnonData, len, hashName, &hlen))
-    {
-        LogMsg("InitializeNSEC3Record: NSEC3HashName failed for %##s", rr->name->c);
-        return mDNSfalse;
-    }
-    if (hlen != SHA1_HASH_LENGTH)
-    {
-        LogMsg("InitializeNSEC3Record: hlen wrong %d", hlen);
-        return mDNSfalse;
-    }
-    mDNSPlatformMemCopy(nxt, hashName, hlen);
-
-    return mDNStrue;
-}
-
-mDNSlocal ResourceRecord *ConstructNSEC3Record(const domainname *service, const mDNSu8 *AnonData, int len, mDNSu32 salt)
-{
-    ResourceRecord *rr;
-    int dlen;
-    domainname *name;
-
-    // We are just allocating an RData which has StandardAuthRDSize
-    if (StandardAuthRDSize < MCAST_NSEC3_RDLENGTH)
-    {
-        LogMsg("ConstructNSEC3Record: StandardAuthRDSize %d smaller than MCAST_NSEC3_RDLENGTH %d", StandardAuthRDSize, MCAST_NSEC3_RDLENGTH);
-        return mDNSNULL;
-    }
-
-    dlen = DomainNameLength(service);
-    // Allocate space for the name and RData. 
-    rr = mDNSPlatformMemAllocate(sizeof(ResourceRecord) + dlen + sizeof(RData));
-    if (!rr)
-        return mDNSNULL;
-    name = (domainname *)((mDNSu8 *)rr + sizeof(ResourceRecord));
-    rr->RecordType        = kDNSRecordTypePacketAuth;
-    rr->InterfaceID       = mDNSInterface_Any;
-    rr->name              = (const domainname *)name;
-    rr->rrtype            = kDNSType_NSEC3;
-    rr->rrclass           = kDNSClass_IN;
-    rr->rroriginalttl     = kStandardTTL;
-    rr->rDNSServer        = mDNSNULL;
-    rr->rdlength          = MCAST_NSEC3_RDLENGTH;
-    rr->rdestimate        = MCAST_NSEC3_RDLENGTH;
-    rr->rdata             = (RData *)((mDNSu8 *)rr->name + dlen);
-
-    AssignDomainName(name, service);
-    if (!InitializeNSEC3Record(rr, AnonData, len, salt))
-    {
-        mDNSPlatformMemFree(rr);
-        return mDNSNULL;
-    }
-    return rr;
-}
-
-mDNSlocal ResourceRecord *CopyNSEC3ResourceRecord(AnonymousInfo *si, const ResourceRecord *rr)
-{
-    AnonInfoResourceRecord *anonRR;
-    domainname *name;
-    mDNSu32 neededLen;
-    mDNSu32 extraLen;
-
-    if (rr->rdlength < MCAST_NSEC3_RDLENGTH)
-    {
-        LogMsg("CopyNSEC3ResourceRecord: rdlength %d smaller than MCAST_NSEC3_RDLENGTH %d", rr->rdlength, MCAST_NSEC3_RDLENGTH);
-        return mDNSNULL;
-    }
-    // Allocate space for the name and the rdata along with the ResourceRecord
-    neededLen = rr->rdlength + DomainNameLength(rr->name);
-    extraLen = (neededLen > sizeof(RDataBody)) ? (neededLen - sizeof(RDataBody)) : 0;
-    anonRR = (AnonInfoResourceRecord *)mDNSPlatformMemAllocate(sizeof(AnonInfoResourceRecord) + extraLen);
-    if (!anonRR)
-        return mDNSNULL;
-
-    anonRR->resrec = *rr;
-
-    anonRR->rdatastorage.MaxRDLength = rr->rdlength;
-    mDNSPlatformMemCopy(anonRR->rdatastorage.u.data, rr->rdata->u.data, rr->rdlength);
-
-    name = (domainname *)(anonRR->rdatastorage.u.data + rr->rdlength);
-    AssignDomainName(name, rr->name);
-
-    anonRR->resrec.name = name;
-    anonRR->resrec.rdata = &anonRR->rdatastorage;
-
-    si->nsec3RR = (ResourceRecord *)anonRR;
-
-    return si->nsec3RR;
-}
-
-// When a service is started or a browse is started with the Anonymous data, we allocate a new random
-// number and based on that allocate a new NSEC3 resource record whose hash is a function of random number (salt) and
-// the anonymous data.
-//
-// If we receive a packet with the NSEC3 option, we need to cache that along with the resource record so that we can
-// check against the question to see whether it answers them or not. In that case, we pass the "rr" that we received.
-mDNSexport  AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *data, int len, const ResourceRecord *rr)
-{
-    AnonymousInfo *ai;
-    ai = (AnonymousInfo *)mDNSPlatformMemAllocate(sizeof(AnonymousInfo));
-    if (!ai)
-    {
-        return mDNSNULL;
-    }
-    mDNSPlatformMemZero(ai, sizeof(AnonymousInfo));
-    if (rr)
-    {
-        if (!CopyNSEC3ResourceRecord(ai, rr))
-        {
-            mDNSPlatformMemFree(ai);
-            return mDNSNULL;
-        }
-        return ai;
-    }
-    ai->salt = mDNSRandom(0xFFFFFFFF);
-    ai->AnonData = mDNSPlatformMemAllocate(len);
-    if (!ai->AnonData)
-    {
-        mDNSPlatformMemFree(ai);
-        return mDNSNULL;
-    }
-    ai->AnonDataLen = len;
-    mDNSPlatformMemCopy(ai->AnonData, data, len);
-    ai->nsec3RR = ConstructNSEC3Record(service, data, len, ai->salt);
-    if (!ai->nsec3RR)
-    {
-        mDNSPlatformMemFree(ai);
-        return mDNSNULL;
-    }
-    return ai;
-}
-
-mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
-{
-    if (ai->nsec3RR)
-        mDNSPlatformMemFree(ai->nsec3RR);
-    if (ai->AnonData)
-        mDNSPlatformMemFree(ai->AnonData);
-    mDNSPlatformMemFree(ai);
-}
-
-mDNSexport void ReInitAnonInfo(AnonymousInfo **AnonInfo, const domainname *name)
-{
-    if (*AnonInfo)
-    {
-        AnonymousInfo *ai = *AnonInfo;
-        *AnonInfo = AllocateAnonInfo(name, ai->AnonData, ai->AnonDataLen, mDNSNULL);
-        if (!(*AnonInfo))
-            *AnonInfo = ai;
-        else
-            FreeAnonInfo(ai);
-    }
-}
-
-// This function should be used only if you know that the question and
-// the resource record belongs to the same set. The main usage is
-// in ProcessQuery where we find the question to be part of the same
-// set as the resource record, but it needs the AnonData to be
-// initialized so that it can walk the cache records to see if they
-// answer the question.
-mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
-{
-    if (!q->AnonInfo || !rr->AnonInfo)
-    {
-        LogMsg("SetAnonData: question %##s(%p), rr %##s(%p), NULL", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
-        return;
-    }
-    
-    debugf("SetAnonData: question %##s(%p), rr %##s(%p)", q->qname.c, q->AnonInfo, rr->name->c, rr->AnonInfo);
-    if (ForQuestion)
-    {
-        if (q->AnonInfo->AnonDataLen < rr->AnonInfo->AnonDataLen)
-        {
-            mDNSPlatformMemFree(q->AnonInfo->AnonData);
-            q->AnonInfo->AnonData = mDNSNULL;
-        }
-
-        if (!q->AnonInfo->AnonData)
-        {
-            q->AnonInfo->AnonData = mDNSPlatformMemAllocate(rr->AnonInfo->AnonDataLen);
-            if (!q->AnonInfo->AnonData)
-                return;
-        }
-        mDNSPlatformMemCopy(q->AnonInfo->AnonData, rr->AnonInfo->AnonData, rr->AnonInfo->AnonDataLen);
-        q->AnonInfo->AnonDataLen = rr->AnonInfo->AnonDataLen;
-    }
-    else
-    {
-        if (rr->AnonInfo->AnonDataLen < q->AnonInfo->AnonDataLen)
-        {
-            mDNSPlatformMemFree(rr->AnonInfo->AnonData);
-            rr->AnonInfo->AnonData = mDNSNULL;
-        }
-
-        if (!rr->AnonInfo->AnonData)
-        {
-            rr->AnonInfo->AnonData = mDNSPlatformMemAllocate(q->AnonInfo->AnonDataLen);
-            if (!rr->AnonInfo->AnonData)
-                return;
-        }
-        mDNSPlatformMemCopy(rr->AnonInfo->AnonData, q->AnonInfo->AnonData, q->AnonInfo->AnonDataLen);
-        rr->AnonInfo->AnonDataLen = q->AnonInfo->AnonDataLen;
-    }
-}
-
-// returns -1 if the caller should ignore the result
-// returns 1 if the record answers the question
-// returns 0 if the record does not answer the question
-mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-{
-    mDNSexport mDNS mDNSStorage;
-    ResourceRecord *nsec3RR;
-    int i;
-    AnonymousInfo *qai, *rai;
-    mDNSu8 *AnonData;
-    int AnonDataLen;
-    rdataNSEC3 *nsec3;
-    int hlen;
-    int nxtLength;
-    mDNSu8 *nxtName;
-    mDNSu8 hashName[NSEC3_MAX_HASH_LEN];
-    mDNSPlatformMemZero(hashName, sizeof(hashName));
-
-    debugf("AnonInfoAnswersQuestion: question qname %##s", q->qname.c);
-
-    // Currently only PTR records can have anonymous information
-    if (q->qtype != kDNSType_PTR)
-    {
-        return -1;
-    }
-
-    // We allow anonymous questions to be answered by both normal services (without the
-    // anonymous information) and anonymous services that are part of the same set. And
-    // normal questions discover normal services and all anonymous services. 
-    //
-    // The three cases have been enumerated clearly even though they all behave the
-    // same way.
-    if (!q->AnonInfo)
-    {
-        debugf("AnonInfoAnswersQuestion: not a anonymous type question");
-        if (!rr->AnonInfo)
-        {
-            // case 1
-            return -1;
-        }
-        else
-        {
-            // case 2
-            debugf("AnonInfoAnswersQuestion: Question %##s not answered using anonymous record %##s", q->qname.c, rr->name->c);
-            return -1;
-        }
-    }
-    else
-    {
-        // case 3
-        if (!rr->AnonInfo)
-        {
-            debugf("AnonInfoAnswersQuestion: not a anonymous type record");
-            return -1;
-        }
-    }
-
-    // case 4: We have the anonymous information both in the question and the record. We need
-    // two sets of information to validate.
-    //
-    // 1) Anonymous data that identifies the set/group
-    // 2) NSEC3 record that contains the hash and the salt
-    //
-    // If the question is a remote one, it does not have the anonymous information to validate (just
-    // the NSEC3 record) and hence the anonymous data should come from the local resource record. If the
-    // question is local, it can come from either of them and if there is a mismatch between the
-    // question and record, it won't validate.
-
-    qai = q->AnonInfo;
-    rai = rr->AnonInfo;
-
-    if (qai->AnonData && rai->AnonData)
-    {
-        // Before a cache record is created, if there is a matching question i.e., part
-        // of the same set, then when the cache is created we also set the anonymous
-        // information. Otherwise, the cache record contains just the NSEC3 record and we
-        // won't be here for that case.
-        //
-        // It is also possible that a local question is matched against the local AuthRecord
-        // as that is also the case for which the AnonData would be non-NULL for both.
-        // We match questions against AuthRecords (rather than the cache) for LocalOnly case and 
-        // to see whether a .local query should be suppressed or not. The latter never happens
-        // because PTR queries are never suppressed.
-
-        // If they don't belong to the same anonymous set, then no point in validating.
-        if ((qai->AnonDataLen != rai->AnonDataLen) ||
-            mDNSPlatformMemCmp(qai->AnonData, rai->AnonData, qai->AnonDataLen) != 0)
-        {
-            debugf("AnonInfoAnswersQuestion: AnonData mis-match for record  %s question %##s ",
-                RRDisplayString(&mDNSStorage, rr), q->qname.c);
-            return 0;
-        }
-        // AnonData matches i.e they belong to the same group and the same service.
-        LogInfo("AnonInfoAnswersQuestion: Answering qname %##s, rname %##s, without validation", q->qname.c,
-            rr->name->c);
-        return 1;
-    }
-    else
-    {
-        debugf("AnonInfoAnswersQuestion: question %p, record %p", qai->AnonData, rai->AnonData);
-    }
-
-    if (qai->AnonData)
-    {
-        // If there is AnonData, then this is a local question. The
-        // NSEC3 RR comes from the resource record which could be part
-        // of the cache or local auth record. The cache entry could
-        // be from a remote host or created when we heard our own 
-        // announcements. In any case, we use that to see if it matches
-        // the question.
-        AnonData = qai->AnonData;
-        AnonDataLen = qai->AnonDataLen;
-        nsec3RR = rai->nsec3RR;
-    }
-    else
-    {
-        // Remote question or hearing our own question back
-        AnonData = rai->AnonData;
-        AnonDataLen = rai->AnonDataLen;
-        nsec3RR = qai->nsec3RR;
-    }
-
-    if (!AnonData || !nsec3RR)
-    {
-        // AnonData can be NULL for the cache entry and if we are hearing our own question back, AnonData is NULL for
-        // that too and we can end up here for that case.
-        debugf("AnonInfoAnswersQuestion: AnonData %p or nsec3RR %p, NULL for question %##s, record %s", AnonData, nsec3RR,
-            q->qname.c, RRDisplayString(&mDNSStorage, rr));
-        return 0;
-    }
-    debugf("AnonInfoAnswersQuestion: Validating question %##s, ResourceRecord %s", q->qname.c, RRDisplayString(&mDNSStorage, nsec3RR));
-
-
-    nsec3 = (rdataNSEC3 *)nsec3RR->rdata->u.data;
-
-    if (!NSEC3HashName(nsec3RR->name, nsec3, AnonData, AnonDataLen, hashName, &hlen))
-    {
-        LogMsg("AnonInfoAnswersQuestion: NSEC3HashName failed for %##s", nsec3RR->name->c);
-        return mDNSfalse;
-    }
-    if (hlen != SHA1_HASH_LENGTH)
-    {
-        LogMsg("AnonInfoAnswersQuestion: hlen wrong %d", hlen);
-        return mDNSfalse;
-    }
-
-    NSEC3Parse(nsec3RR, mDNSNULL, &nxtLength, &nxtName, mDNSNULL, mDNSNULL);
-
-    if (hlen != nxtLength)
-    {
-        LogMsg("AnonInfoAnswersQuestion: ERROR!! hlen %d not same as nxtLength %d", hlen, nxtLength);
-        return mDNSfalse;
-    }
-
-    for (i = 0; i < nxtLength; i++)
-    {
-        if (nxtName[i] != hashName[i])
-        {
-            debugf("AnonInfoAnswersQuestion: mismatch output %x, digest %x, i %d", nxtName[i+1], hashName[i], i);
-            return 0;
-        }
-    }
-    LogInfo("AnonInfoAnswersQuestion: ResourceRecord %s matched question %##s (%s)", RRDisplayString(&mDNSStorage, nsec3RR), q->qname.c, DNSTypeName(q->qtype));
-    return 1;
-}
-
-// Find a matching NSEC3 record for the name. We parse the questions and the records in the packet in order.
-// Similarly we also parse the NSEC3 records in order and this mapping to the questions and records
-// respectively.
-mDNSlocal CacheRecord *FindMatchingNSEC3ForName(mDNS *const m, CacheRecord **nsec3, const domainname *name)
-{
-    CacheRecord *cr;
-    CacheRecord **prev = nsec3;
-    
-    (void) m;
-
-    for (cr = *nsec3; cr; cr = cr->next)
-    {
-        if (SameDomainName(cr->resrec.name, name))
-        {
-            debugf("FindMatchingNSEC3ForName: NSEC3 record %s matched %##s", CRDisplayString(m, cr), name->c);
-            *prev = cr->next;
-            cr->next = mDNSNULL;
-            return cr;
-        }
-        prev = &cr->next;
-    }
-    return mDNSNULL;
-}
-
-mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
-{
-    CacheRecord *nsec3CR;
-
-    if (q->qtype != kDNSType_PTR)
-        return;
-
-    nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, &q->qname);
-    if (nsec3CR)
-    {
-        q->AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
-        if (q->AnonInfo)
-        {
-            debugf("InitializeAnonInfoForQuestion: Found a matching NSEC3 record %s, for %##s (%s)",
-                RRDisplayString(m, q->AnonInfo->nsec3RR), q->qname.c, DNSTypeName(q->qtype));
-        }
-        ReleaseCacheRecord(m, nsec3CR);
-    }
-}
-
-mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
-{
-    CacheRecord *nsec3CR;
-
-    if (!(*McastNSEC3Records))
-        return;
-
-    // If already initialized or not a PTR type, we don't have to do anything
-    if (cr->resrec.AnonInfo || cr->resrec.rrtype != kDNSType_PTR)
-        return;
-
-    nsec3CR = FindMatchingNSEC3ForName(m, McastNSEC3Records, cr->resrec.name);
-    if (nsec3CR)
-    {
-        cr->resrec.AnonInfo = AllocateAnonInfo(mDNSNULL, mDNSNULL, 0, &nsec3CR->resrec);
-        if (cr->resrec.AnonInfo)
-        {
-            debugf("InitializeAnonInfoForCR: Found a matching NSEC3 record %s, for %##s (%s)",
-                RRDisplayString(m, cr->resrec.AnonInfo->nsec3RR), cr->resrec.name->c,
-                DNSTypeName(cr->resrec.rrtype));
-        }
-        ReleaseCacheRecord(m, nsec3CR);
-    }
-}
-
-mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
-{
-    // if a1 is NULL and a2 is not NULL AND vice-versa
-    // return false as there is a change.
-    if ((a1 != mDNSNULL) != (a2 != mDNSNULL))
-        return mDNSfalse;
-
-    // Both could be NULL or non-NULL
-    if (a1 && a2)
-    {
-        // The caller already verified that the owner name is the same.
-        // Check whether the RData is same.
-        if (!IdenticalSameNameRecord(a1->nsec3RR, a2->nsec3RR))
-        {
-            debugf("IdenticalAnonInfo: nsec3RR mismatch");
-            return mDNSfalse;
-        }
-    }
-    return mDNStrue;
-}
-
-mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
-{
-    AnonymousInfo *aifrom = crfrom->resrec.AnonInfo;
-    AnonymousInfo *aito = crto->resrec.AnonInfo;
-
-    (void) m;
-
-    if (!aifrom)
-        return;
-
-    if (aito)
-    {
-        crto->resrec.AnonInfo = aifrom;
-        FreeAnonInfo(aito);
-        crfrom->resrec.AnonInfo = mDNSNULL;
-    }
-    else
-    {
-        FreeAnonInfo(aifrom);
-        crfrom->resrec.AnonInfo = mDNSNULL;
-    }
-}
-
-#else // !ANONYMOUS_DISABLED
-
-mDNSexport void ReInitAnonInfo(AnonymousInfo **si, const domainname *name)
-{
-       (void)si;
-       (void)name;
-}
-
-mDNSexport AnonymousInfo * AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr)
-{
-       (void)service;
-       (void)AnonData;
-       (void)len;
-       (void)rr;
-
-       return mDNSNULL;
-}
-
-mDNSexport void FreeAnonInfo(AnonymousInfo *ai)
-{
-       (void)ai;
-}
-
-mDNSexport void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion)
-{
-       (void)q;
-       (void)rr;
-       (void)ForQuestion;
-}
-
-mDNSexport int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q)
-{
-       (void)rr;
-       (void)q;
-
-       return mDNSfalse;
-}
-
-mDNSexport void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q)
-{
-       (void)m;
-       (void)McastNSEC3Records;
-       (void)q;
-}
-
-mDNSexport void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr)
-{
-       (void)m;
-       (void)McastNSEC3Records;
-       (void)cr;
-}
-
-mDNSexport void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom)
-{
-       (void)m;
-       (void)crto;
-       (void)crfrom;
-}
-
-mDNSexport mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2)
-{
-       (void)a1;
-       (void)a2;
-
-       return mDNStrue;
-}
-
-#endif // !ANONYMOUS_DISABLED
diff --git a/mDNSCore/anonymous.h b/mDNSCore/anonymous.h
deleted file mode 100644 (file)
index b60812e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 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.
- */
-
-#ifndef __ANONYMOUS_H_
-#define __ANONYMOUS_H_
-
-extern void ReInitAnonInfo(AnonymousInfo **si, const domainname *name);
-extern AnonymousInfo *AllocateAnonInfo(const domainname *service, const mDNSu8 *AnonData, int len, const ResourceRecord *rr);
-extern void FreeAnonInfo(AnonymousInfo *ai);
-extern void SetAnonData(DNSQuestion *q, ResourceRecord *rr, mDNSBool ForQuestion);
-extern int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-extern void InitializeAnonInfoForCR(mDNS *const m, CacheRecord **McastNSEC3Records, CacheRecord *cr);
-extern void InitializeAnonInfoForQuestion(mDNS *const m, CacheRecord **McastNSEC3Records, DNSQuestion *q);
-extern void CopyAnonInfoForCR(mDNS *const m, CacheRecord *crto, CacheRecord *crfrom);
-extern mDNSBool IdenticalAnonInfo(AnonymousInfo *a1, AnonymousInfo *a2);
-
-#endif
index a94c005e71de6219d77975aa79cbffa15d37f2d0..120d2fc4cb09b54cf4b6758c731e4d5bb78e9069 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2019 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.
@@ -19,7 +19,7 @@
 
 #ifndef UNICAST_DISABLED
 
-mDNSexport mDNS mDNSStorage;
+extern mDNS mDNSStorage;
 
 // Implementation Notes
 //
@@ -245,7 +245,7 @@ again:
         pc->q.ValidatingResponse = 1;
     for (cr = cg->members; cr; cr = cr->next)
     {
-        if (SameNameRecordAnswersQuestion(&cr->resrec, &pc->q))
+        if (SameNameCacheRecordAnswersQuestion(cr, &pc->q))
         {
             if (first)
             {
@@ -473,11 +473,11 @@ mDNSlocal void ProxyClientCallback(mDNS *const m, DNSQuestion *question, const R
 
     if (!pc->tcp)
     {
-        mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, (UDPSocket *)pc->socket, &pc->addr, pc->port, mDNSNULL, mDNSNULL, mDNSfalse);
+        mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, mDNSNULL, (UDPSocket *)pc->socket, &pc->addr, pc->port, mDNSNULL, mDNSfalse);
     }
     else
     {
-        mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, mDNSNULL, &pc->addr, pc->port, (TCPSocket *)pc->socket, mDNSNULL, mDNSfalse);
+        mDNSSendDNSMessage(m, &m->omsg, ptr, pc->interfaceID, (TCPSocket *)pc->socket, mDNSNULL, &pc->addr, pc->port, mDNSNULL, mDNSfalse);
     }
 
 done:
@@ -515,13 +515,11 @@ mDNSlocal void SendError(void *socket, DNSMessage *const msg, const mDNSu8 *cons
     
     if (!tcp)
     {
-        mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, socket, dstaddr, dstport, mDNSNULL, mDNSNULL,
-            mDNSfalse);
+        mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, mDNSNULL, socket, dstaddr, dstport, mDNSNULL, mDNSfalse);
     }
     else
     {
-        mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, mDNSNULL, dstaddr, dstport, (TCPSocket *)socket,
-            mDNSNULL, mDNSfalse);
+        mDNSSendDNSMessage(m, &m->omsg, (mDNSu8 *)&m->omsg + pktlen, InterfaceID, (TCPSocket *)socket, mDNSNULL, dstaddr, dstport, mDNSNULL, mDNSfalse);
     }
     mDNSPlatformDisposeProxyContext(context);
 }
@@ -662,13 +660,12 @@ mDNSlocal void ProxyCallbackCommon(void *socket, DNSMessage *const msg, const mD
         LogInfo("ProxyCallbackCommon: Found a duplicate for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
         return;
     }
-    pc = mDNSPlatformMemAllocate(sizeof(DNSProxyClient));
+    pc = (DNSProxyClient *) mDNSPlatformMemAllocateClear(sizeof(*pc));
     if (!pc)
     {
         LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
         return;
     }
-    mDNSPlatformMemZero(pc, sizeof(DNSProxyClient));
     pc->addr = *srcaddr;
     pc->port = srcport;
     pc->msgid = msg->h.id;
@@ -686,7 +683,7 @@ mDNSlocal void ProxyCallbackCommon(void *socket, DNSMessage *const msg, const mD
         }
         else
         {
-            pc->optRR = mDNSPlatformMemAllocate(optLen);
+            pc->optRR = (mDNSu8 *) mDNSPlatformMemAllocate(optLen);
             if (!pc->optRR)
             {
                 LogMsg("ProxyCallbackCommon: Memory failure for pkt from %#a:%d, ignoring this", srcaddr, mDNSVal16(srcport));
index 3010d6f24c7133c5f42a684bd4462f5e3f628f58..0766582131fc2de28836bbd6b7d63a1ca624f596 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2019 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.
@@ -225,7 +225,7 @@ mDNSexport int DNSSECCanonicalOrder(const domainname *const d1, const domainname
         return 0;
 }
 
-// Initialize the question enough so that it can be answered from the cache using SameNameRecordAnswersQuestion or
+// Initialize the question enough so that it can be answered from the cache using SameNameCacheRecordAnswersQuestion or
 // ResourceRecordAnswersQuestion.
 mDNSexport void InitializeQuestion(mDNS *const m, DNSQuestion *question, mDNSInterfaceID InterfaceID, const domainname *qname,
                                    mDNSu16 qtype, mDNSQuestionCallback *callback, void *context)
@@ -259,9 +259,8 @@ mDNSexport DNSSECVerifier *AllocateDNSSECVerifier(mDNS *const m, const domainnam
 {
     DNSSECVerifier *dv;
 
-    dv = (DNSSECVerifier *)mDNSPlatformMemAllocate(sizeof(DNSSECVerifier));
+    dv = (DNSSECVerifier *) mDNSPlatformMemAllocateClear(sizeof(*dv));
     if (!dv) { LogMsg("AllocateDNSSECVerifier: ERROR!! memory alloc failed"); return mDNSNULL; }
-    mDNSPlatformMemZero(dv, sizeof(*dv));
 
     LogDNSSEC("AllocateDNSSECVerifier called %p", dv);
 
@@ -297,13 +296,13 @@ mDNSlocal AuthChain *AuthChainCopy(AuthChain *ae)
 
     while (ae)
     {
-        ac = mDNSPlatformMemAllocate(sizeof(AuthChain));
+        ac = (AuthChain *) mDNSPlatformMemAllocateClear(sizeof(*ac));
         if (!ac)
         {
             LogMsg("AuthChainCopy: AuthChain alloc failure");
             if (retac)
                 FreeDNSSECAuthChainInfo(retac);
-            return mDNSfalse;
+            return mDNSNULL;
         }
 
         ac->next  = mDNSNULL;
@@ -496,7 +495,7 @@ mDNSlocal RRVerifier* CopyRRVerifier(RRVerifier *from)
 {
     RRVerifier *r;
 
-    r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + from->rdlength);
+    r = (RRVerifier *) mDNSPlatformMemAllocate(sizeof(*r) + from->rdlength);
     if (!r)
     {
         LogMsg("CopyRRVerifier: memory failure");
@@ -513,7 +512,7 @@ mDNSexport RRVerifier* AllocateRRVerifier(const ResourceRecord *const rr, mStatu
 {
     RRVerifier *r;
 
-    r = mDNSPlatformMemAllocate(sizeof (RRVerifier) + rr->rdlength);
+    r = (RRVerifier *) mDNSPlatformMemAllocateClear(sizeof(*r) + rr->rdlength);
     if (!r)
     {
         LogMsg("AllocateRRVerifier: memory failure");
@@ -1967,19 +1966,17 @@ mDNSlocal mDNSBool ValidateSignatureWithKey(DNSSECVerifier *dv, RRVerifier *rrse
         nrrsets++;
 
     tmp = rrset;
-    start = ptr = mDNSPlatformMemAllocate(nrrsets * sizeof (rdataComp));
+    start = ptr = (rdataComp *) mDNSPlatformMemAllocateClear(nrrsets * sizeof(rdataComp));
     debugdnssec("ValidateSignatureWithKey: start %p, nrrsets %d", start, nrrsets);
     if (ptr)
     {
-        // Need to initialize for failure case below
-        mDNSPlatformMemZero(ptr, nrrsets * (sizeof (rdataComp)));
         while (tmp)
         {
             ptr->rdlength = tmp->rdlength;
             ptr->rrtype = tmp->rrtype;
             if (ptr->rdlength)
             {
-                ptr->rdata = mDNSPlatformMemAllocate(ptr->rdlength);
+                ptr->rdata = (mDNSu8 *) mDNSPlatformMemAllocate(ptr->rdlength);
                 if (ptr->rdata)
                 {
                     mDNSPlatformMemCopy(ptr->rdata, tmp->rdata, tmp->rdlength);
@@ -2286,7 +2283,7 @@ mDNSlocal mDNSBool AuthChainAdd(DNSSECVerifier *dv, RRVerifier *resultKey, RRVer
         return mDNSfalse;
     }
 
-    ae = mDNSPlatformMemAllocate(sizeof(AuthChain));
+    ae = (AuthChain *) mDNSPlatformMemAllocateClear(sizeof(*ae));
     if (!ae)
     {
         LogMsg("AuthChainAdd: AuthChain alloc failure");
@@ -2368,7 +2365,7 @@ mDNSlocal void SetTTLRRSet(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus statu
     }
 
     for (rr = cg->members; rr; rr = rr->next)
-        if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
+        if (SameNameCacheRecordAnswersQuestion(rr, &question))
         {
             // originalttl is never touched. The actual TTL is derived based on when it was
             // received.
@@ -2496,7 +2493,7 @@ mDNSlocal void SetTTLRRSet(mDNS *const m, DNSSECVerifier *dv, DNSSECStatus statu
     // Find the RRset and set its TTL
     for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
     {
-        if (SameNameRecordAnswersQuestion(&rr->resrec, &question))
+        if (SameNameCacheRecordAnswersQuestion(rr, &question))
         {
             LogDNSSEC("SetTTLRRSet: Setting the TTL %d for %s, question %##s (%s)", rrTTL, CRDisplayString(m, rr),
                       question.qname.c, DNSTypeName(rr->resrec.rrtype));
@@ -2709,7 +2706,7 @@ mDNSlocal void DNSSECNoResponse(mDNS *const m, DNSSECVerifier *dv)
     // RRSIGs that can match the original question
     for (cr = cg->members; cr; cr = cr->next)
     {
-        if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
+        if (SameNameCacheRecordAnswersQuestion(cr, &dv->q))
         {
             answer = &cr->resrec;
             break;
@@ -3057,7 +3054,7 @@ mDNSlocal void DNSSECValidationCB(mDNS *const m, DNSSECVerifier *dv, DNSSECStatu
     dv->q.ValidatingResponse = mDNSfalse;
     for (cr = cg->members; cr; cr = cr->next)
     {
-        if (SameNameRecordAnswersQuestion(&cr->resrec, &dv->q))
+        if (SameNameCacheRecordAnswersQuestion(cr, &dv->q))
         {
             if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
                 DNSSECNegativeValidationCB(m, dv, cg, &cr->resrec, status);
@@ -3107,7 +3104,7 @@ mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *
 
     // Walk the cache and get all the rrsets for verification.
     for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-        if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+        if (SameNameCacheRecordAnswersQuestion(rr, q))
         {
             // We also get called for RRSIGs which matches qtype. We don't need that here as we are
             // building rrset for matching q->qname. Checking for RRSIG type is important as otherwise
@@ -3834,10 +3831,10 @@ mDNSexport void ProveInsecure(mDNS *const m, DNSSECVerifier *dv, InsecureContext
 
     if (ic == mDNSNULL)
     {
-        ic = (InsecureContext *)mDNSPlatformMemAllocate(sizeof(InsecureContext));
+        ic = (InsecureContext *) mDNSPlatformMemAllocateClear(sizeof(*ic));
         if (!ic)
         {
-            LogMsg("mDNSPlatformMemAllocate: ERROR!! memory alloc failed for ic");
+            LogMsg("mDNSPlatformMemAllocateClear: ERROR!! memory alloc failed for ic");
             return;
         }
         
index b770af8de0a9e6a032302c03c22e49b6433cfed3..c34ad678d78277982316b82d3ffb17f8d31a43c7 100644 (file)
@@ -19,7 +19,6 @@
 #define __DNSSEC_H
 
 #include "CryptoAlg.h"
-#include "mDNSDebug.h"
 
 typedef enum
 {
index 4e70ef8374f8765bd2aa58cecac9a3807bcdbd62..4ec1934f365e4735956942bbf4f2d26ca4b21db0 100755 (executable)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
 #include "uDNS.h"                       // Defines entry points into unicast-specific routines
 #include "nsec.h"
 #include "dnssec.h"
-#include "anonymous.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#include "SymptomReporter.h"
+#endif
 
 // Disable certain benign warnings with Microsoft compilers
 #if (defined(_MSC_VER))
 #include "dns_sd_internal.h"
 
 #if APPLE_OSX_mDNSResponder
-#include <WebFilterDNS/WebFilterDNS.h>
-
 // Delay in seconds before disabling multicast after there are no active queries or registrations.
 #define BONJOUR_DISABLE_DELAY 60
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
 
-#if !NO_WCF
 WCFConnection *WCFConnectionNew(void) __attribute__((weak_import));
 void WCFConnectionDealloc(WCFConnection* c) __attribute__((weak_import));
+#endif
 
-// Do we really need to define a macro for "if"?
-#define CHECK_WCF_FUNCTION(X) if (X)
-#endif // ! NO_WCF
-
-#else
-
-#define NO_WCF 1
-#endif // APPLE_OSX_mDNSResponder
-
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
 #include "Metrics.h"
 #endif
 
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
 #include "DNS64.h"
 #endif
 
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
-
 // Forward declarations
 mDNSlocal void BeginSleepProcessing(mDNS *const m);
 mDNSlocal void RetrySPSRegistrations(mDNS *const m);
@@ -89,14 +85,18 @@ mDNSlocal void mDNS_SendKeepalives(mDNS *const m);
 mDNSlocal void mDNS_ExtractKeepaliveInfo(AuthRecord *ar, mDNSu32 *timeout, mDNSAddr *laddr, mDNSAddr *raddr, mDNSEthAddr *eth,
                                          mDNSu32 *seq, mDNSu32 *ack, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu16 *win);
 
-mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m);
-mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m);
+typedef mDNSu32 DeadvertiseFlags;
+#define kDeadvertiseFlag_NormalHostname (1U << 0)
+#define kDeadvertiseFlag_RandHostname   (1U << 1)
+#define kDeadvertiseFlag_All            (kDeadvertiseFlag_NormalHostname | kDeadvertiseFlag_RandHostname)
+
+mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, DeadvertiseFlags flags);
+mDNSlocal void AdvertiseInterfaceIfNeeded(mDNS *const m, NetworkInterfaceInfo *set);
 mDNSlocal void FreeNSECRecords(mDNS *const m, CacheRecord *NSECRecords);
 mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
                                         const mDNSInterfaceID InterfaceID, CacheRecord **NSEC3Records);
 mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *eth);
 
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark - Program Constants
@@ -105,8 +105,6 @@ mDNSlocal mDNSu8 *GetValueForMACAddr(mDNSu8 *ptr, mDNSu8 *limit, mDNSEthAddr *et
 // To Turn OFF mDNS_Tracer set MDNS_TRACER to 0 or undef it
 #define MDNS_TRACER 1
 
-#define NO_HINFO 1
-
 // Any records bigger than this are considered 'large' records
 #define SmallRecordLimit 1024
 
@@ -174,6 +172,87 @@ mDNSexport const char *const mDNS_DomainTypeNames[] =
 #pragma mark - General Utility Functions
 #endif
 
+#if MDNS_MALLOC_DEBUGGING
+// When doing memory allocation debugging, this function traverses all lists in the mDNS query
+// structures and caches and checks each entry in the list to make sure it's still good.
+mDNSlocal void mDNS_ValidateLists(void *context)
+{
+    mDNS *m = context;
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+    mDNSu32 NumAllInterfaceRecords   = 0;
+    mDNSu32 NumAllInterfaceQuestions = 0;
+#endif
+
+    // Check core mDNS lists
+    AuthRecord                  *rr;
+    for (rr = m->ResourceRecords; rr; rr=rr->next)
+    {
+        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)
+            LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
+                             rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+        if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
+#endif
+    }
+
+    for (rr = m->DuplicateRecords; rr; rr=rr->next)
+    {
+        if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
+            LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+        if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
+#endif
+    }
+
+    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->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0)
+            LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
+        if (q->DuplicateOf && q->LocalSocket)
+            LogMemCorruption("Questions list: Duplicate Question %p should not have LocalSocket set %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+        if (!LocalOnlyOrP2PInterface(q->InterfaceID) && mDNSOpaque16IsZero(q->TargetQID))
+            NumAllInterfaceQuestions++;
+#endif
+    }
+
+    CacheGroup                  *cg;
+    CacheRecord                 *cr;
+    mDNSu32 slot;
+    FORALL_CACHERECORDS(slot, cg, cr)
+    {
+        if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
+            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));
+        }
+    }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+    if (m->NumAllInterfaceRecords != NumAllInterfaceRecords)
+       LogMemCorruption("NumAllInterfaceRecords is %d should be %d", m->NumAllInterfaceRecords, NumAllInterfaceRecords);
+    
+    if (m->NumAllInterfaceQuestions != NumAllInterfaceQuestions)
+       LogMemCorruption("NumAllInterfaceQuestions is %d should be %d", m->NumAllInterfaceQuestions, NumAllInterfaceQuestions);
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+}
+#endif // MDNS_MALLOC_DEBUGGING
+
 // Returns true if this is a  unique, authoritative LocalOnly record that answers questions of type 
 // A, AAAA , CNAME, or PTR.  The caller should answer the question with this record and not send out 
 // the question on the wire if LocalOnlyRecordAnswersQuestion() also returns true.
@@ -209,7 +288,7 @@ mDNSexport void SetNextQueryTime(mDNS *const m, const DNSQuestion *const q)
 
 mDNSlocal void ReleaseAuthEntity(AuthHash *r, AuthEntity *e)
 {
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
     unsigned int i;
     for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
 #endif
@@ -243,7 +322,7 @@ mDNSlocal AuthEntity *GetAuthEntity(AuthHash *r, const AuthGroup *const Preserve
         // free them all individually which normally happens when we parse /etc/hosts into
         // AuthHash where we add the "new" entries and discard (free) the already added
         // entries. If we allocate as chunks, we can't free them individually.
-        AuthEntity *storage = mDNSPlatformMemAllocate(sizeof(AuthEntity));
+        AuthEntity *storage = (AuthEntity *) mDNSPlatformMemAllocateClear(sizeof(*storage));
         storage->next = mDNSNULL;
         r->rrauth_free = storage;
     }
@@ -314,7 +393,7 @@ mDNSlocal AuthGroup *GetAuthGroup(AuthHash *r, const ResourceRecord *const rr)
     ag->rrauth_tail  = &ag->members;
     ag->NewLocalOnlyRecords = mDNSNULL;
     if (namelen > sizeof(ag->namestorage))
-        ag->name = mDNSPlatformMemAllocate(namelen);
+        ag->name = (domainname *) mDNSPlatformMemAllocate(namelen);
     else
         ag->name = (domainname*)ag->namestorage;
     if (!ag->name)
@@ -452,14 +531,17 @@ mDNSexport char *InterfaceNameForID(mDNS *const m, const mDNSInterfaceID Interfa
 }
 
 // Caller should hold the lock
-mDNSlocal void GenerateNegativeResponse(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc)
+mDNSlocal void GenerateNegativeResponseEx(mDNS *const m, mDNSInterfaceID InterfaceID, QC_result qc, mDNSBool noData)
 {
     DNSQuestion *q;
     if (!m->CurrentQuestion) { LogMsg("GenerateNegativeResponse: ERROR!! CurrentQuestion not set"); return; }
     q = m->CurrentQuestion;
-    LogInfo("GenerateNegativeResponse: Generating negative response for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d->Q%d] GenerateNegativeResponse: Generating negative response for question " PRI_DM_NAME " (" PUB_S ")",
+           q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
 
     MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, InterfaceID, mDNSNULL);
+    m->rec.r.resrec.negativeRecordType = noData ? kNegativeRecordType_NoData : kNegativeRecordType_Unspecified;
 
     // We need to force the response through in the following cases
     //
@@ -473,21 +555,25 @@ mDNSlocal void GenerateNegativeResponse(mDNS *const m, mDNSInterfaceID Interface
     // Don't touch the question after this
     m->rec.r.resrec.RecordType = 0;     // Clear RecordType to show we're not still using it
 }
+#define GenerateNegativeResponse(M, INTERFACE_ID, QC) GenerateNegativeResponseEx(M, INTERFACE_ID, QC, mDNSfalse)
 
 mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, ResourceRecord *rr)
 {
     const mDNSBool selfref = SameDomainName(&q->qname, &rr->rdata->u.name);
     if (q->CNAMEReferrals >= 10 || selfref)
     {
-        LogMsg("AnswerQuestionByFollowingCNAME: %p %##s (%s) NOT following CNAME referral %d%s for %s",
-               q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ")  NOT following CNAME referral %d" PUB_S " for " PRI_S,
+               q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+               q->CNAMEReferrals, selfref ? " (Self-Referential)" : "", RRDisplayString(m, rr));
+
     }
     else
     {
         const mDNSu32 c = q->CNAMEReferrals + 1;        // Stash a copy of the new q->CNAMEReferrals value
         UDPSocket *sock = q->LocalSocket;
         mDNSOpaque16 id = q->TargetQID;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
         uDNSMetrics metrics;
 #endif
 
@@ -508,10 +594,12 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
         // which we would subsequently cancel and retract if the CNAME referral record were removed.
         // In reality this is such a corner case we'll ignore it until someone actually needs it.
 
-        LogInfo("AnswerQuestionByFollowingCNAME: %p %##s (%s) following CNAME referral %d for %s",
-                q, q->qname.c, DNSTypeName(q->qtype), q->CNAMEReferrals, RRDisplayString(m, rr));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d->Q%d] AnswerQuestionByFollowingCNAME: %p " PRI_DM_NAME " (" PUB_S ") following CNAME referral %d for " PRI_S,
+               q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+               q->CNAMEReferrals, RRDisplayString(m, rr));
 
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
         if ((q->CNAMEReferrals == 0) && !q->metrics.originalQName)
         {
             domainname *    qName;
@@ -520,7 +608,7 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
             qNameLen = DomainNameLength(&q->qname);
             if ((qNameLen > 0) && (qNameLen <= MAX_DOMAIN_NAME))
             {
-                qName = mDNSPlatformMemAllocate(qNameLen);
+                qName = (domainname *) mDNSPlatformMemAllocate(qNameLen);
                 if (qName)
                 {
                     mDNSPlatformMemCopy(qName->c, q->qname.c, qNameLen);
@@ -539,16 +627,18 @@ mDNSexport void AnswerQuestionByFollowingCNAME(mDNS *const m, DNSQuestion *q, Re
         // to try this as unicast query even though it is a .local name
         if (!mDNSOpaque16IsZero(q->TargetQID) && IsLocalDomain(&q->qname))
         {
-            LogInfo("AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p %##s (%s) Record %s",
-                    q, q->qname.c, DNSTypeName(q->qtype), RRDisplayString(m, rr));
-            q->InterfaceID = mDNSInterface_Unicast;
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                   "[R%d->Q%d] AnswerQuestionByFollowingCNAME: Resolving a .local CNAME %p " PRI_DM_NAME " (" PUB_S ") Record " PRI_S,
+                   q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), RRDisplayString(m, rr));
+            q->IsUnicastDotLocal = mDNStrue;
         }
         mDNS_StartQuery_internal(m, q);                             // start new query
         // Record how many times we've done this. We need to do this *after* mDNS_StartQuery_internal,
         // because mDNS_StartQuery_internal re-initializes CNAMEReferrals to zero
         q->CNAMEReferrals = c;
-#if AWD_METRICS
-        metrics.expiredAnswerState = q->metrics.expiredAnswerState; //  We want the newly initialized state for this value
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+        metrics.expiredAnswerState  = q->metrics.expiredAnswerState; //  We want the newly initialized state for this value
+        metrics.dnsOverTCPState     = q->metrics.dnsOverTCPState;    //  We want the newly initialized state for this value
         q->metrics = metrics;
 #endif
         if (sock)
@@ -692,7 +782,7 @@ mDNSlocal void AnswerLocalQuestionWithLocalAuthRecord(mDNS *const m, AuthRecord
     mDNS_ReclaimLockAfterCallback();    // Decrement mDNS_reentrancy to block mDNS API calls again
 }
 
-mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
+mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
 {
     if (m->CurrentQuestion)
         LogMsg("AnswerInterfaceAnyQuestionsWithLocalAuthRecord: ERROR m->CurrentQuestion already set: %##s (%s)",
@@ -702,12 +792,12 @@ mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, Aut
     {
         mDNSBool answered;
         DNSQuestion *q = m->CurrentQuestion;
-        if (RRAny(rr))
-            answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
+        if (RRAny(ar))
+            answered = AuthRecordAnswersQuestion(ar, q);
         else
-            answered = LocalOnlyRecordAnswersQuestion(rr, q);
+            answered = LocalOnlyRecordAnswersQuestion(ar, q);
         if (answered)
-            AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord);       // MUST NOT dereference q again
+            AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord);       // MUST NOT dereference q again
         if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
             m->CurrentQuestion = q->next;
     }
@@ -725,7 +815,7 @@ mDNSlocal void AnswerInterfaceAnyQuestionsWithLocalAuthRecord(mDNS *const m, Aut
 // AnswerAllLocalQuestionsWithLocalAuthRecord is used by the m->NewLocalRecords loop in mDNS_Execute(),
 // and by mDNS_Deregister_internal()
 
-mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *rr, QC_result AddRecord)
+mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRecord *ar, QC_result AddRecord)
 {
     if (m->CurrentQuestion)
         LogMsg("AnswerAllLocalQuestionsWithLocalAuthRecord ERROR m->CurrentQuestion already set: %##s (%s)",
@@ -737,12 +827,12 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
         mDNSBool answered;
         DNSQuestion *q = m->CurrentQuestion;
         // We are called with both LocalOnly/P2P record or a regular AuthRecord
-        if (RRAny(rr))
-            answered = ResourceRecordAnswersQuestion(&rr->resrec, q);
+        if (RRAny(ar))
+            answered = AuthRecordAnswersQuestion(ar, q);
         else
-            answered = LocalOnlyRecordAnswersQuestion(rr, q);
+            answered = LocalOnlyRecordAnswersQuestion(ar, q);
         if (answered)
-            AnswerLocalQuestionWithLocalAuthRecord(m, rr, AddRecord);           // MUST NOT dereference q again
+            AnswerLocalQuestionWithLocalAuthRecord(m, ar, AddRecord);           // MUST NOT dereference q again
         if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
             m->CurrentQuestion = q->next;
     }
@@ -750,8 +840,8 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
     m->CurrentQuestion = mDNSNULL;
 
     // If this AuthRecord is marked LocalOnly or P2P, then we want to deliver it to all local 'mDNSInterface_Any' questions
-    if (rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P)
-        AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, rr, AddRecord);
+    if (ar->ARType == AuthRecordLocalOnly || ar->ARType == AuthRecordP2P)
+        AnswerInterfaceAnyQuestionsWithLocalAuthRecord(m, ar, AddRecord);
 
 }
 
@@ -763,18 +853,45 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
 
 #define RRTypeIsAddressType(T) ((T) == kDNSType_A || (T) == kDNSType_AAAA)
 
-#define ResourceRecordIsValidAnswer(RR) ( ((RR)->resrec.RecordType & kDNSRecordTypeActiveMask)  && \
-                                          ((RR)->Additional1 == mDNSNULL || ((RR)->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
-                                          ((RR)->Additional2 == mDNSNULL || ((RR)->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) && \
-                                          ((RR)->DependentOn == mDNSNULL || ((RR)->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask))  )
+mDNSlocal mDNSBool ResourceRecordIsValidAnswer(const AuthRecord *const rr)
+{
+    if ((rr->resrec.RecordType & kDNSRecordTypeActiveMask) &&
+        ((rr->Additional1 == mDNSNULL) || (rr->Additional1->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
+        ((rr->Additional2 == mDNSNULL) || (rr->Additional2->resrec.RecordType & kDNSRecordTypeActiveMask)) &&
+        ((rr->DependentOn == mDNSNULL) || (rr->DependentOn->resrec.RecordType & kDNSRecordTypeActiveMask)))
+    {
+        return mDNStrue;
+    }
+    else
+    {
+        return mDNSfalse;
+    }
+}
+
+mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *const rr, const mDNSInterfaceID InterfaceID)
+{
+    if (rr->resrec.InterfaceID == mDNSInterface_Any)
+    {
+        return mDNSPlatformValidRecordForInterface(rr, InterfaceID);
+    }
+    else
+    {
+        return ((rr->resrec.InterfaceID == InterfaceID) ? mDNStrue : mDNSfalse);
+    }
+}
 
-#define ResourceRecordIsValidInterfaceAnswer(RR, INTID) \
-    (ResourceRecordIsValidAnswer(RR) && \
-     ((RR)->resrec.InterfaceID == mDNSInterface_Any || (RR)->resrec.InterfaceID == (INTID)))
+mDNSlocal mDNSBool ResourceRecordIsValidInterfaceAnswer(const AuthRecord *const rr, const mDNSInterfaceID interfaceID)
+{
+    return ((IsInterfaceValidForAuthRecord(rr, interfaceID) && ResourceRecordIsValidAnswer(rr)) ? mDNStrue : mDNSfalse);
+}
 
 #define DefaultProbeCountForTypeUnique ((mDNSu8)3)
 #define DefaultProbeCountForRecordType(X)      ((X) == kDNSRecordTypeUnique ? DefaultProbeCountForTypeUnique : (mDNSu8)0)
 
+// Parameters for handling probing conflicts
+#define kMaxAllowedMCastProbingConflicts 1                     // Maximum number of conflicts to allow from mcast messages.
+#define kProbingConflictPauseDuration    mDNSPlatformOneSecond // Duration of probing pause after an allowed mcast conflict.
+
 // See RFC 6762: "8.3 Announcing"
 // "The Multicast DNS responder MUST send at least two unsolicited responses, one second apart."
 // Send 4, which is really 8 since we send on both IPv4 and IPv6.
@@ -812,7 +929,7 @@ mDNSlocal void AnswerAllLocalQuestionsWithLocalAuthRecord(mDNS *const m, AuthRec
 // 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 127. This means that when we do our 80% query at 102 seconds,
+// We adjust the 100 second TTL to 127. This means that when we do our 80% query after 102 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.
 
@@ -937,6 +1054,7 @@ mDNSlocal void InitializeLastAPTime(mDNS *const m, AuthRecord *const rr)
 
     if (rr->ProbeCount)
     {
+        rr->ProbingConflictCount = 0;
         // If we have no probe suppression time set, or it is in the past, set it now
         if (m->SuppressProbes == 0 || m->SuppressProbes - m->timenow < 0)
         {
@@ -1007,11 +1125,7 @@ mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord
     const domainname *target;
     if (rr->AutoTarget)
     {
-        // For autotunnel services pointing at our IPv6 ULA we don't need or want a NAT mapping, but for all other
-        // advertised services referencing our uDNS hostname, we want NAT mappings automatically created as appropriate,
-        // with the port number in our advertised SRV record automatically tracking the external mapped port.
-        DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
-        if (!AuthInfo || !AuthInfo->AutoTunnel) rr->AutoTarget = Target_AutoHostAndNATMAP;
+        rr->AutoTarget = Target_AutoHostAndNATMAP;
     }
 
     target = GetServiceTarget(m, rr);
@@ -1029,13 +1143,30 @@ mDNSlocal const domainname *SetUnicastTargetToHostName(mDNS *const m, AuthRecord
     }
 }
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal mDNSBool AuthRecordIncludesOrIsAWDL(const AuthRecord *const ar)
+{
+    return ((AuthRecordIncludesAWDL(ar) || mDNSPlatformInterfaceIsAWDL(ar->resrec.InterfaceID)) ? mDNStrue : mDNSfalse);
+}
+#endif
+
 // 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 *const target = GetRRDomainNameTarget(&rr->resrec);
-    const domainname *newname = &m->MulticastHostname;
+    const domainname *newname;
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if (AuthRecordIncludesOrIsAWDL(rr))
+    {
+        newname = &m->RandomizedHostname;
+    }
+    else
+#endif
+    {
+        newname = &m->MulticastHostname;
+    }
     if (!target) LogInfo("SetTargetToHostName: Don't know how to set the target of rrtype %s", DNSTypeName(rr->resrec.rrtype));
 
     if (!(rr->ForceMCast || rr->ARType == AuthRecordLocalOnly || rr->ARType == AuthRecordP2P || IsLocalDomain(&rr->namestorage)))
@@ -1133,16 +1264,18 @@ mDNSexport void ActivateUnicastRegistration(mDNS *const m, AuthRecord *const rr)
         LogInfo("ActivateUnicastRegistration: Resource record %s, current state %d, moving to Pending", ARDisplayString(m, rr), rr->state);
         rr->state = regState_Pending;
     }
-    rr->ProbeCount     = 0;
-    rr->ProbeRestartCount = 0;
-    rr->AnnounceCount  = 0;
-    rr->ThisAPInterval = INIT_RECORD_REG_INTERVAL;
-    rr->LastAPTime     = m->timenow - rr->ThisAPInterval;
-    rr->expire         = 0; // Forget about all the leases, start fresh
-    rr->uselease       = mDNStrue;
-    rr->updateid       = zeroID;
-    rr->SRVChanged     = mDNSfalse;
-    rr->updateError    = mStatus_NoError;
+    rr->ProbingConflictCount = 0;
+    rr->LastConflictPktNum   = 0;
+    rr->ProbeRestartCount    = 0;
+    rr->ProbeCount           = 0;
+    rr->AnnounceCount        = 0;
+    rr->ThisAPInterval       = INIT_RECORD_REG_INTERVAL;
+    rr->LastAPTime           = m->timenow - rr->ThisAPInterval;
+    rr->expire               = 0; // Forget about all the leases, start fresh
+    rr->uselease             = mDNStrue;
+    rr->updateid             = zeroID;
+    rr->SRVChanged           = mDNSfalse;
+    rr->updateError          = mStatus_NoError;
     // RestartRecordGetZoneData calls this function whenever a new interface gets registered with core.
     // The records might already be registered with the server and hence could have NAT state.
     if (rr->NATinfo.clientContext)
@@ -1233,7 +1366,6 @@ mDNSlocal AuthRecord *CheckAuthSameRecord(AuthHash *r, AuthRecord *rr)
     return (mDNSNULL);
 }
 
-
 mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
 {
     if (RRLocalOnly(rr))
@@ -1243,31 +1375,99 @@ mDNSlocal void DecrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
         return;
     }
 
-    if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost)
+    if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
     {
-        // If about to get rid of the last advertised service
-        if (m->AutoTargetServices == 1)
-            DeadvertiseAllInterfaceRecords(m);
-
-        m->AutoTargetServices--;
-        LogInfo("DecrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
+        NetworkInterfaceInfo *intf;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+        DeadvertiseFlags flags     = 0; // DeadvertiseFlags for non-AWDL interfaces.
+        DeadvertiseFlags flagsAWDL = 0; // DeadvertiseFlags for AWDL interfaces.
+        if (AuthRecordIncludesOrIsAWDL(rr))
+        {
+            if (AuthRecordIncludesAWDL(rr))
+            {
+                m->AutoTargetAWDLIncludedCount--;
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                    "DecrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
+                    m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
+                if (m->AutoTargetAWDLIncludedCount == 0)
+                {
+                    flags |= kDeadvertiseFlag_RandHostname;
+                    if (m->AutoTargetAWDLOnlyCount == 0) flagsAWDL |= kDeadvertiseFlag_RandHostname;
+                }
+            }
+            else
+            {
+                m->AutoTargetAWDLOnlyCount--;
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                    "DecrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
+                    m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
+                if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
+                {
+                    flagsAWDL |= kDeadvertiseFlag_RandHostname;
+                }
+            }
+            if (flags || flagsAWDL)
+            {
+                for (intf = m->HostInterfaces; intf; intf = intf->next)
+                {
+                    if (!intf->Advertise) continue;
+                    if (mDNSPlatformInterfaceIsAWDL(intf->InterfaceID))
+                    {
+                        if (flagsAWDL) DeadvertiseInterface(m, intf, flagsAWDL);
+                    }
+                    else
+                    {
+                        if (flags) DeadvertiseInterface(m, intf, flags);
+                    }
+                }
+            }
+            if ((m->AutoTargetAWDLIncludedCount == 0) && (m->AutoTargetAWDLOnlyCount == 0))
+            {
+                GetRandomUUIDLocalHostname(&m->RandomizedHostname);
+            }
+        }
+        else
+#endif
+        {
+            m->AutoTargetServices--;
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "DecrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
+                m->AutoTargetServices, ARDisplayString(m, rr));
+            if (m->AutoTargetServices == 0)
+            {
+                for (intf = m->HostInterfaces; intf; intf = intf->next)
+                {
+                    if (intf->Advertise) DeadvertiseInterface(m, intf, kDeadvertiseFlag_NormalHostname);
+                }
+            }
+        }
     }
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     if (!AuthRecord_uDNS(rr))
     {
         if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
             m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
         m->NumAllInterfaceRecords--;
-        LogInfo("DecrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "DecrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
             m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
     }
-#endif // BONJOUR_ON_DEMAND
+#endif
+}
+
+mDNSlocal void AdvertiseNecessaryInterfaceRecords(mDNS *const m)
+{
+    NetworkInterfaceInfo *intf;
+    for (intf = m->HostInterfaces; intf; intf = intf->next)
+    {
+        if (intf->Advertise) AdvertiseInterfaceIfNeeded(m, intf);
+    }
 }
 
 mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
 {
-    mDNSBool enablingBonjour = 0;
+    mDNSBool enablingBonjour = mDNSfalse;
 
     if (RRLocalOnly(rr))
     {
@@ -1276,11 +1476,12 @@ mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
         return;
     }
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     if (!AuthRecord_uDNS(rr))
     {
         m->NumAllInterfaceRecords++;
-        LogInfo("IncrementAutoTargetServices: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %s",
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "IncrementAutoTargetServices: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_S,
             m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, ARDisplayString(m, rr));
         if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
         {
@@ -1290,24 +1491,43 @@ mDNSlocal void IncrementAutoTargetServices(mDNS *const m, AuthRecord *const rr)
                 // Enable Bonjour immediately by scheduling network changed processing where
                 // we will join the multicast group on each active interface.
                 m->BonjourEnabled = 1;
-                enablingBonjour = 1;
+                enablingBonjour = mDNStrue;
                 m->NetworkChanged = m->timenow;
             }
         }
     }
-#endif // BONJOUR_ON_DEMAND
+#endif
 
-    if (!AuthRecord_uDNS(rr) && rr->resrec.rrtype == kDNSType_SRV && rr->AutoTarget == Target_AutoHost)
+    if (!AuthRecord_uDNS(rr) && (rr->resrec.rrtype == kDNSType_SRV) && (rr->AutoTarget == Target_AutoHost))
     {
-        m->AutoTargetServices++;
-        LogInfo("IncrementAutoTargetServices: AutoTargetServices %d Record %s", m->AutoTargetServices, ARDisplayString(m, rr));
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+        if (AuthRecordIncludesAWDL(rr))
+        {
+            m->AutoTargetAWDLIncludedCount++;
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "IncrementAutoTargetServices: AutoTargetAWDLIncludedCount %u Record " PRI_S,
+                m->AutoTargetAWDLIncludedCount, ARDisplayString(m, rr));
+        }
+        else if (mDNSPlatformInterfaceIsAWDL(rr->resrec.InterfaceID))
+        {
+            m->AutoTargetAWDLOnlyCount++;
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "IncrementAutoTargetServices: AutoTargetAWDLOnlyCount %u Record " PRI_S,
+                m->AutoTargetAWDLOnlyCount, ARDisplayString(m, rr));
+        }
+        else
+#endif
+        {
+            m->AutoTargetServices++;
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "IncrementAutoTargetServices: AutoTargetServices %u Record " PRI_S,
+                m->AutoTargetServices, ARDisplayString(m, rr));
+        }
         // If this is the first advertised service and we did not just enable Bonjour above, then
         // advertise all the interface records.  If we did enable Bonjour above, the interface records will
         // be advertised during the network changed processing scheduled above, so no need 
         // to do it here.
-        if ((m->AutoTargetServices == 1) && (enablingBonjour == 0))
-            AdvertiseAllInterfaceRecords(m);
+        if (!enablingBonjour) AdvertiseNecessaryInterfaceRecords(m);
     }
 }
 
@@ -1553,7 +1773,6 @@ mDNSexport mStatus mDNS_Register_internal(mDNS *const m, AuthRecord *const rr)
         if (!m->NewLocalRecords) m->NewLocalRecords = rr;
         // When we called SetTargetToHostName, it may have caused mDNS_Register_internal to be re-entered, appending new
         // records to the list, so we now need to update p to advance to the new end to the list before appending our new record.
-        // Note that for AutoTunnel this should never happen, but this check makes the code future-proof.
         while (*p) p=&(*p)->next;
         *p = rr;
         if (rr->resrec.RecordType == kDNSRecordTypeUnique) rr->resrec.RecordType = kDNSRecordTypeVerified;
@@ -1792,7 +2011,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
     // we need to retract that announcement before we delete the record
 
     // If this is a record (including mDNSInterface_LocalOnly records) for which we've given local-only answers then
-    // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse)" here, but that would not not be safe.
+    // it's tempting to just do "AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv)" here, but that would not not be safe.
     // The AnswerAllLocalQuestionsWithLocalAuthRecord routine walks the question list invoking client callbacks, using the "m->CurrentQuestion"
     // mechanism to cope with the client callback modifying the question list while that's happening.
     // However, mDNS_Deregister could have been called from a client callback (e.g. from the domain enumeration callback FoundDomain)
@@ -1819,7 +2038,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
         }
         // Sometimes the records don't complete proper deregistration i.e., don't wait for a response
         // from the server. In that case, if the records have been part of a group update, clear the
-        // state here. Some recors e.g., AutoTunnel gets reused without ever being completely initialized
+        // state here.
         rr->updateid = zeroID;
 
         // We defer cleaning up NAT state only after sending goodbyes. This is important because
@@ -1847,14 +2066,9 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
         return(mStatus_BadReferenceErr);
     }
 
-    // <rdar://problem/7457925> Local-only questions don't get remove events for unique records
-    // We may want to consider changing this code so that we generate local-only question "rmv"
-    // events (and maybe goodbye packets too) for unique records as well as for shared records
-    // Note: If we change the logic for this "if" statement, need to ensure that the code in
-    // CompleteDeregistration() sets the appropriate state variables to gaurantee that "else"
-    // clause will execute here and the record will be cut from the list.
     if (rr->WakeUp.HMAC.l[0] ||
-        (RecordType == kDNSRecordTypeShared && (rr->RequireGoodbye || rr->AnsweredLocalQ)))
+        (((RecordType == kDNSRecordTypeShared) || (rr->ARType == AuthRecordLocalOnly)) &&
+        (rr->RequireGoodbye || rr->AnsweredLocalQ)))
     {
         verbosedebugf("mDNS_Deregister_internal: Starting deregistration for %s", ARDisplayString(m, rr));
         rr->resrec.RecordType    = kDNSRecordTypeDeregistering;
@@ -1883,10 +2097,6 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
         if (m->CurrentRecord   == rr) m->CurrentRecord   = rr->next;
         rr->next = mDNSNULL;
 
-        // Should we generate local remove events here?
-        // i.e. something like:
-        // if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
-
         verbosedebugf("mDNS_Deregister_internal: Deleting record for %s", ARDisplayString(m, rr));
         rr->resrec.RecordType = kDNSRecordTypeUnregistered;
 
@@ -1929,7 +2139,7 @@ mDNSexport mStatus mDNS_Deregister_internal(mDNS *const m, AuthRecord *const rr,
                 }
                 else
                 {
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
                     // See if this record was also registered with any D2D plugins.
                     D2D_stop_advertising_record(r2);
 #endif
@@ -2034,21 +2244,12 @@ mDNSlocal void AddAdditionalsToResponseList(mDNS *const m, AuthRecord *ResponseR
     }
 }
 
-mDNSlocal int AnonInfoSpace(AnonymousInfo *info)
-{
-    ResourceRecord *rr = info->nsec3RR;
-
-    // 2 bytes for compressed name + type (2) class (2) TTL (4) rdlength (2) rdata (n)
-    return (2 + 10 + rr->rdlength);
-}
-
 mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const dest, const mDNSInterfaceID InterfaceID)
 {
     AuthRecord *rr;
     AuthRecord  *ResponseRecords = mDNSNULL;
     AuthRecord **nrp             = &ResponseRecords;
     NetworkInterfaceInfo *intf = FirstInterfaceForID(m, InterfaceID);
-    int AnoninfoSpace = 0;
 
     // Make a list of all our records that need to be unicast to this destination
     for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -2097,17 +2298,10 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
         while (ResponseRecords && ResponseRecords->NR_AnswerTo)
         {
             rr = ResponseRecords;
-            if (rr->resrec.AnonInfo)
-            {
-                AnoninfoSpace += AnonInfoSpace(rr->resrec.AnonInfo);
-                rr->resrec.AnonInfo->SendNow = mDNSInterfaceMark;
-            }
             if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                 rr->resrec.rrclass |= kDNSClass_UniqueRRSet;        // Temporarily set the cache flush bit so PutResourceRecord will set it
 
-            // Retract the limit by AnoninfoSpace which we need to put the AnoInfo option.
-            newptr = PutResourceRecordTTLWithLimit(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec, rr->resrec.rroriginalttl,
-                 m->omsg.data + (AllowedRRSpace(&m->omsg) - AnoninfoSpace));
+            newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAnswers, &rr->resrec);
 
             rr->resrec.rrclass &= ~kDNSClass_UniqueRRSet;           // Make sure to clear cache flush bit back to normal state
             if (!newptr && m->omsg.h.numAnswers)
@@ -2122,29 +2316,6 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
             rr->RequireGoodbye  = mDNStrue;
         }
 
-        // We have reserved the space for AnonInfo option. PutResourceRecord uses the
-        // standard limit (AllowedRRSpace) and we should have space now.
-        for (rr = m->ResourceRecords; rr; rr=rr->next)
-        {
-            if (rr->resrec.AnonInfo && rr->resrec.AnonInfo->SendNow == mDNSInterfaceMark)
-            {
-                ResourceRecord *nsec3RR = rr->resrec.AnonInfo->nsec3RR;
-
-                newptr = PutResourceRecord(&m->omsg, responseptr, &m->omsg.h.numAuthorities, nsec3RR);
-                if (newptr)
-                {
-                    responseptr = newptr;
-                    debugf("SendDelayedUnicastResponse: Added NSEC3 Record %s on %p", RRDisplayString(m, nsec3RR), intf->InterfaceID);
-                }
-                else
-                {
-                    // We allocated space and we should not fail. Don't break, we need to clear the SendNow flag.
-                    LogMsg("SendDelayedUnicastResponse: ERROR!! Cannot Add NSEC3 Record %s on %p", RRDisplayString(m, nsec3RR), intf->InterfaceID);
-                }
-                rr->resrec.AnonInfo->SendNow = mDNSNULL;
-            }
-        }
-
         // Add additionals, if there's space
         while (ResponseRecords && !ResponseRecords->NR_AnswerTo)
         {
@@ -2164,7 +2335,7 @@ mDNSlocal void SendDelayedUnicastResponse(mDNS *const m, const mDNSAddr *const d
         }
 
         if (m->omsg.h.numAnswers)
-            mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+            mDNSSendDNSMessage(m, &m->omsg, responseptr, InterfaceID, mDNSNULL, mDNSNULL, dest, MulticastDNSPort, mDNSNULL, mDNSfalse);
     }
 }
 
@@ -2178,7 +2349,7 @@ mDNSexport void CompleteDeregistration(mDNS *const m, AuthRecord *rr)
     rr->resrec.RecordType = kDNSRecordTypeShared;
     rr->RequireGoodbye    = mDNSfalse;
     rr->WakeUp.HMAC       = zeroEthAddr;
-    if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse); rr->AnsweredLocalQ = mDNSfalse; }
+    if (rr->AnsweredLocalQ) { AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv); rr->AnsweredLocalQ = mDNSfalse; }
     mDNS_Deregister_internal(m, rr, mDNS_Dereg_normal);     // Don't touch rr after this
 }
 
@@ -2485,22 +2656,6 @@ mDNSlocal mDNSBool ShouldSendGoodbyesBeforeSleep(mDNS *const m, const NetworkInt
     }
 }
 
-mDNSlocal mDNSBool IsInterfaceValidForAuthRecord(const AuthRecord *ar, mDNSInterfaceID InterfaceID)
-{
-    mDNSBool result;
-
-    if (ar->resrec.InterfaceID == mDNSInterface_Any)
-    {
-        result = mDNSPlatformValidRecordForInterface(ar, InterfaceID);
-    }
-    else
-    {
-        result = (ar->resrec.InterfaceID == InterfaceID);
-    }
-
-    return(result);
-}
-
 // Note about acceleration of announcements to facilitate automatic coalescing of
 // multiple independent threads of announcements into a single synchronized thread:
 // The announcements in the packet may be at different stages of maturity;
@@ -2733,7 +2888,6 @@ mDNSlocal void SendResponses(mDNS *const m)
         int numDereg    = 0;
         int numAnnounce = 0;
         int numAnswer   = 0;
-        int AnoninfoSpace = 0;
         mDNSu8 *responseptr = m->omsg.data;
         mDNSu8 *newptr;
         InitializeDNSMessage(&m->omsg.h, zeroID, ResponseFlags);
@@ -2771,17 +2925,6 @@ mDNSlocal void SendResponses(mDNS *const m)
                     SetNewRData(&rr->resrec, rr->NewRData, rr->newrdlength);
                 }
 
-                if (rr->resrec.AnonInfo)
-                {
-                    int tmp = AnonInfoSpace(rr->resrec.AnonInfo);
-
-                    AnoninfoSpace += tmp;
-                    // Adjust OwnerRecordSpace/TraceRecordSpace which is used by PutRR_OS_TTL below so that
-                    // we have space to put in the NSEC3 record in the authority section.
-                    OwnerRecordSpace += tmp;
-                    TraceRecordSpace += tmp;
-                }
-
                 if (rr->resrec.RecordType & kDNSRecordTypeUniqueMask)
                     rr->resrec.rrclass |= kDNSClass_UniqueRRSet;        // Temporarily set the cache flush bit so PutResourceRecord will set it
                 newptr = PutRR_OS_TTL(responseptr, &m->omsg.h.numAnswers, &rr->resrec, active ? rr->resrec.rroriginalttl : 0);
@@ -2804,13 +2947,6 @@ mDNSlocal void SendResponses(mDNS *const m)
 
                 if (newptr)     // If succeeded in sending, advance to next interface
                 {
-                    if (rr->resrec.AnonInfo)
-                    {
-                        debugf("SendResponses: Marking %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
-                                TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
-                        rr->resrec.AnonInfo->SendNow = intf->InterfaceID;
-                    }
-
                     // If sending on all interfaces, go to next interface; else we're finished now
                     if (rr->ImmedAnswer == mDNSInterfaceMark && rr->resrec.InterfaceID == mDNSInterface_Any)
                         rr->SendRNow = GetNextActiveInterfaceID(intf);
@@ -2820,31 +2956,6 @@ mDNSlocal void SendResponses(mDNS *const m)
             }
         }
 
-        // Get the reserved space back
-        OwnerRecordSpace -= AnoninfoSpace;
-        TraceRecordSpace -= AnoninfoSpace;
-        newptr = responseptr;
-        for (rr = m->ResourceRecords; rr; rr=rr->next)
-        {
-            if (rr->resrec.AnonInfo && rr->resrec.AnonInfo->SendNow == intf->InterfaceID)
-            {
-                ResourceRecord *nsec3RR = rr->resrec.AnonInfo->nsec3RR;
-
-                newptr = PutRR_OS_TTL(newptr, &m->omsg.h.numAuthorities, nsec3RR,  nsec3RR->rroriginalttl);
-                if (newptr)
-                {
-                    responseptr = newptr;
-                    debugf("SendResponses: Added NSEC3 %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
-                            TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
-                }
-                else
-                {
-                    LogMsg("SendResponses: Cannot add NSEC3 %s, OwnerRecordSpace %d, TraceRecordSpace %d, limit %p", ARDisplayString(m, rr), OwnerRecordSpace,
-                            TraceRecordSpace, m->omsg.data + AllowedRRSpace(&m->omsg) - OwnerRecordSpace - TraceRecordSpace);
-                }
-                rr->resrec.AnonInfo->SendNow = mDNSNULL;
-            }
-        }
         // Second Pass. Add additional records, if there's space.
         newptr = responseptr;
         for (rr = m->ResourceRecords; rr; rr=rr->next)
@@ -2993,8 +3104,8 @@ mDNSlocal void SendResponses(mDNS *const m)
                    numAnswer,                numAnswer                == 1 ? "" : "s",
                    m->omsg.h.numAdditionals, m->omsg.h.numAdditionals == 1 ? "" : "s", intf->InterfaceID);
 
-            if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
-            if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+            if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSfalse);
+            if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, responseptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSfalse);
             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.
@@ -3027,7 +3138,7 @@ mDNSlocal void SendResponses(mDNS *const m)
         {
             if (rr->ARType != AuthRecordLocalOnly && rr->ARType != AuthRecordP2P)
                 LogInfo("SendResponses: No active interface %d to send: %d %02X %s",
-                     (uint32_t)rr->SendRNow, (uint32_t)rr->resrec.InterfaceID, rr->resrec.RecordType, ARDisplayString(m, rr));
+                IIDPrintable(rr->SendRNow), IIDPrintable(rr->resrec.InterfaceID), rr->resrec.RecordType, ARDisplayString(m, rr));
             rr->SendRNow = mDNSNULL;
         }
 
@@ -3064,13 +3175,13 @@ mDNSlocal void SendResponses(mDNS *const m)
 //    so allow at most 1/10 second lateness
 // 5. For records with rroriginalttl set to zero, that means we really want to delete them immediately
 //    (we have a new record with DelayDelivery set, waiting for the old record to go away before we can notify clients).
-#define CacheCheckGracePeriod(RR) (                                                   \
-        ((RR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
-        ((RR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(rr)/50)            : \
-        ((RR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : \
-        ((RR)->resrec.rroriginalttl > 0                ) ? (mDNSPlatformOneSecond/10)   : 0)
+#define CacheCheckGracePeriod(CR) (                                                   \
+        ((CR)->CRActiveQuestion == mDNSNULL            ) ? (60 * mDNSPlatformOneSecond) : \
+        ((CR)->UnansweredQueries < MaxUnansweredQueries) ? (TicksTTL(CR)/50)            : \
+        ((CR)->resrec.rroriginalttl > 10               ) ? (mDNSPlatformOneSecond)      : \
+        ((CR)->resrec.rroriginalttl > 0                ) ? (mDNSPlatformOneSecond/10)   : 0)
 
-#define NextCacheCheckEvent(RR) ((RR)->NextRequiredQuery + CacheCheckGracePeriod(RR))
+#define NextCacheCheckEvent(CR) ((CR)->NextRequiredQuery + CacheCheckGracePeriod(CR))
 
 mDNSexport void ScheduleNextCacheCheckTime(mDNS *const m, const mDNSu32 slot, const mDNSs32 event)
 {
@@ -3144,8 +3255,7 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
     mDNSBool ucast = (q->LargeAnswers || q->RequestUnicast) && m->CanReceiveUnicastOn5353 && intf->SupportsUnicastMDNSResponse;
     mDNSu16 ucbit = (mDNSu16)(ucast ? kDNSQClass_UnicastResponse : 0);
     const mDNSu8 *const limit = query->data + NormalMaxDNSMessageData;
-    mDNSu8 anoninfo_space = q->AnonInfo ? AnonInfoSpace(q->AnonInfo) : 0;
-    mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast - anoninfo_space, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
+    mDNSu8 *newptr = putQuestion(query, *queryptr, limit - *answerforecast, &q->qname, q->qtype, (mDNSu16)(q->qclass | ucbit));
     if (!newptr)
     {
         debugf("BuildQuestion: No more space in this packet for question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -3153,18 +3263,18 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
     }
     else
     {
-        mDNSu32 forecast = *answerforecast + anoninfo_space;
+        mDNSu32 forecast = *answerforecast;
         const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
-        CacheRecord *rr;
+        CacheRecord *cr;
         CacheRecord **ka = *kalistptrptr;   // Make a working copy of the pointer we're going to update
 
-        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)             // If we have a resource record in our cache,
-            if (rr->resrec.InterfaceID == q->SendQNow &&                    // received on this interface
-                !(rr->resrec.RecordType & kDNSRecordTypeUniqueMask) &&      // which is a shared (i.e. not unique) record type
-                rr->NextInKAList == mDNSNULL && ka != &rr->NextInKAList &&  // which is not already in the known answer list
-                rr->resrec.rdlength <= SmallRecordLimit &&                  // which is small enough to sensibly fit in the packet
-                SameNameRecordAnswersQuestion(&rr->resrec, q) &&            // which answers our question
-                rr->TimeRcvd + TicksTTL(rr)/2 - m->timenow >                // and its half-way-to-expiry time is at least 1 second away
+        for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)             // If we have a resource record in our cache,
+            if (cr->resrec.InterfaceID == q->SendQNow &&                    // received on this interface
+                !(cr->resrec.RecordType & kDNSRecordTypeUniqueMask) &&      // which is a shared (i.e. not unique) record type
+                cr->NextInKAList == mDNSNULL && ka != &cr->NextInKAList &&  // which is not already in the known answer list
+                cr->resrec.rdlength <= SmallRecordLimit &&                  // which is small enough to sensibly fit in the packet
+                SameNameCacheRecordAnswersQuestion(cr, q) &&                // which answers our question
+                cr->TimeRcvd + TicksTTL(cr)/2 - m->timenow >                // and its half-way-to-expiry time is at least 1 second away
                 mDNSPlatformOneSecond)                                      // (also ensures we never include goodbye records with TTL=1)
             {
                 // We don't want to include unique records in the Known Answer section. The Known Answer section
@@ -3173,10 +3283,10 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
                 // which we have a unique record already in our cache, then including that unique record as a
                 // Known Answer, so as to suppress the only answer we were expecting to get, makes little sense.
 
-                *ka = rr;   // Link this record into our known answer chain
-                ka = &rr->NextInKAList;
+                *ka = cr;   // Link this record into our known answer chain
+                ka = &cr->NextInKAList;
                 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
-                forecast += 12 + rr->resrec.rdestimate;
+                forecast += 12 + cr->resrec.rdestimate;
                 // If we're trying to put more than one question in this packet, and it doesn't fit
                 // then undo that last question and try again next time
                 if (query->h.numQuestions > 1 && newptr + forecast >= limit)
@@ -3196,14 +3306,14 @@ mDNSlocal mDNSBool BuildQuestion(mDNS *const m, const NetworkInterfaceInfo *intf
         *kalistptrptr    = ka;                  // Update the known answer list pointer
         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
-                SameNameRecordAnswersQuestion(&rr->resrec, q))              // which answers our question
+        for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)             // For every resource record in our cache,
+            if (cr->resrec.InterfaceID == q->SendQNow &&                    // received on this interface
+                cr->NextInKAList == mDNSNULL && ka != &cr->NextInKAList &&  // which is not in the known answer list
+                SameNameCacheRecordAnswersQuestion(cr, q))                  // which answers our question
             {
-                rr->UnansweredQueries++;                                    // indicate that we're expecting a response
-                rr->LastUnansweredTime = m->timenow;
-                SetNextCacheCheckTimeForRecord(m, rr);
+                cr->UnansweredQueries++;                                    // indicate that we're expecting a response
+                cr->LastUnansweredTime = m->timenow;
+                SetNextCacheCheckTimeForRecord(m, cr);
             }
 
         return(mDNStrue);
@@ -3267,7 +3377,7 @@ mDNSlocal const CacheRecord *FindSPSInCache1(mDNS *const m, const DNSQuestion *c
     for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
         if (cr->resrec.rrtype == kDNSType_PTR && cr->resrec.rdlength >= 6)                      // If record is PTR type, with long enough name,
             if (cr != c0 && cr != c1)                                                           // that's not one we've seen before,
-                if (SameNameRecordAnswersQuestion(&cr->resrec, q))                              // and answers our browse query,
+                if (SameNameCacheRecordAnswersQuestion(cr, q))                                  // and answers our browse query,
                     if (!IdenticalSameNameRecord(&cr->resrec, &m->SPSRecords.RR_PTR.resrec))    // and is not our own advertised service...
                     {
                         mDNSu32 metric = SPSMetric(cr->resrec.rdata->u.name.c);
@@ -3434,15 +3544,15 @@ mDNSlocal mDNSBool AccelerateThisQuery(mDNS *const m, DNSQuestion *q)
         // We forecast: qname (n) type (2) class (2)
         mDNSu32 forecast = (mDNSu32)DomainNameLength(&q->qname) + 4;
         const CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
-        const CacheRecord *rr;
-        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)             // If we have a resource record in our cache,
-            if (rr->resrec.rdlength <= SmallRecordLimit &&                  // which is small enough to sensibly fit in the packet
-                SameNameRecordAnswersQuestion(&rr->resrec, q) &&            // which answers our question
-                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
+        const CacheRecord *cr;
+        for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)              // If we have a resource record in our cache,
+            if (cr->resrec.rdlength <= SmallRecordLimit &&                   // which is small enough to sensibly fit in the packet
+                SameNameCacheRecordAnswersQuestion(cr, q) &&                 // which answers our question
+                cr->TimeRcvd + TicksTTL(cr)/2 - m->timenow >= 0 &&           // and it is less than half-way to expiry
+                cr->NextRequiredQuery - (m->timenow + q->ThisQInterval) > 0) // and we'll ask at least once again before NextRequiredQuery
             {
                 // We forecast: compressed name (2) type (2) class (2) TTL (4) rdlength (2) rdata (n)
-                forecast += 12 + rr->resrec.rdestimate;
+                forecast += 12 + cr->resrec.rdestimate;
                 if (forecast >= 512) return(mDNSfalse); // If this would add 512 bytes or more to the packet, don't accelerate
             }
         return(mDNStrue);
@@ -3491,11 +3601,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                 ExpireDupSuppressInfoOnInterface(q->DupSuppress, m->timenow - TicksTTL(cr)/20, cr->resrec.InterfaceID);
                 // For uDNS queries (TargetQID non-zero) we adjust LastQTime,
                 // and bump UnansweredQueries so that we don't spin trying to send the same cache expiration query repeatedly
-                if (q->Target.type)
-                {
-                    q->SendQNow = mDNSInterfaceMark; // If targeted query, mark it
-                }
-                else if (!mDNSOpaque16IsZero(q->TargetQID))
+                if (!mDNSOpaque16IsZero(q->TargetQID))
                 {
                     q->LastQTime = m->timenow - q->ThisQInterval;
                     cr->UnansweredQueries++;
@@ -3530,29 +3636,7 @@ mDNSlocal void SendQueries(mDNS *const m)
     while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
     {
         q = m->CurrentQuestion;
-        if (q->Target.type && (q->SendQNow || TimeToSendThisQuestion(q, m->timenow)))
-        {
-            mDNSu8       *qptr        = m->omsg.data;
-            const mDNSu8 *const limit = m->omsg.data + sizeof(m->omsg.data);
-
-            // If we fail to get a new on-demand socket (should only happen cases of the most extreme resource exhaustion), we'll try again next time
-            if (!q->LocalSocket) q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
-            if (q->LocalSocket)
-            {
-                InitializeDNSMessage(&m->omsg.h, q->TargetQID, QueryFlags);
-                qptr = putQuestion(&m->omsg, qptr, limit, &q->qname, q->qtype, q->qclass);
-                mDNSSendDNSMessage(m, &m->omsg, qptr, mDNSInterface_Any, q->LocalSocket, &q->Target, q->TargetPort, mDNSNULL, mDNSNULL, q->UseBackgroundTrafficClass);
-                q->ThisQInterval    *= QuestionIntervalStep;
-            }
-            if (q->ThisQInterval > MaxQuestionInterval)
-                q->ThisQInterval = MaxQuestionInterval;
-            q->LastQTime         = m->timenow;
-            q->LastQTxTime       = m->timenow;
-            q->RecentAnswerPkts  = 0;
-            q->SendQNow          = mDNSNULL;
-            q->ExpectUnicastResp = NonZeroTime(m->timenow);
-        }
-        else if (mDNSOpaque16IsZero(q->TargetQID) && !q->Target.type && TimeToSendThisQuestion(q, m->timenow))
+        if (mDNSOpaque16IsZero(q->TargetQID) && TimeToSendThisQuestion(q, m->timenow))
         {
             //LogInfo("Time to send %##s (%s) %d", q->qname.c, DNSTypeName(q->qtype), m->timenow - NextQSendTime(q));
             q->SendQNow = mDNSInterfaceMark;        // Mark this question for sending on all interfaces
@@ -3581,7 +3665,7 @@ mDNSlocal void SendQueries(mDNS *const m)
     for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
     {
         if (mDNSOpaque16IsZero(q->TargetQID)
-            && (q->SendQNow || (!q->Target.type && ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
+            && (q->SendQNow || (ActiveQuestion(q) && q->ThisQInterval <= maxExistingQuestionInterval && AccelerateThisQuery(m,q))))
         {
             // If at least halfway to next query time, advance to next interval
             // If less than halfway to next query time, then
@@ -3780,21 +3864,9 @@ mDNSlocal void SendQueries(mDNS *const m)
                     else if ((Suppress = SuppressOnThisInterface(q->DupSuppress, intf)) ||
                         BuildQuestion(m, intf, &m->omsg, &queryptr, q, &kalistptr, &answerforecast))
                     {
-                        // We successfully added the question to the packet. Make sure that
-                        // we also send the NSEC3 record if required. BuildQuestion accounted for
-                        // the space.
-                        //
-                        // Note: We don't suppress anonymous questions and hence Suppress should always
-                        // be zero.
-
                         if (Suppress)
                             m->mDNSStats.DupQuerySuppressions++;
 
-                        if (!Suppress && q->AnonInfo)
-                        {
-                            debugf("SendQueries: marking for question %##s, Suppress %d", q->qname.c, Suppress);
-                            q->AnonInfo->SendNow = intf->InterfaceID;
-                        }
                         q->SendQNow = (q->InterfaceID || !q->SendOnAll) ? mDNSNULL : GetNextActiveInterfaceID(intf);
                         if (q->WakeOnResolveCount)
                         {
@@ -3803,7 +3875,7 @@ mDNSlocal void SendQueries(mDNS *const m)
                         }
 
                         // use background traffic class if any included question requires it
-                        if (q->UseBackgroundTrafficClass)
+                        if (q->UseBackgroundTraffic)
                         {
                             useBackgroundTrafficClass = mDNStrue;
                         }
@@ -3908,24 +3980,6 @@ mDNSlocal void SendQueries(mDNS *const m)
             }
         }
 
-        for (q = m->Questions; q; q = q->next)
-        {
-            if (q->AnonInfo && q->AnonInfo->SendNow == intf->InterfaceID)
-            {
-                mDNSu8 *newptr = PutResourceRecord(&m->omsg, queryptr, &m->omsg.h.numAuthorities, q->AnonInfo->nsec3RR);
-                if (newptr)
-                {
-                    debugf("SendQueries: Added NSEC3 record %s on InterfaceID %p", RRDisplayString(m, q->AnonInfo->nsec3RR), intf->InterfaceID);
-                    queryptr = newptr;
-                }
-                else
-                {
-                    LogMsg("SendQueries: ERROR!! Cannot add NSEC3 record %s on InterfaceID %p", RRDisplayString(m, q->AnonInfo->nsec3RR), intf->InterfaceID);
-                }
-                q->AnonInfo->SendNow = mDNSNULL;
-            }
-        }
-
         if (queryptr > m->omsg.data)
         {
             // If we have data to send, add OWNER/TRACER/OWNER+TRACER option if necessary, then send packet
@@ -3969,12 +4023,12 @@ mDNSlocal void SendQueries(mDNS *const m)
 
             if ((m->omsg.h.flags.b[0] & kDNSFlag0_TC) && m->omsg.h.numQuestions > 1)
                 LogMsg("SendQueries: Should not have more than one question (%d) in a truncated packet", m->omsg.h.numQuestions);
-            debugf("SendQueries:   Sending %d Question%s %d Answer%s %d Update%s on %p",
+            debugf("SendQueries:   Sending %d Question%s %d Answer%s %d Update%s on %d (%s)",
                    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, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, mDNSNULL, useBackgroundTrafficClass);
-            if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, mDNSNULL, useBackgroundTrafficClass);
+                   m->omsg.h.numAuthorities, m->omsg.h.numAuthorities == 1 ? "" : "s", IIDPrintable(intf->InterfaceID), intf->ifname);
+            if (intf->IPv4Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v4, MulticastDNSPort, mDNSNULL, useBackgroundTrafficClass);
+            if (intf->IPv6Available) mDNSSendDNSMessage(m, &m->omsg, queryptr, intf->InterfaceID, mDNSNULL, mDNSNULL, &AllDNSLinkGroup_v6, MulticastDNSPort, mDNSNULL, useBackgroundTrafficClass);
             if (!m->SuppressSending) m->SuppressSending = NonZeroTime(m->timenow + (mDNSPlatformOneSecond+9)/10);
             if (++pktcount >= 1000)
             { LogMsg("SendQueries exceeded loop limit %d: giving up", pktcount); break; }
@@ -4000,7 +4054,7 @@ mDNSlocal void SendQueries(mDNS *const m)
         {
             if (ar->ARType != AuthRecordLocalOnly && ar->ARType != AuthRecordP2P)
                 LogInfo("SendQueries: No active interface %d to send probe: %d %s",
-                    (uint32_t)ar->SendRNow, (uint32_t)ar->resrec.InterfaceID, ARDisplayString(m, ar));
+                        IIDPrintable(ar->SendRNow), IIDPrintable(ar->resrec.InterfaceID), ARDisplayString(m, ar));
             ar->SendRNow = mDNSNULL;
         }
 
@@ -4035,7 +4089,7 @@ mDNSlocal void SendQueries(mDNS *const m)
             // so don't log the warning in that case.
             if (q->InterfaceID != mDNSInterface_BLE)
                 LogInfo("SendQueries: No active interface %d to send %s question: %d %##s (%s)",
-                    (uint32_t)q->SendQNow, x ? "new" : "old", (uint32_t)q->InterfaceID, q->qname.c, DNSTypeName(q->qtype));
+                        IIDPrintable(q->SendQNow), x ? "new" : "old", IIDPrintable(q->InterfaceID), q->qname.c, DNSTypeName(q->qtype));
             q->SendQNow = mDNSNULL;
         }
         q->CachedAnswerNeedsUpdate = mDNSfalse;
@@ -4105,6 +4159,44 @@ mDNSlocal void ResetQuestionState(mDNS *const m, DNSQuestion *q)
     debugf("ResetQuestionState: Set MaxQuestionInterval for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 }
 
+mDNSlocal void AdjustUnansweredQueries(mDNS *const m, CacheRecord *const rr)
+{
+    const mDNSs32 expireTime = RRExpireTime(rr);
+    const mDNSu32 interval = TicksTTL(rr) / 20; // Calculate 5% of the cache record's TTL.
+    mDNSu32 rem;
+
+    // If the record is expired or UnansweredQueries is already at the max, then return early.
+    if (((m->timenow - expireTime) >= 0) || (rr->UnansweredQueries >= MaxUnansweredQueries)) return;
+
+    if (interval == 0)
+    {
+        LogInfo("AdjustUnansweredQueries: WARNING: unusually small TTL (%d ticks) for %s", TicksTTL(rr), CRDisplayString(m, rr));
+        return;
+    }
+
+    // Calculate the number of whole 5% TTL intervals between now and expiration time.
+    rem = ((mDNSu32)(expireTime - m->timenow)) / interval;
+
+    // Calculate the expected number of remaining refresher queries.
+    // Refresher queries are sent at the start of the last MaxUnansweredQueries intervals.
+    if (rem > MaxUnansweredQueries) rem = MaxUnansweredQueries;
+
+    // If the current number of remaining refresher queries is greater than expected, then at least one refresher query time
+    // was missed. This can happen if the cache record didn't have an active question during any of the times at which
+    // refresher queries would have been sent if the cache record did have an active question. The cache record's
+    // UnansweredQueries count needs to be adjusted to avoid a burst of refresher queries being sent in an attempt to make up
+    // for lost time. UnansweredQueries is set to the number of queries that would have been sent had the cache record had an
+    // active question from the 80% point of its lifetime up to now, with one exception: if the number of expected remaining
+    // refresher queries is zero (because timenow is beyond the 95% point), then UnansweredQueries is set to
+    // MaxUnansweredQueries - 1 so that at least one refresher query is sent before the cache record expires.
+       // Note: The cast is safe because rem is never greater than MaxUnansweredQueries; the comparison has to be signed.
+    if ((MaxUnansweredQueries - rr->UnansweredQueries) > (mDNSs32)rem)
+    {
+        if (rem == 0) rem++;
+        rr->UnansweredQueries = (mDNSu8)(MaxUnansweredQueries - rem);
+    }
+}
+
 // 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,
@@ -4149,7 +4241,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
         return;
     }
 
-    if (QuerySuppressed(q))
+    if (q->Suppressed && (AddRecord != QC_suppressed))
     {
         // If the query is suppressed, then we don't want to answer from the cache. But if this query is
         // supposed to time out, we still want to callback the clients. We do this only for TimeoutQuestions
@@ -4162,7 +4254,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
     if (AddRecord == QC_add && Question_uDNS(q) && rr->resrec.RecordType != kDNSRecordTypePacketNegative &&
         q->allowExpired != AllowExpired_None && rr->resrec.mortality == Mortality_Mortal ) rr->resrec.mortality = Mortality_Immortal; // Update a non-expired cache record to immortal if appropriate
     
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     if ((AddRecord == QC_add) && Question_uDNS(q) && !followcname)
     {
         const domainname *  queryName;
@@ -4182,13 +4274,9 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
                 responseLatencyMs = 0;
             }
 
-            MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, q->metrics.expiredAnswerState, responseLatencyMs, isForCellular);
+            MetricsUpdateDNSQueryStats(queryName, q->qtype, &rr->resrec, q->metrics.querySendCount, q->metrics.expiredAnswerState, q->metrics.dnsOverTCPState, responseLatencyMs, isForCellular);
             q->metrics.answered = mDNStrue;
         }
-        if (q->metrics.querySendCount > 0)
-        {
-            MetricsUpdateDNSResolveStats(queryName, &rr->resrec, isForCellular);
-        }
     }
 #endif
     // Note: Use caution here. In the case of records with rr->DelayDelivery set, AnswerCurrentQuestionWithResourceRecord(... mDNStrue)
@@ -4197,10 +4285,14 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
 
     if (AddRecord == QC_add && !q->DuplicateOf && rr->CRActiveQuestion != q && rr->resrec.mortality != Mortality_Ghost)
     {
-        if (!rr->CRActiveQuestion) m->rrcache_active++; // If not previously active, increment rrcache_active count
         debugf("AnswerCurrentQuestionWithResourceRecord: Updating CRActiveQuestion from %p to %p for cache record %s, CurrentAnswer %d",
                rr->CRActiveQuestion, q, CRDisplayString(m,rr), q->CurrentAnswers);
-        rr->CRActiveQuestion = q;                       // We know q is non-null
+        if (!rr->CRActiveQuestion)
+        {
+            m->rrcache_active++;            // If not previously active, increment rrcache_active count
+            AdjustUnansweredQueries(m, rr); // Adjust UnansweredQueries in case the record missed out on refresher queries
+        }
+        rr->CRActiveQuestion = q;           // We know q is non-null
         SetNextCacheCheckTimeForRecord(m, rr);
     }
 
@@ -4220,7 +4312,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
 
     if (rr->DelayDelivery) return;      // We'll come back later when CacheRecordDeferredAdd() calls us
 
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
     // If DNS64StateMachine() returns true, then the question was restarted as a different question, so return.
     if (!mDNSOpaque16IsZero(q->TargetQID) && DNS64StateMachine(m, q, &rr->resrec, AddRecord)) return;
 #endif
@@ -4266,7 +4358,7 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
         }
         else
         {
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
             if (DNS64ShouldAnswerQuestion(q, &rr->resrec))
             {
                 DNS64AnswerCurrentQuestion(m, &rr->resrec, AddRecord);
@@ -4279,6 +4371,11 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
         }
         mDNS_ReclaimLockAfterCallback();    // Decrement mDNS_reentrancy to block mDNS API calls again
     }
+    // Note: Proceed with caution after this point because client callback function
+    // invoked above is allowed to do anything, such as starting/stopping queries
+    // (including this one itself, or the next or previous query in the linked list),
+    // registering/deregistering records, starting/stopping NAT traversals, etc.
+
     // If this is an "Add" operation and this question needs validation, validate the response.
     // In the case of negative responses, extra care should be taken. Negative cache records are
     // used for many purposes. For example,
@@ -4321,9 +4418,9 @@ mDNSexport void AnswerCurrentQuestionWithResourceRecord(mDNS *const m, CacheReco
     }
 }
 
-mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
+mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *cr)
 {
-    rr->DelayDelivery = 0;
+    cr->DelayDelivery = 0;
     if (m->CurrentQuestion)
         LogMsg("CacheRecordDeferredAdd ERROR m->CurrentQuestion already set: %##s (%s)",
                m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
@@ -4331,8 +4428,8 @@ mDNSlocal void CacheRecordDeferredAdd(mDNS *const m, CacheRecord *rr)
     while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
     {
         DNSQuestion *q = m->CurrentQuestion;
-        if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-            AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+        if (CacheRecordAnswersQuestion(cr, q))
+            AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
         if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
             m->CurrentQuestion = q->next;
     }
@@ -4369,7 +4466,7 @@ mDNSlocal mDNSs32 CheckForSoonToExpireRecords(mDNS *const m, const domainname *c
 // 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)
+mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *cr)
 {
     DNSQuestion *q;
 
@@ -4377,7 +4474,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
     // counters here we'll end up double-incrementing them when we do it again in AnswerNewQuestion().
     for (q = m->Questions; q && q != m->NewQuestions; q=q->next)
     {
-        if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+        if (CacheRecordAnswersQuestion(cr, 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,
@@ -4398,28 +4495,28 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
                     SetNextQueryTime(m,q);
                 }
             }
-            verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", rr, rr->resrec.name->c,
-                          DNSTypeName(rr->resrec.rrtype), rr->resrec.rroriginalttl, rr->resrec.rDNSServer ?
-                          &rr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(rr->resrec.rDNSServer ?
-                                                                             rr->resrec.rDNSServer->port : zeroIPPort), q);
+            verbosedebugf("CacheRecordAdd %p %##s (%s) %lu %#a:%d question %p", cr, cr->resrec.name->c,
+                          DNSTypeName(cr->resrec.rrtype), cr->resrec.rroriginalttl, cr->resrec.rDNSServer ?
+                          &cr->resrec.rDNSServer->addr : mDNSNULL, mDNSVal16(cr->resrec.rDNSServer ?
+                                                                             cr->resrec.rDNSServer->port : zeroIPPort), q);
             q->CurrentAnswers++;
 
             q->unansweredQueries = 0;
-            if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
-            if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+            if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+            if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
             if (q->CurrentAnswers > 4000)
             {
                 static int msgcount = 0;
                 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 = 0;
-                rr->UnansweredQueries = MaxUnansweredQueries;
+                cr->resrec.rroriginalttl = 0;
+                cr->UnansweredQueries = MaxUnansweredQueries;
             }
         }
     }
 
-    if (!rr->DelayDelivery)
+    if (!cr->DelayDelivery)
     {
         if (m->CurrentQuestion)
             LogMsg("CacheRecordAdd ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
@@ -4427,15 +4524,15 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
         while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
         {
             q = m->CurrentQuestion;
-            if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-                AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+            if (CacheRecordAnswersQuestion(cr, q))
+                AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
             if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
                 m->CurrentQuestion = q->next;
         }
         m->CurrentQuestion = mDNSNULL;
     }
 
-    SetNextCacheCheckTimeForRecord(m, rr);
+    SetNextCacheCheckTimeForRecord(m, cr);
 }
 
 // NoCacheAnswer is only called from mDNSCoreReceiveResponse, *never* directly as a result of a client API call.
@@ -4448,7 +4545,7 @@ mDNSlocal void CacheRecordAdd(mDNS *const m, CacheRecord *rr)
 // 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)
+mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *cr)
 {
     LogMsg("No cache space: Delivering non-cached result for %##s", m->rec.r.resrec.name->c);
     if (m->CurrentQuestion)
@@ -4459,8 +4556,8 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
     while (m->CurrentQuestion)
     {
         DNSQuestion *q = m->CurrentQuestion;
-        if (ResourceRecordAnswersQuestion(&rr->resrec, q))
-            AnswerCurrentQuestionWithResourceRecord(m, rr, QC_addnocache);  // QC_addnocache means "don't expect remove events for this"
+        if (CacheRecordAnswersQuestion(cr, q))
+            AnswerCurrentQuestionWithResourceRecord(m, cr, 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;
     }
@@ -4471,12 +4568,12 @@ mDNSlocal void NoCacheAnswer(mDNS *const m, CacheRecord *rr)
 // Note that CacheRecordRmv is *only* called for records that are referenced by at least one active question.
 // If new questions are created as a result of invoking client callbacks, they will be added to
 // the end of the question list, and m->NewQuestions will be set to indicate the first new question.
-// rr is an existing cache CacheRecord that just expired and is being deleted
+// cr is an existing cache CacheRecord that just expired and is being deleted
 // (kDNSRecordTypePacketAns/PacketAnsUnique/PacketAdd/PacketAddUnique).
 // Note: CacheRecordRmv calls AnswerCurrentQuestionWithResourceRecord which can call a user callback,
 // 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)
+mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *cr)
 {
     if (m->CurrentQuestion)
         LogMsg("CacheRecordRmv ERROR m->CurrentQuestion already set: %##s (%s)",
@@ -4492,10 +4589,10 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
         // response. A cache may be present that answers this question e.g., cache entry generated
         // before the question became suppressed. We need to skip the suppressed questions here as
         // the RMV event has already been generated.
-        if (!QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q) &&
-            (q->allowExpired == AllowExpired_None || rr->resrec.mortality == Mortality_Mortal))
+        if (!q->Suppressed && CacheRecordAnswersQuestion(cr, q) &&
+            (q->allowExpired == AllowExpired_None || cr->resrec.mortality == Mortality_Mortal))
         {
-            verbosedebugf("CacheRecordRmv %p %s", rr, CRDisplayString(m, rr));
+            verbosedebugf("CacheRecordRmv %p %s", cr, CRDisplayString(m, cr));
             q->FlappingInterface1 = mDNSNULL;
             q->FlappingInterface2 = mDNSNULL;
 
@@ -4506,8 +4603,8 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
             else
             {
                 q->CurrentAnswers--;
-                if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
-                if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+                if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+                if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
             }
 
             // If we have dropped below the answer threshold for this mDNS question,
@@ -4520,15 +4617,15 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
                 LogInfo("CacheRecordRmv: (%s) %##s dropped below threshold of %d answers",
                     DNSTypeName(q->qtype), q->qname.c, q->BrowseThreshold);
             }
-            if (rr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
+            if (cr->resrec.rdata->MaxRDLength) // Never generate "remove" events for negative results
             {
                 if ((q->CurrentAnswers == 0) && mDNSOpaque16IsZero(q->TargetQID))
                 {
                     LogInfo("CacheRecordRmv: Last answer for %##s (%s) expired from cache; will reconfirm antecedents",
                             q->qname.c, DNSTypeName(q->qtype));
-                    ReconfirmAntecedents(m, &q->qname, q->qnamehash, rr->resrec.InterfaceID, 0);
+                    ReconfirmAntecedents(m, &q->qname, q->qnamehash, cr->resrec.InterfaceID, 0);
                 }
-                AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+                AnswerCurrentQuestionWithResourceRecord(m, cr, QC_rmv);
             }
         }
         if (m->CurrentQuestion == q)    // If m->CurrentQuestion was not auto-advanced, do it ourselves now
@@ -4539,7 +4636,7 @@ mDNSlocal void CacheRecordRmv(mDNS *const m, CacheRecord *rr)
 
 mDNSlocal void ReleaseCacheEntity(mDNS *const m, CacheEntity *e)
 {
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
     unsigned int i;
     for (i=0; i<sizeof(*e); i++) ((char*)e)[i] = 0xFF;
 #endif
@@ -4617,13 +4714,6 @@ mDNSexport void ReleaseCacheRecord(mDNS *const m, CacheRecord *r)
     }
     r->resrec.name = mDNSNULL;
 
-    if (r->resrec.AnonInfo)
-    {
-        debugf("ReleaseCacheRecord: freeing AnonInfo for %##s (%s)", r->resrec.name->c, DNSTypeName(r->resrec.rrtype));
-        FreeAnonInfo((void *)r->resrec.AnonInfo);
-    }
-    r->resrec.AnonInfo = mDNSNULL;
-
     if (!r->resrec.InterfaceID)
     {
         m->rrcache_totalused_unicast -= r->resrec.rdlength;
@@ -4666,7 +4756,8 @@ mDNSlocal void CheckCacheExpiration(mDNS *const m, const mDNSu32 slot, CacheGrou
                 // a normal deferred ADD case, then AnswerCurrentQuestionWithResourceRecord will reset it to
                 // MaxQuestionInterval. If we have inactive questions referring to negative cache entries,
                 // don't ressurect them as they will deliver duplicate "No such Record" ADD events
-                if (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived && ActiveQuestion(q))
+                if (((mDNSOpaque16IsZero(q->TargetQID) && (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)) ||
+                     (!mDNSOpaque16IsZero(q->TargetQID) && !q->LongLived)) && ActiveQuestion(q))
                 {
                     q->ThisQInterval = InitialQuestionInterval;
                     q->LastQTime     = m->timenow - q->ThisQInterval;
@@ -4778,7 +4869,7 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN
                         m->CurrentRecord = mDNSNULL;
                         return mDNStrue;
                     }
-                    AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+                    AnswerLocalQuestionWithLocalAuthRecord(m, rr, QC_add);
                     if (m->CurrentQuestion != q)
                         break;     // If callback deleted q, then we're finished here
                 }
@@ -4823,45 +4914,29 @@ mDNSlocal mDNSBool AnswerQuestionWithLORecord(mDNS *const m, DNSQuestion *q, mDN
 
 // Today, we suppress questions (not send them on the wire) for several reasons e.g.,
 // AAAA query is suppressed because no IPv6 capability or PID is not allowed to make
-// DNS requests. We need to temporarily suspend the suppress status so that we can
-// deliver a negative response (AnswerCurrentQuestionWithResourceRecord does not answer
-// suppressed questions) and reset it back. In the future, if there are other
-// reasons for suppressing the query, this function should be updated.
+// DNS requests.
 mDNSlocal void AnswerSuppressedQuestion(mDNS *const m, DNSQuestion *q)
 {
-    mDNSBool SuppressQuery;
-    mDNSBool DisallowPID;
-
-    // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response, just
-    // deactivate the DNSQuestion.
-    if (!q->ReturnIntermed)
+    // If the client did not set the kDNSServiceFlagsReturnIntermediates flag, then don't generate a negative response,
+    // just deactivate the DNSQuestion.
+    if (q->ReturnIntermed)
+    {
+        GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed);
+    }
+    else
     {
         q->ThisQInterval = 0;
-        return;
     }
-
-    SuppressQuery = q->SuppressQuery;
-    DisallowPID   = q->DisallowPID;
-
-    // make sure that QuerySuppressed() returns false
-    q->SuppressQuery = mDNSfalse;
-    q->DisallowPID   = mDNSfalse;
-
-    GenerateNegativeResponse(m, mDNSInterface_Any, QC_suppressed);
-
-    q->SuppressQuery = SuppressQuery;
-    q->DisallowPID   = DisallowPID;
 }
 
 mDNSlocal void AnswerNewQuestion(mDNS *const m)
 {
     mDNSBool ShouldQueryImmediately = mDNStrue;
     DNSQuestion *const q = m->NewQuestions;     // Grab the question we're going to answer
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
     if (!mDNSOpaque16IsZero(q->TargetQID)) DNS64HandleNewQuestion(m, q);
 #endif
     CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
-    mDNSBool AnsweredFromCache = mDNSfalse;
 
     verbosedebugf("AnswerNewQuestion: Answering %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
@@ -4891,14 +4966,21 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
     // 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: %##s (%s)",
-               m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+    if (m->CurrentQuestion) {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d->Q%d] AnswerNewQuestion ERROR m->CurrentQuestion already set: " PRI_DM_NAME " (" PUB_S ")",
+               m->CurrentQuestion->request_id, mDNSVal16(m->CurrentQuestion->TargetQID),
+               DM_NAME_PARAM(m->CurrentQuestion->qname.c), DNSTypeName(m->CurrentQuestion->qtype));
+    }
+
     m->CurrentQuestion = q;     // Indicate which question we're answering, so we'll know if it gets deleted
 
     if (q->NoAnswer == NoAnswer_Fail)
     {
-        LogMsg("AnswerNewQuestion: NoAnswer_Fail %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d->Q%d] AnswerNewQuestion: NoAnswer_Fail " PRI_DM_NAME " (" PUB_S ")",
+               q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
+
         MakeNegativeCacheRecord(m, &m->rec.r, &q->qname, q->qnamehash, q->qtype, q->qclass, 60, mDNSInterface_Any, q->qDNSServer);
         q->NoAnswer = NoAnswer_Normal;      // Temporarily turn off answer suppression
         AnswerCurrentQuestionWithResourceRecord(m, &m->rec.r, QC_addnocache);
@@ -4918,65 +5000,53 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
     if (AnswerQuestionWithLORecord(m, q, mDNSfalse))
         goto exit;
 
-    // If we are not supposed to answer this question, generate a negative response.
-    // Temporarily suspend the SuppressQuery so that AnswerCurrentQuestionWithResourceRecord can answer the question
-    //
     // If it is a question trying to validate some response, it already checked the cache for a response. If it still
     // reissues a question it means it could not find the RRSIGs. So, we need to bypass the cache check and send
     // the question out.
-    if (QuerySuppressed(q))
+    if (q->Suppressed)
     {
         AnswerSuppressedQuestion(m, q);
     }
     else if (!q->ValidatingResponse)
     {
-        CacheRecord *rr;
-        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-            if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+        CacheRecord *cr;
+        for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+            if (SameNameCacheRecordAnswersQuestion(cr, q))
             {
                 // SecsSinceRcvd is whole number of elapsed seconds, rounded down
-                mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - rr->TimeRcvd)) / mDNSPlatformOneSecond;
-                if (rr->resrec.rroriginalttl <= SecsSinceRcvd && q->allowExpired != AllowExpired_AllowExpiredAnswers) continue;   // Go to next one in loop
+                mDNSu32 SecsSinceRcvd = ((mDNSu32)(m->timenow - cr->TimeRcvd)) / mDNSPlatformOneSecond;
+                mDNSBool IsExpired = (cr->resrec.rroriginalttl <= SecsSinceRcvd);
+                if (IsExpired && q->allowExpired != AllowExpired_AllowExpiredAnswers) 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))
+                if ((cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) || (q->ExpectUnique))
                     ShouldQueryImmediately = mDNSfalse;
                 q->CurrentAnswers++;
-                if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
-                if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
-                AnsweredFromCache = mDNStrue;
-#if AWD_METRICS
-                if (q->metrics.expiredAnswerState == ExpiredAnswer_Allowed) q->metrics.expiredAnswerState = ExpiredAnswer_AnsweredWithExpired;
+                if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers++;
+                if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers++;
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+                if (q->metrics.expiredAnswerState == ExpiredAnswer_Allowed) q->metrics.expiredAnswerState = IsExpired ? ExpiredAnswer_AnsweredWithExpired : ExpiredAnswer_AnsweredWithCache;
 #endif
-                AnswerCurrentQuestionWithResourceRecord(m, rr, QC_add);
+                AnswerCurrentQuestionWithResourceRecord(m, cr, QC_add);
                 if (m->CurrentQuestion != q) break;     // If callback deleted q, then we're finished here
             }
-            else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(rr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
+            else if (mDNSOpaque16IsZero(q->TargetQID) && RRTypeIsAddressType(cr->resrec.rrtype) && RRTypeIsAddressType(q->qtype))
                 ShouldQueryImmediately = mDNSfalse;
     }
     // We don't use LogInfo for this "Question deleted" message because it happens so routinely that
     // it's not remotely remarkable, and therefore unlikely to be of much help tracking down bugs.
     if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving cache answers"); goto exit; }
 
-    // Neither a local record nor a cache entry could answer this question. If this question need to be retried
-    // with search domains, generate a negative response which will now retry after appending search domains.
-    // If the query was suppressed above, we already generated a negative response. When it gets unsuppressed,
-    // we will retry with search domains.
-    if (!QuerySuppressed(q) && !AnsweredFromCache && q->RetryWithSearchDomains)
-    {
-        LogInfo("AnswerNewQuestion: Generating response for retrying with search domains %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
-    }
-
-    if (m->CurrentQuestion != q) { debugf("AnswerNewQuestion: Question deleted while giving negative answer"); goto exit; }
-
+    q->InitialCacheMiss  = mDNStrue;                                    // Initial cache check is done, so mark as a miss from now on
     if (q->allowExpired == AllowExpired_AllowExpiredAnswers)
     {
         q->allowExpired = AllowExpired_MakeAnswersImmortal;             // After looking through the cache for an answer, demote to make immortal
         if (q->firstExpiredQname.c[0])                                  // If an original query name was saved on an expired answer, start it over in case it is updated
         {
-            LogMsg("AnswerNewQuestion: Restarting original question %p firstExpiredQname %##s for allowExpiredAnswers question", q, &q->firstExpiredQname.c);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                   "[R%d->Q%d] AnswerNewQuestion: Restarting original question %p firstExpiredQname " PRI_DM_NAME " for allowExpiredAnswers question",
+                   q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(&q->firstExpiredQname.c));
             mDNS_StopQuery_internal(m, q);                              // Stop old query
             AssignDomainName(&q->qname, &q->firstExpiredQname);         // Update qname
             q->qnamehash = DomainNameHashValue(&q->qname);              // and namehash
@@ -4990,7 +5060,7 @@ mDNSlocal void AnswerNewQuestion(mDNS *const m)
     // Hence we don't execute the following block of code for those cases.
     if (ShouldQueryImmediately && ActiveQuestion(q))
     {
-        debugf("AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+        debugf("[R%d->Q%d] AnswerNewQuestion: ShouldQueryImmediately %##s (%s)", q->request_id, mDNSVal16(q->TargetQID), q->qname.c, DNSTypeName(q->qtype));
         q->ThisQInterval  = InitialQuestionInterval;
         q->LastQTime      = m->timenow - q->ThisQInterval;
         if (mDNSOpaque16IsZero(q->TargetQID))       // For mDNS, spread packets to avoid a burst of simultaneous queries
@@ -5047,7 +5117,7 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
             if (LocalOnlyRecordAnswersQuestion(rr, q))
             {
                 retEv = mDNStrue;
-                AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+                AnswerLocalQuestionWithLocalAuthRecord(m, rr, QC_add);
                 if (m->CurrentQuestion != q) break;     // If callback deleted q, then we're finished here
             }
         }
@@ -5059,12 +5129,12 @@ mDNSlocal void AnswerNewLocalOnlyQuestion(mDNS *const m)
 
         while (m->CurrentRecord && m->CurrentRecord != m->NewLocalRecords)
         {
-            AuthRecord *rr = m->CurrentRecord;
-            m->CurrentRecord = rr->next;
-            if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+            AuthRecord *ar = m->CurrentRecord;
+            m->CurrentRecord = ar->next;
+            if (AuthRecordAnswersQuestion(ar, q))
             {
                 retEv = mDNStrue;
-                AnswerLocalQuestionWithLocalAuthRecord(m, rr, mDNStrue);
+                AnswerLocalQuestionWithLocalAuthRecord(m, ar, QC_add);
                 if (m->CurrentQuestion != q) break;     // If callback deleted q, then we're finished here
             }
         }
@@ -5090,8 +5160,11 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
     if (!m->rrcache_free && m->MainCallback)
     {
         if (m->rrcache_totalused != m->rrcache_size)
-            LogMsg("GetFreeCacheRR: count mismatch: m->rrcache_totalused %lu != m->rrcache_size %lu",
-                   m->rrcache_totalused, m->rrcache_size);
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                      "GetFreeCacheRR: count mismatch: m->rrcache_totalused %u != m->rrcache_size %u",
+                      m->rrcache_totalused, m->rrcache_size);
+        }
 
         // 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.
@@ -5099,8 +5172,11 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
         // 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 > 5000 && m->rrcache_size / 32 > m->rrcache_active)
-            LogInfo("Possible denial-of-service attack in progress: m->rrcache_size %lu; m->rrcache_active %lu",
-                    m->rrcache_size, m->rrcache_active);
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                      "Possible denial-of-service attack in progress: m->rrcache_size %u; m->rrcache_active %u",
+                      m->rrcache_size, m->rrcache_active);
+        }
         else
         {
             mDNS_DropLockBeforeCallback();      // Allow client to legally make mDNS API calls from the callback
@@ -5141,8 +5217,8 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
                 else ReleaseCacheGroup(m, cp);
             }
         }
-        LogInfo("GetCacheEntity recycled %d records to reduce cache from %d to %d",
-                oldtotalused - m->rrcache_totalused, oldtotalused, m->rrcache_totalused);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "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
@@ -5151,7 +5227,7 @@ mDNSlocal CacheEntity *GetCacheEntity(mDNS *const m, const CacheGroup *const Pre
         m->rrcache_free = e->next;
         if (++m->rrcache_totalused >= m->rrcache_report)
         {
-            LogInfo("RR Cache now using %ld objects", m->rrcache_totalused);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "RR Cache now using %u objects", m->rrcache_totalused);
             if      (m->rrcache_report <  100) m->rrcache_report += 10;
             else if (m->rrcache_report < 1000) m->rrcache_report += 100;
             else m->rrcache_report += 1000;
@@ -5172,7 +5248,7 @@ mDNSlocal CacheRecord *GetCacheRecord(mDNS *const m, CacheGroup *cg, mDNSu16 RDL
         r->resrec.rdata = (RData*)&r->smallrdatastorage;    // By default, assume we're usually going to be using local storage
         if (RDLength > InlineCacheRDSize)           // If RDLength is too big, allocate extra storage
         {
-            r->resrec.rdata = (RData*)mDNSPlatformMemAllocate(sizeofRDataHeader + RDLength);
+            r->resrec.rdata = (RData*) mDNSPlatformMemAllocateClear(sizeofRDataHeader + RDLength);
             if (r->resrec.rdata) r->resrec.rdata->MaxRDLength = r->resrec.rdlength = RDLength;
             else { ReleaseCacheEntity(m, (CacheEntity*)r); r = mDNSNULL; }
         }
@@ -5190,7 +5266,7 @@ mDNSlocal CacheGroup *GetCacheGroup(mDNS *const m, const mDNSu32 slot, const Res
     cg->members      = mDNSNULL;
     cg->rrcache_tail = &cg->members;
     if (namelen > sizeof(cg->namestorage))
-        cg->name = mDNSPlatformMemAllocate(namelen);
+        cg->name = (domainname *) mDNSPlatformMemAllocate(namelen);
     else
         cg->name = (domainname*)cg->namestorage;
     if (!cg->name)
@@ -5287,7 +5363,7 @@ mDNSlocal void CheckRmvEventsForLocalRecords(mDNS *const m)
         {
             debugf("CheckRmvEventsForLocalRecords: Generating local RMV events for %s", ARDisplayString(m, rr));
             rr->resrec.RecordType = kDNSRecordTypeShared;
-            AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNSfalse);
+            AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_rmv);
             if (m->CurrentRecord == rr) // If rr still exists in list, restore its state now
             {
                 rr->resrec.RecordType = kDNSRecordTypeDeregistering;
@@ -5429,7 +5505,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
             mDNS_SendKeepalives(m);
         }
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
         if (m->NextBonjourDisableTime && (m->timenow - m->NextBonjourDisableTime >= 0))
         {
             // Schedule immediate network change processing to leave the multicast group
@@ -5440,15 +5516,12 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
 
             LogInfo("mDNS_Execute: Scheduled network changed processing to leave multicast group.");
         }
-#endif // BONJOUR_ON_DEMAND
+#endif
 
         // Clear AnnounceOwner if necessary. (Do this *before* SendQueries() and SendResponses().)
         if (m->AnnounceOwner && m->timenow - m->AnnounceOwner >= 0)
         {
             m->AnnounceOwner = 0;
-
-            // This is a good time to reset the delay counter used to prevent spurious conflicts
-            m->DelayConflictProcessing = 0;
         }
 
         if (m->DelaySleep && m->timenow - m->DelaySleep >= 0)
@@ -5498,7 +5571,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
             if (LocalRecordReady(rr))
             {
                 debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
-                AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+                AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_add);
             }
             else if (!rr->next)
             {
@@ -5545,6 +5618,7 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
         {
             m->NewLocalOnlyRecords = mDNSfalse;
             for (slot = 0; slot < AUTH_HASH_SLOTS; slot++)
+            {
                 for (ag = m->rrauth.rrauth_hash[slot]; ag; ag = ag->next)
                 {
                     for (i=0; i<100 && ag->NewLocalOnlyRecords; i++)
@@ -5555,13 +5629,14 @@ mDNSexport mDNSs32 mDNS_Execute(mDNS *const m)
                         if (LocalRecordReady(rr))
                         {
                             debugf("mDNS_Execute: Delivering Add event with LocalAuthRecord %s", ARDisplayString(m, rr));
-                            AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, mDNStrue);
+                            AnswerAllLocalQuestionsWithLocalAuthRecord(m, rr, QC_add);
                         }
                         else LogMsg("mDNS_Execute: LocalOnlyRecord %s not ready", ARDisplayString(m, rr));
                     }
                     // We limit about 100 per AuthGroup that can be serviced at a time
                     if (i >= 100) LogMsg("mDNS_Execute: ag->NewLocalOnlyRecords exceeded loop limit");
                 }
+            }
         }
 
         // 5. See what packets we need to send
@@ -5683,34 +5758,15 @@ mDNSlocal mDNSBool QuestionHasLocalAnswers(mDNS *const m, DNSQuestion *q)
 // In cases 2 and 3 we do want to cause the question to be resent immediately (ScheduleImmediately is true)
 mDNSlocal void ActivateUnicastQuery(mDNS *const m, DNSQuestion *const question, mDNSBool ScheduleImmediately)
 {
-    // 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
-    // Even though BTMM client tunnels are only useful for AAAA queries, we need to treat v4 and v6 queries equally.
-    // Otherwise we can get the situation where the A query completes really fast (with an NXDOMAIN result) and the
-    // caller then gives up waiting for the AAAA result while we're still in the process of setting up the tunnel.
-    // To level the playing field, we block both A and AAAA queries while tunnel setup is in progress, and then
-    // returns results for both at the same time. If we are looking for the _autotunnel6 record, then skip this logic
-    // as this would trigger looking up _autotunnel6._autotunnel6 and end up failing the original query.
-
-    if (RRTypeIsAddressType(question->qtype) && PrivateQuery(question) &&
-        !SameDomainLabel(question->qname.c, (const mDNSu8 *)"\x0c_autotunnel6")&& question->QuestionCallback != AutoTunnelCallback)
-    {
-        question->NoAnswer = NoAnswer_Suspended;
-        AddNewClientTunnel(question);
-        return;
-    }
-#endif // APPLE_OSX_mDNSResponder
-
     if (!question->DuplicateOf)
     {
-        debugf("ActivateUnicastQuery: %##s %s%s%s",
-               question->qname.c, DNSTypeName(question->qtype), PrivateQuery(question) ? " (Private)" : "", ScheduleImmediately ? " ScheduleImmediately" : "");
+        debugf("ActivateUnicastQuery: %##s %s%s",
+               question->qname.c, DNSTypeName(question->qtype), ScheduleImmediately ? " ScheduleImmediately" : "");
         question->CNAMEReferrals = 0;
         if (question->nta) { CancelGetZoneData(m, question->nta); question->nta = mDNSNULL; }
         if (question->LongLived)
         {
-            question->state = LLQ_InitialRequest;
+            question->state = LLQ_Init;
             question->id = zeroOpaque64;
             question->servPort = zeroIPPort;
             if (question->tcp) { DisposeTCPConn(question->tcp); question->tcp = mDNSNULL; }
@@ -5798,23 +5854,13 @@ mDNSexport void mDNSCoreRestartAddressQueries(mDNS *const m, mDNSBool SearchDoma
             // If the query is suppressed, the RMV events won't be delivered
             if (!CacheRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Cache Record RMV events"); continue; }
 
-            // SuppressQuery status does not affect questions that are answered using local records
+            // Suppressed status does not affect questions that are answered using local records
             if (!LocalRecordRmvEventsForQuestion(m, q)) { LogInfo("mDNSCoreRestartAddressQueries: Question deleted while delivering Local Record RMV events"); continue; }
 
-            LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d, qnameOrig %p", q,
-                    q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains, q->qnameOrig);
+            LogInfo("mDNSCoreRestartAddressQueries: Stop question %p %##s (%s), AppendSearchDomains %d", q,
+                    q->qname.c, DNSTypeName(q->qtype), q->AppendSearchDomains);
             mDNS_StopQuery_internal(m, q);
-            // Reset state so that it looks like it was in the beginning i.e it should look at /etc/hosts, cache
-            // and then search domains should be appended. At the beginning, qnameOrig was NULL.
-            if (q->qnameOrig)
-            {
-                LogInfo("mDNSCoreRestartAddressQueries: qnameOrig %##s", q->qnameOrig);
-                AssignDomainName(&q->qname, q->qnameOrig);
-                mDNSPlatformMemFree(q->qnameOrig);
-                q->qnameOrig = mDNSNULL;
-                q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
-            }
-            q->SearchListIndex = 0;
+            if (q->ResetHandler) q->ResetHandler(q);
             q->next = restart;
             restart = q;
         }
@@ -6115,7 +6161,7 @@ mDNSexport mStatus UpdateKeepaliveRData(mDNS *const m, AuthRecord *rr, NetworkIn
     newrdlength += 2;
 
     rdsize = newrdlength > sizeof(RDataBody) ? newrdlength : sizeof(RDataBody);
-    newrd = mDNSPlatformMemAllocate(sizeof(RData) - sizeof(RDataBody) + rdsize);
+    newrd = (RData *) mDNSPlatformMemAllocate(sizeof(RData) - sizeof(RDataBody) + rdsize);
     if (!newrd) { LogMsg("UpdateKeepaliveRData: ptr NULL"); return mStatus_NoMemoryErr; }
 
     newrd->MaxRDLength = (mDNSu16) rdsize;
@@ -6269,7 +6315,7 @@ mDNSlocal void SendSPSRegistrationForOwner(mDNS *const m, NetworkInterfaceInfo *
                 LogSPS("SendSPSRegistration: Sending Update %s %d (%d) id %5d with %d records %d bytes to %#a:%d", intf->ifname, intf->NextSPSAttempt, sps,
                        mDNSVal16(m->omsg.h.id), m->omsg.h.mDNS_numUpdates, p - m->omsg.data, &intf->SPSAddr[sps], mDNSVal16(intf->SPSPort[sps]));
                 // if (intf->NextSPSAttempt < 5) m->omsg.h.flags = zeroID;  // For simulating packet loss
-                err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSNULL, mDNSfalse);
+                err = mDNSSendDNSMessage(m, &m->omsg, p, intf->InterfaceID, mDNSNULL, mDNSNULL, &intf->SPSAddr[sps], intf->SPSPort[sps], mDNSNULL, mDNSfalse);
                 if (err) LogSPS("SendSPSRegistration: mDNSSendDNSMessage err %d", err);
                 if (err && intf->SPSAddr[sps].type == mDNSAddrType_IPv4 && intf->NetWakeResolve[sps].ThisQInterval == -1)
                 {
@@ -6298,15 +6344,13 @@ mDNSlocal mDNSBool RecordIsFirstOccurrenceOfOwner(mDNS *const m, const AuthRecor
 
 mDNSlocal void mDNSCoreStoreProxyRR(mDNS *const m, const mDNSInterfaceID InterfaceID, AuthRecord *const rr)
 {
-    AuthRecord *newRR = mDNSPlatformMemAllocate(sizeof(AuthRecord));
-
+    AuthRecord *newRR = (AuthRecord *) mDNSPlatformMemAllocateClear(sizeof(*newRR));
     if (newRR == mDNSNULL)
     {
         LogSPS("%s : could not allocate memory for new resource record", __func__);
         return;
     }
 
-    mDNSPlatformMemZero(newRR, sizeof(AuthRecord));
     mDNS_SetupResourceRecord(newRR, mDNSNULL, InterfaceID, rr->resrec.rrtype,
                              rr->resrec.rroriginalttl, rr->resrec.RecordType,
                              rr->ARType, mDNSNULL, mDNSNULL);
@@ -6831,7 +6875,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
 {
     AuthRecord *rr;
 
-    LogSPS("%s (old state %d) at %ld", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
+    LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
+        PUB_S " (old state %d) at %d", sleep ? "Sleeping" : "Waking", m->SleepState, m->timenow);
 
     if (sleep && !m->SleepState)        // Going to sleep
     {
@@ -6860,7 +6905,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
         if (m->SystemWakeOnLANEnabled && m->DelaySleep)
         {
             // If we just woke up moments ago, allow ten seconds for networking to stabilize before going back to sleep
-            LogSPS("mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
+            LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+                      "mDNSCoreMachineSleep: Re-sleeping immediately after waking; will delay for %d ticks", m->DelaySleep - m->timenow);
             m->SleepLimit = NonZeroTime(m->DelaySleep + mDNSPlatformOneSecond * 10);
         }
         else
@@ -6874,12 +6920,10 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
 #ifndef UNICAST_DISABLED
         SuspendLLQs(m);
 #endif
-#if APPLE_OSX_mDNSResponder
-        RemoveAutoTunnel6Record(m);
-#endif
-        LogSPS("mDNSCoreMachineSleep: m->SleepState %d (%s) seq %d", m->SleepState,
-               m->SleepState == SleepState_Transferring ? "Transferring" :
-               m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?", m->SleepSeqNum);
+        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "mDNSCoreMachineSleep: m->SleepState %d (" PUB_S ") seq %d",
+                  m->SleepState,
+                  m->SleepState == SleepState_Transferring ? "Transferring" :
+                  m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?", m->SleepSeqNum);
         mDNS_Unlock(m);
     }
     else if (!sleep)        // Waking up
@@ -6912,7 +6956,6 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
             mDNSCoreBeSleepProxyServer_internal(m, m->SPSType, m->SPSPortability, m->SPSMarginalPower, m->SPSTotalPower, m->SPSFeatureFlags);
         }
         m->mDNSStats.Wakes++;
-        m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
         // ... and the same for NextSPSAttempt
         for (intf = GetFirstActiveInterface(m->HostInterfaces); intf; intf = GetFirstActiveInterface(intf->next)) intf->NextSPSAttempt = -1;
 
@@ -6921,7 +6964,8 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
 
         // and reactivtate service registrations
         m->NextSRVUpdate = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
-        LogInfo("mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
+        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+                  "mDNSCoreMachineSleep waking: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
 
         // 2. Re-validate our cache records
         currtime = mDNSPlatformUTC();
@@ -6957,21 +7001,25 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
 
                     if (diff >= remain || diff > (2 * 24 * 3600))
                     {
-                        LogInfo("mDNSCoreMachineSleep: %s: Purging cache entry SleptTime %d, Remaining TTL %d",
-                            CRDisplayString(m, cr), diff, remain);
+                        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+                                  "mDNSCoreMachineSleep: " PRI_S ": Purging cache entry SleptTime %d, Remaining TTL %d",
+                                  CRDisplayString(m, cr), diff, remain);
                         mDNS_PurgeCacheResourceRecord(m, cr);
                         continue;
                     }
                     cr->TimeRcvd -= (diff * mDNSPlatformOneSecond);
                     if (m->timenow - (cr->TimeRcvd + ((mDNSs32)uTTL * mDNSPlatformOneSecond)) >= 0)
                     {
-                        LogInfo("mDNSCoreMachineSleep: %s: Purging after adjusting the remaining TTL %d by %d seconds",
-                            CRDisplayString(m, cr), remain, diff);
+                        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+                                  "mDNSCoreMachineSleep: " PRI_S ": Purging after adjusting the remaining TTL %d by %d seconds",
+                                  CRDisplayString(m, cr), remain, diff);
                         mDNS_PurgeCacheResourceRecord(m, cr);
                     }
                     else
                     {
-                        LogInfo("mDNSCoreMachineSleep: %s: Adjusted the remain ttl %u by %d seconds", CRDisplayString(m, cr), remain, diff);
+                        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+                                  "mDNSCoreMachineSleep: " PRI_S ": Adjusted the remain ttl %u by %d seconds",
+                                  CRDisplayString(m, cr), remain, diff);
                     }
                 }
             }
@@ -7001,7 +7049,7 @@ mDNSexport void mDNSCoreMachineSleep(mDNS *const m, mDNSBool sleep)
         // But if we do get a network configuration change, mDNSMacOSXNetworkChanged will call uDNS_SetupDNSConfig, which
         // will call mDNS_SetPrimaryInterfaceInfo, which will call RecreateNATMappings to refresh them, potentially sooner
         // than five seconds from now.
-        LogInfo("mDNSCoreMachineSleep: recreating NAT mappings in 5 seconds");
+        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG, "mDNSCoreMachineSleep: recreating NAT mappings in 5 seconds");
         RecreateNATMappings(m, mDNSPlatformOneSecond * 5);
         mDNS_Unlock(m);
     }
@@ -7071,9 +7119,6 @@ mDNSexport mDNSBool mDNSCoreReadyForSleep(mDNS *m, mDNSs32 now)
         {
             if (rr->state == regState_Refresh && rr->tcp)
             { LogSPS("mDNSCoreReadyForSleep: waiting for Record updateIntID 0x%x 0x%x (updateid %d) %s", rr->updateIntID.l[1], rr->updateIntID.l[0], mDNSVal16(rr->updateid), ARDisplayString(m,rr)); goto notready; }
-            #if APPLE_OSX_mDNSResponder
-            if (!RecordReadyForSleep(rr)) { LogSPS("mDNSCoreReadyForSleep: waiting for %s", ARDisplayString(m, rr)); goto notready; }
-            #endif
         }
 
     mDNS_Unlock(m);
@@ -7176,7 +7221,7 @@ mDNSlocal mDNSu8 *GenerateUnicastResponse(const DNSMessage *const query, const m
     const mDNSu8    *const limit     = response->data + sizeof(response->data);
     const mDNSu8    *ptr             = query->data;
     AuthRecord  *rr;
-    mDNSu32 maxttl = mDNSMaximumTTLSeconds;
+    mDNSu32 maxttl = (!InterfaceID) ? mDNSMaximumUnicastTTLSeconds : mDNSMaximumMulticastTTLSeconds;
     int i;
 
     // Initialize the response fields so we can answer the questions
@@ -7247,6 +7292,12 @@ mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const
     if (!our) { LogMsg("CompareRData ERROR: our is NULL"); return(+1); }
     if (!pkt) { LogMsg("CompareRData ERROR: pkt is NULL"); return(+1); }
 
+#if defined(__clang_analyzer__)
+    // Get rid of analyzer warnings about ourptr and pktptr pointing to garbage after retruning from putRData().
+    // There are no clear indications from the analyzer of the cause of the supposed problem.
+    mDNSPlatformMemZero(ourdata, 1);
+    mDNSPlatformMemZero(pktdata, 1);
+#endif
     ourend = putRData(mDNSNULL, ourdata, ourdata + sizeof(ourdata), &our->resrec);
     pktend = putRData(mDNSNULL, pktdata, pktdata + sizeof(pktdata), &pkt->resrec);
     while (ourptr < ourend && pktptr < pktend && *ourptr == *pktptr) { ourptr++; pktptr++; }
@@ -7261,6 +7312,17 @@ mDNSlocal int CompareRData(const AuthRecord *const our, const CacheRecord *const
     return(-1);
 }
 
+mDNSlocal mDNSBool PacketRecordMatches(const AuthRecord *const rr, const CacheRecord *const pktrr, const AuthRecord *const master)
+{
+    if (IdenticalResourceRecord(&rr->resrec, &pktrr->resrec))
+    {
+        const AuthRecord *r2 = rr;
+        while (r2->DependentOn) r2 = r2->DependentOn;
+        if (r2 == master) return(mDNStrue);
+    }
+    return(mDNSfalse);
+}
+
 // See if we have an authoritative record that's identical to this packet record,
 // whose canonical DependentOn record is the specified master record.
 // The DependentOn pointer is typically used for the TXT record of service registrations
@@ -7275,21 +7337,11 @@ mDNSlocal mDNSBool MatchDependentOn(const mDNS *const m, const CacheRecord *cons
     const AuthRecord *r1;
     for (r1 = m->ResourceRecords; r1; r1=r1->next)
     {
-        if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
-        {
-            const AuthRecord *r2 = r1;
-            while (r2->DependentOn) r2 = r2->DependentOn;
-            if (r2 == master) return(mDNStrue);
-        }
+        if (PacketRecordMatches(r1, pktrr, master)) return(mDNStrue);
     }
     for (r1 = m->DuplicateRecords; r1; r1=r1->next)
     {
-        if (IdenticalResourceRecord(&r1->resrec, &pktrr->resrec))
-        {
-            const AuthRecord *r2 = r1;
-            while (r2->DependentOn) r2 = r2->DependentOn;
-            if (r2 == master) return(mDNStrue);
-        }
+        if (PacketRecordMatches(r1, pktrr, master)) return(mDNStrue);
     }
     return(mDNSfalse);
 }
@@ -7359,7 +7411,7 @@ mDNSlocal void ResolveSimultaneousProbe(mDNS *const m, const DNSMessage *const q
     {
         ptr = GetLargeResourceRecord(m, query, ptr, end, q->InterfaceID, kDNSRecordTypePacketAuth, &m->rec);
         if (!ptr) break;
-        if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+        if (m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative && CacheRecordAnswersQuestion(&m->rec.r, q))
         {
             FoundUpdate = mDNStrue;
             if (PacketRRConflict(m, our, &m->rec.r))
@@ -7523,7 +7575,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                                const mDNSAddr *srcaddr, const mDNSInterfaceID InterfaceID, mDNSBool LegacyQuery, mDNSBool QueryWasMulticast,
                                mDNSBool QueryWasLocalUnicast, DNSMessage *const response)
 {
-    mDNSBool FromLocalSubnet    = srcaddr && mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
+    const mDNSBool FromLocalSubnet   = mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
     AuthRecord   *ResponseRecords    = mDNSNULL;
     AuthRecord  **nrp                = &ResponseRecords;
 
@@ -7585,9 +7637,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
         ptr = getQuestion(query, ptr, end, InterfaceID, &pktq); // get the question...
         if (!ptr) goto exit;
 
-        pktq.AnonInfo = mDNSNULL;
-        if (McastNSEC3Records)
-            InitializeAnonInfoForQuestion(m, &McastNSEC3Records, &pktq);
         // The only queries that *need* a multicast response are:
         // * Queries sent via multicast
         // * from port 5353
@@ -7619,7 +7668,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
         {
             rr = m->CurrentRecord;
             m->CurrentRecord = rr->next;
-            if (AnyTypeRecordAnswersQuestion(&rr->resrec, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
+            if (AnyTypeRecordAnswersQuestion(rr, &pktq) && (QueryWasMulticast || QueryWasLocalUnicast || rr->AllowRemoteQuery))
             {
                 m->mDNSStats.MatchingAnswersForQueries++;
                 if (RRTypeAnswersQuestionType(&rr->resrec, pktq.qtype))
@@ -7629,12 +7678,6 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                     else if (ResourceRecordIsValidAnswer(rr))
                     {
                         NumAnswersForThisQuestion++;
-                        // As we have verified this question to be part of the same subset,
-                        // set the anonymous data which is needed below when walk the cache
-                        // records to see what answers we should be expecting. The cache records
-                        // may cache only the nsec3RR and not the anonymous data itself. 
-                        if (pktq.AnonInfo && rr->resrec.AnonInfo)
-                            SetAnonData(&pktq, &rr->resrec, mDNStrue);
 
                         // Note: We should check here if this is a probe-type query, and if so, generate an immediate
                         // unicast answer back to the source, because timeliness in answering probes is important.
@@ -7696,12 +7739,16 @@ 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 (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
-                    if (SameNameRecordAnswersQuestion(&cr->resrec, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
+                {
+                    if (SameNameCacheRecordAnswersQuestion(cr, &pktq) && cr->resrec.rdlength <= SmallRecordLimit)
+                    {
                         if (!cr->NextInKAList && eap != &cr->NextInKAList)
                         {
                             *eap = cr;
                             eap = &cr->NextInKAList;
                         }
+                    }
+                }
             }
 #endif // POOF_ENABLED
 
@@ -7709,25 +7756,23 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
             // We only do this for non-truncated queries. Right now it would be too complicated to try
             // to keep track of duplicate suppression state between multiple packets, especially when we
             // can't guarantee to receive all of the Known Answer packets that go with a particular query.
-            // For anonymous question, the duplicate suppressesion should happen if the
-            // question belongs in the same group. As the group is expected to be
-            // small, we don't do the optimization for now.
-            if (!pktq.AnonInfo)
+            for (q = m->Questions; q; q=q->next)
             {
-                for (q = m->Questions; q; q=q->next)
-                    if (!q->Target.type && ActiveQuestion(q) && m->timenow - q->LastQTxTime > mDNSPlatformOneSecond / 4)
-                        if (!q->InterfaceID || q->InterfaceID == InterfaceID)
-                            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))
-                                { *dqp = q; dqp = &q->NextInDQList; }
+                if (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))
+                            { *dqp = q; dqp = &q->NextInDQList; }
+                        }
+                    }
+                }
             }
         }
-        if (pktq.AnonInfo)
-        {
-            FreeAnonInfo(pktq.AnonInfo);
-        }
     }
 
     // ***
@@ -7815,7 +7860,7 @@ mDNSlocal mDNSu8 *ProcessQuery(mDNS *const m, const DNSMessage *const query, con
                 while (*dqp)
                 {
                     DNSQuestion *q = *dqp;
-                    if (ResourceRecordAnswersQuestion(&m->rec.r.resrec, q))
+                    if (CacheRecordAnswersQuestion(&m->rec.r, q))
                     { *dqp = q->NextInDQList; q->NextInDQList = mDNSNULL; }
                     else dqp = &q->NextInDQList;
                 }
@@ -8059,7 +8104,7 @@ 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, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+        mDNSSendDNSMessage(m, &m->omsg, responseend, InterfaceID, mDNSNULL, mDNSNULL, srcaddr, srcport, mDNSNULL, mDNSfalse);
     }
 }
 
@@ -8110,7 +8155,6 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
 {
     DNSQuestion *q;
     (void)id;
-    (void)srcaddr;
 
     for (q = m->Questions; q; q=q->next)
     {
@@ -8136,8 +8180,8 @@ mDNSlocal DNSQuestion *ExpectingUnicastResponseForRecord(mDNS *const m,
                     //  if (mDNSSameAddress(srcaddr, &q->Target))                   return(mDNStrue);
                     //  if (q->LongLived && mDNSSameAddress(srcaddr, &q->servAddr)) return(mDNStrue); Shouldn't need this now that we have LLQType checking
                     //  if (TrustedSource(m, srcaddr))                              return(mDNStrue);
-                    LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) [q->Target %#a:%d] from %#a:%d %s",
-                            q->qname.c, DNSTypeName(q->qtype), &q->Target, mDNSVal16(srcp), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
+                    LogInfo("WARNING: Ignoring suspect uDNS response for %##s (%s) from %#a:%d %s",
+                            q->qname.c, DNSTypeName(q->qtype), srcaddr, mDNSVal16(port), CRDisplayString(m, rr));
                     return(mDNSNULL);
                 }
             }
@@ -8186,15 +8230,6 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
         rr->resrec.name        = cg->name;           // And set rr->resrec.name to point into our CacheGroup header
         rr->resrec.mortality   = Mortality_Mortal;
 
-        // We need to add the anonymous info before we call CacheRecordAdd so that
-        // if it finds a matching question with this record, it bumps up the counters like
-        // CurrentAnswers etc. Otherwise, when a cache entry gets removed, CacheRecordRmv
-        // will complain.
-        if (m->rec.r.resrec.AnonInfo)
-        {
-            rr->resrec.AnonInfo = m->rec.r.resrec.AnonInfo;
-            m->rec.r.resrec.AnonInfo = mDNSNULL;
-        }
         rr->DelayDelivery = delay;
 
         // If this is an oversized record with external storage allocated, copy rdata to external storage
@@ -8229,7 +8264,7 @@ mDNSexport CacheRecord *CreateNewCacheEntry(mDNS *const m, const mDNSu32 slot, C
         {
             // Can't use the "cg->name" if we are not adding to the cache as the
             // CacheGroup may be released anytime if it is empty
-            domainname *name = mDNSPlatformMemAllocate(DomainNameLength(cg->name));
+            domainname *name = (domainname *) mDNSPlatformMemAllocate(DomainNameLength(cg->name));
             if (name)
             {
                 AssignDomainName(name, cg->name);
@@ -8470,16 +8505,18 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
         ptr = getQuestion(response, ptr, end, InterfaceID, &q);
         if (ptr && (qptr = ExpectingUnicastResponseForQuestion(m, dstport, response->h.id, &q, !dstaddr, mDNSNULL)))
         {
-            CacheRecord *rr, *neg = mDNSNULL;
+            CacheRecord *cr, *neg = mDNSNULL;
             CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
-            for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-                if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
+            for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+            {
+                if (SameNameCacheRecordAnswersQuestion(cr, qptr))
                 {
                     // 1. If we got a fresh answer to this query, then don't need to generate a negative entry
-                    if (RRExpireTime(rr) - m->timenow > 0) break;
+                    if (RRExpireTime(cr) - m->timenow > 0) break;
                     // 2. If we already had a negative entry, keep track of it so we can resurrect it instead of creating a new one
-                    if (rr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = rr;
+                    if (cr->resrec.RecordType == kDNSRecordTypePacketNegative) neg = cr;
                 }
+            }
             // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
             // Active Directory sites) we don't want to waste memory making negative cache entries for all the unicast answers.
             // Otherwise we just fill up our cache with negative entries for just about every single multicast name we ever look up
@@ -8498,26 +8535,31 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
             // do the appropriate thing. This negative response is also needed for appending new search domains.
             if (!InterfaceID && q.qtype != kDNSType_SOA && IsLocalDomain(&q.qname))
             {
-                if (!rr)
+                if (!cr)
                 {
-                    LogInfo("mDNSCoreReceiveNoUnicastAnswers: Generate negative response for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
+                    const mDNSBool noData = ((response->h.flags.b[1] & kDNSFlag1_RC_Mask) == kDNSFlag1_RC_NoErr) ? mDNStrue : mDNSfalse;
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                              "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Generate negative response for " PRI_DM_NAME " (" PUB_S ")",
+                              q.request_id, mDNSVal16(q.TargetQID), DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
                     m->CurrentQuestion = qptr;
                     // We are not creating a cache record in this case, we need to pass back
                     // the error we got so that the proxy code can return the right one to
                     // the application
                     if (qptr->ProxyQuestion)
                         qptr->responseFlags = response->h.flags;
-                    GenerateNegativeResponse(m, mDNSInterface_Any, QC_forceresponse);
+                    GenerateNegativeResponseEx(m, mDNSInterface_Any, QC_forceresponse, noData);
                     m->CurrentQuestion = mDNSNULL;
                 }
                 else
                 {
-                    LogInfo("mDNSCoreReceiveNoUnicastAnswers: Skipping check and not creating a negative cache entry for %##s (%s)", q.qname.c, DNSTypeName(q.qtype));
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                              "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Skipping check and not creating a negative cache entry for " PRI_DM_NAME " (" PUB_S ")",
+                              q.request_id, mDNSVal16(q.TargetQID), DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
                 }
             }
             else
             {
-                if (!rr)
+                if (!cr)
                 {
                     // 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
@@ -8592,7 +8634,9 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
                     // If we already had a negative cache entry just update it, else make one or more new negative cache entries.
                     if (neg)
                     {
-                        LogInfo("mDNSCoreReceiveNoUnicastAnswers: Renewing negative TTL from %d to %d %s", neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
+                        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                                  "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: Renewing negative TTL from %d to %d " PRI_S,
+                                  q.request_id, mDNSVal16(q.TargetQID), neg->resrec.rroriginalttl, negttl, CRDisplayString(m, neg));
                         RefreshCacheRecord(m, neg, negttl);
                         // When we created the cache for the first time and answered the question, the question's
                         // interval was set to MaxQuestionInterval. If the cache is about to expire and we are resending
@@ -8610,7 +8654,9 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
                             {
                                 // We might just have an SOA record for zones that are not signed and hence don't log
                                 // this as an error
-                                LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr %s during refresh", CRDisplayString(m, neg));
+                                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                                          "[R%u->Q%d] mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr " PRI_S" during refresh",
+                                          q.request_id, mDNSVal16(q.TargetQID), CRDisplayString(m, neg));
                                 FreeNSECRecords(m, NSECRecords);
                                 neg->CRDNSSECQuestion = 0;
                             }
@@ -8646,14 +8692,17 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
                                     negcr->CRDNSSECQuestion = 0;
                                     if (!AddNSECSForCacheRecord(m, NSECRecords, negcr, rcode))
                                     {
-                                        LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr %s",
-                                            CRDisplayString(m, negcr));
+                                        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                                                  "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord failed to add NSEC for negcr " PRI_S,
+                                                  q.request_id, mDNSVal16(q.TargetQID), CRDisplayString(m, negcr));
                                         FreeNSECRecords(m, NSECRecords);
                                     }
                                     else
                                     {
                                         negcr->CRDNSSECQuestion = 1;
-                                        LogInfo("mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord added neg NSEC for %s", CRDisplayString(m, negcr));
+                                        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                                                  "[R%u->Q%u] mDNSCoreReceiveNoUnicastAnswers: AddNSECSForCacheRecord added neg NSEC for " PRI_S,
+                                                  q.request_id, mDNSVal16(q.TargetQID), CRDisplayString(m, negcr));
                                     }
                                     NSECRecords = mDNSNULL;
                                     negcr->DelayDelivery = 0;
@@ -8694,13 +8743,22 @@ mDNSlocal void mDNSCoreReceiveNoUnicastAnswers(mDNS *const m, const DNSMessage *
             }
         }
     }
-    if (NSECRecords) { LogInfo("mDNSCoreReceiveNoUnicastAnswers: NSECRecords not used"); FreeNSECRecords(m, NSECRecords); }
-    if (SOARecord)   { LogInfo("mDNSCoreReceiveNoUnicastAnswers: SOARecord not used"); ReleaseCacheRecord(m, SOARecord); }
+    if (NSECRecords)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveNoUnicastAnswers: NSECRecords not used");
+        FreeNSECRecords(m, NSECRecords);
+    }
+    if (SOARecord)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveNoUnicastAnswers: SOARecord not used");
+        ReleaseCacheRecord(m, SOARecord);
+    }
 }
 
 mDNSlocal void mDNSCorePrintStoredProxyRecords(mDNS *const m)
 {
     AuthRecord *rrPtr = mDNSNULL;
+    if (!m->SPSRRSet) return;
     LogSPS("Stored Proxy records :");
     for (rrPtr = m->SPSRRSet; rrPtr; rrPtr = rrPtr->next)
     {
@@ -8724,27 +8782,27 @@ mDNSlocal mDNSBool mDNSCoreRegisteredProxyRecord(mDNS *const m, AuthRecord *rr)
     return mDNSfalse;
 }
 
-mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
+mDNSexport CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
     const mDNSu32 slot, CacheGroup *cg, DNSQuestion *unicastQuestion, CacheRecord ***cfp, CacheRecord **NSECCachePtr,
     mDNSInterfaceID InterfaceID)
 {
-    CacheRecord *rr;
+    CacheRecord *cr;
     CacheRecord **cflocal = *cfp;
 
-    for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+    for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
     {
         mDNSBool match;
         // Resource record received via unicast, the resGroupID should match ?
         if (!InterfaceID)
         {
-            const mDNSu32 id1 = (rr->resrec.rDNSServer ? rr->resrec.rDNSServer->resGroupID : 0);
+            const mDNSu32 id1 = (cr->resrec.rDNSServer ? cr->resrec.rDNSServer->resGroupID : 0);
             const mDNSu32 id2 = (m->rec.r.resrec.rDNSServer ? m->rec.r.resrec.rDNSServer->resGroupID : 0);
             match = (id1 == id2);
         }
         else
-            match = (rr->resrec.InterfaceID == InterfaceID);
+            match = (cr->resrec.InterfaceID == InterfaceID);
         // If we found this exact resource record, refresh its TTL
-        if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &rr->resrec))
+        if (match && IdenticalSameNameRecord(&m->rec.r.resrec, &cr->resrec))
         {
             if (m->rec.r.resrec.rdlength > InlineCacheRDSize)
                 verbosedebugf("mDNSCoreReceiveCacheCheck: Found record size %5d interface %p already in cache: %s",
@@ -8753,83 +8811,58 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage
             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 && LLQType != uDNS_LLQ_Events)
+                if (cr->NextInCFList == mDNSNULL && *cfp != &cr->NextInCFList && LLQType != uDNS_LLQ_Events)
                 {
-                    *cflocal = rr;
-                    cflocal = &rr->NextInCFList;
+                    *cflocal = cr;
+                    cflocal = &cr->NextInCFList;
                     *cflocal = (CacheRecord*)1;
-                    *cfp = &rr->NextInCFList;
+                    *cfp = &cr->NextInCFList;
                 }
 
                 // If this packet record is marked unique, and our previous cached copy was not, then fix it
-                if (!(rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
+                if (!(cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask))
                 {
                     DNSQuestion *q;
                     for (q = m->Questions; q; q=q->next)
                     {
-                        if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+                        if (CacheRecordAnswersQuestion(cr, q))
                             q->UniqueAnswers++;
                     }
-                    rr->resrec.RecordType = m->rec.r.resrec.RecordType;
+                    cr->resrec.RecordType = m->rec.r.resrec.RecordType;
                 }
             }
 
-            if (!SameRDataBody(&m->rec.r.resrec, &rr->resrec.rdata->u, SameDomainNameCS))
+            if (!SameRDataBody(&m->rec.r.resrec, &cr->resrec.rdata->u, SameDomainNameCS))
             {
                 // If the rdata of the packet record differs in name capitalization from the record in our cache
                 // then mDNSPlatformMemSame will detect this. In this case, throw the old record away, so that clients get
                 // a 'remove' event for the record with the old capitalization, and then an 'add' event for the new one.
                 // <rdar://problem/4015377> mDNS -F returns the same domain multiple times with different casing
-                rr->resrec.rroriginalttl = 0;
-                rr->TimeRcvd = m->timenow;
-                rr->UnansweredQueries = MaxUnansweredQueries;
-                SetNextCacheCheckTimeForRecord(m, rr);
-                LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change old: %s", CRDisplayString(m, rr));
-                LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change new: %s", CRDisplayString(m, &m->rec.r));
-                LogInfo("mDNSCoreReceiveCacheCheck: Discarding due to domainname case change in %d slot %3d in %d %d",
-                        NextCacheCheckEvent(rr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
+                cr->resrec.rroriginalttl = 0;
+                cr->TimeRcvd = m->timenow;
+                cr->UnansweredQueries = MaxUnansweredQueries;
+                SetNextCacheCheckTimeForRecord(m, cr);
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change old: " PRI_S, CRDisplayString(m, cr));
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change new: " PRI_S, CRDisplayString(m, &m->rec.r));
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: Discarding due to domainname case change in %d slot %3d in %d %d",
+                          NextCacheCheckEvent(cr) - m->timenow, slot, m->rrcache_nextcheck[slot] - m->timenow, m->NextCacheCheck - m->timenow);
                 // DO NOT break out here -- we want to continue as if we never found it
             }
-            else if (!IdenticalAnonInfo(m->rec.r.resrec.AnonInfo, rr->resrec.AnonInfo))
-            {
-                // If the NSEC3 record changed, a few possibilities
-                //
-                // 1) the peer reinitialized e.g., after network change and still part of the
-                //    same set.
-                // 2) the peer went to a different set but we did not see the goodbyes. If we just
-                //    update the nsec3 record, it would be incorrect. Flush the cache so that we
-                //    can deliver a RMV followed by ADD.
-                // 3) if the peer is ourselves and we see the goodbye when moving to a different set
-                //    and so we flush the cache and create a new cache record with the new set information.
-                //    Now we move back to the original set. In this case, we can't just update the
-                //    NSEC3 record alone. We need to flush so that we can deliver an RMV followed by ADD
-                //    when we create the new cache entry.
-                //
-                // Note: For case (1), we could avoid flushing the cache but we can't tell the difference
-                // from the other cases.
-                rr->resrec.rroriginalttl = 0;
-                rr->TimeRcvd = m->timenow;
-                rr->UnansweredQueries = MaxUnansweredQueries;
-                SetNextCacheCheckTimeForRecord(m, rr);
-                LogInfo("mDNSCoreReceiveCacheCheck: AnonInfo changed for %s", CRDisplayString(m, rr));
-                // DO NOT break out here -- we want to continue as if we never found it. When we return
-                // from this function, we will create a new cache entry with the new NSEC3 record
-            }
             else if (m->rec.r.resrec.rroriginalttl > 0)
             {
                 DNSQuestion *q;
 
                 m->mDNSStats.CacheRefreshed++;
                 
-                if (rr->resrec.mortality == Mortality_Ghost && unicastQuestion && (unicastQuestion->allowExpired != AllowExpired_AllowExpiredAnswers) && !rr->DelayDelivery)
+                if (cr->resrec.mortality == Mortality_Ghost && unicastQuestion && (unicastQuestion->allowExpired != AllowExpired_AllowExpiredAnswers) && !cr->DelayDelivery)
                 {
-                    rr->DelayDelivery = NonZeroTime(m->timenow);
-                    debugf("mDNSCoreReceiveCacheCheck: Reset DelayDelivery for mortalityExpired EXP:%d RR %s", m->timenow - RRExpireTime(rr), CRDisplayString(m, rr));
+                    cr->DelayDelivery = NonZeroTime(m->timenow);
+                    debugf("mDNSCoreReceiveCacheCheck: Reset DelayDelivery for mortalityExpired EXP:%d RR %s", m->timenow - RRExpireTime(cr), CRDisplayString(m, cr));
                 }
 
-                if (rr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, rr));
-                RefreshCacheRecord(m, rr, m->rec.r.resrec.rroriginalttl);
-                rr->responseFlags = response->h.flags;
+                if (cr->resrec.rroriginalttl == 0) debugf("uDNS rescuing %s", CRDisplayString(m, cr));
+                RefreshCacheRecord(m, cr, m->rec.r.resrec.rroriginalttl);
+                cr->responseFlags = response->h.flags;
 
                 // If we may have NSEC records returned with the answer (which we don't know yet as it
                 // has not been processed), we need to cache them along with the first cache
@@ -8838,11 +8871,11 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage
                 // that would answer the question. It is possible that we might cache additional things
                 // e.g., MX question might cache A records also, and we want to cache the NSEC on
                 // the record that answers the question.
-                if (response->h.numAnswers && unicastQuestion && unicastQuestion->qtype == rr->resrec.rrtype
+                if (response->h.numAnswers && unicastQuestion && unicastQuestion->qtype == cr->resrec.rrtype
                     && !(*NSECCachePtr))
                 {
-                    LogInfo("mDNSCoreReceiveCacheCheck: rescuing RR %s", CRDisplayString(m, rr));
-                    *NSECCachePtr = rr;
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "mDNSCoreReceiveCacheCheck: rescuing RR " PRI_S, CRDisplayString(m, cr));
+                    *NSECCachePtr = cr;
                 }
                 // We have to reset the question interval to MaxQuestionInterval so that we don't keep
                 // polling the network once we get a valid response back. For the first time when a new
@@ -8852,12 +8885,12 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage
                 // Currently, we do this for for both multicast and unicast questions as long as the record
                 // type is unique. For unicast, resource record is always unique and for multicast it is
                 // true for records like A etc. but not for PTR.
-                if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
+                if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask)
                 {
                     for (q = m->Questions; q; q=q->next)
                     {
                         if (!q->DuplicateOf && !q->LongLived &&
-                            ActiveQuestion(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+                            ActiveQuestion(q) && CacheRecordAnswersQuestion(cr, q))
                         {
                             ResetQuestionState(m, q);
                             debugf("mDNSCoreReceiveCacheCheck: Set MaxQuestionInterval for %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
@@ -8877,19 +8910,19 @@ mDNSlocal CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage
                 // If record's current expiry time is more than a second from now, we set it to expire in one second.
                 // If the record is already going to expire in less than one second anyway, we leave it alone --
                 // we don't want to let the goodbye packet *extend* the record's lifetime in our cache.
-                debugf("DE for %s", CRDisplayString(m, rr));
-                if (RRExpireTime(rr) - m->timenow > mDNSPlatformOneSecond)
+                debugf("DE for %s", CRDisplayString(m, cr));
+                if (RRExpireTime(cr) - m->timenow > mDNSPlatformOneSecond)
                 {
-                    rr->resrec.rroriginalttl = 1;
-                    rr->TimeRcvd = m->timenow;
-                    rr->UnansweredQueries = MaxUnansweredQueries;
-                    SetNextCacheCheckTimeForRecord(m, rr);
+                    cr->resrec.rroriginalttl = 1;
+                    cr->TimeRcvd = m->timenow;
+                    cr->UnansweredQueries = MaxUnansweredQueries;
+                    SetNextCacheCheckTimeForRecord(m, cr);
                 }
                 break;
             }
         }
     }
-    return rr;
+    return cr;
 }
 
 mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const response, const mDNSu8 *end,
@@ -8935,11 +8968,6 @@ mDNSlocal void mDNSParseNSEC3Records(mDNS *const m, const DNSMessage *const resp
 mDNSlocal void mDNSCoreResetRecord(mDNS *const m)
 {
     m->rec.r.resrec.RecordType = 0;     // Clear RecordType to show we're not still using it
-    if (m->rec.r.resrec.AnonInfo)
-    {
-        FreeAnonInfo(m->rec.r.resrec.AnonInfo);
-        m->rec.r.resrec.AnonInfo = mDNSNULL;
-    }
 }
 
 // Note: mDNSCoreReceiveResponse calls mDNS_Deregister_internal which can call a user callback, which may change
@@ -8954,7 +8982,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                        const mDNSInterfaceID InterfaceID)
 {
     int i;
-    mDNSBool ResponseMCast    = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
+    const mDNSBool ResponseMCast = dstaddr && mDNSAddrIsDNSMulticast(dstaddr);
     mDNSBool ResponseSrcLocal = !srcaddr || mDNS_AddressIsLocalSubnet(m, InterfaceID, srcaddr);
     DNSQuestion *llqMatch = mDNSNULL;
     DNSQuestion *unicastQuestion = mDNSNULL;
@@ -8993,7 +9021,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
            response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
            response->h.numAdditionals, response->h.numAdditionals == 1 ? " "    : "s", end - response->data, LLQType);
 
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     if (mDNSSameIPPort(srcport, UnicastDNSPort))
     {
         MetricsUpdateDNSResponseSize((mDNSu32)(end - (mDNSu8 *)response));
@@ -9054,7 +9082,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
             {
                 if (!failure)
                 {
-                    CacheRecord *rr;
+                    CacheRecord *cr;
                     // Remember the unicast question that we found, which we use to make caching
                     // decisions later on in this function
                     CacheGroup *cg = CacheGroupForName(m, q.qnamehash, &q.qname);
@@ -9063,30 +9091,38 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                         unicastQuestion = qptr;
                         if (qptr->qDNSServer && DNSSECQuestion(qptr))
                         {
-                            LogInfo("mDNSCoreReceiveResponse: Setting aware for %##s (%s) on %#a", qptr->qname.c,
-                                DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr);
+                            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                                   "[R%d->Q%d] mDNSCoreReceiveResponse: Setting aware for " PRI_DM_NAME " (" PUB_S ") on " PRI_IP_ADDR,
+                                   qptr->request_id, mDNSVal16(qptr->TargetQID), DM_NAME_PARAM(qptr->qname.c),
+                                   DNSTypeName(qptr->qtype), &qptr->qDNSServer->addr);
+
                             qptr->qDNSServer->DNSSECAware = mDNStrue;
                             qptr->qDNSServer->req_DO = mDNStrue;
                         }
                         if (qptr->ValidatingResponse)
                             DNSSECQuestion = mDNStrue;
                     }
-                    for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-                        if (SameNameRecordAnswersQuestion(&rr->resrec, qptr))
+                    for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+                    {
+                        if (SameNameCacheRecordAnswersQuestion(cr, qptr))
                         {
                             debugf("uDNS marking %p %##s (%s) %p %s", q.InterfaceID, q.qname.c, DNSTypeName(q.qtype),
-                                   rr->resrec.InterfaceID, CRDisplayString(m, rr));
+                                   cr->resrec.InterfaceID, CRDisplayString(m, cr));
                             // Don't want to disturb rroriginalttl here, because code below might need it for the exponential backoff doubling algorithm
-                            rr->TimeRcvd          = m->timenow - TicksTTL(rr) - 1;
-                            rr->UnansweredQueries = MaxUnansweredQueries;
-                            rr->CRDNSSECQuestion = 0;
+                            cr->TimeRcvd          = m->timenow - TicksTTL(cr) - 1;
+                            cr->UnansweredQueries = MaxUnansweredQueries;
+                            cr->CRDNSSECQuestion = 0;
                             if (unicastQuestion && DNSSECQuestion(unicastQuestion))
                             {
-                                LogInfo("mDNSCoreReceiveResponse: CRDNSSECQuestion set for record %s, question %##s (%s)", CRDisplayString(m, rr),
-                                    unicastQuestion->qname.c, DNSTypeName(unicastQuestion->qtype));
-                                rr->CRDNSSECQuestion = 1;
+                                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                                       "[R%d->Q%d] mDNSCoreReceiveResponse: CRDNSSECQuestion set for record " PRI_S ", question " PRI_DM_NAME " (" PUB_S ")",
+                                       unicastQuestion->request_id, mDNSVal16(unicastQuestion->TargetQID),
+                                       CRDisplayString(m, cr), DM_NAME_PARAM(unicastQuestion->qname.c),
+                                       DNSTypeName(unicastQuestion->qtype));
+                                cr->CRDNSSECQuestion = 1;
                             }
                         }
+                    }
                 }
                 else
                 {
@@ -9098,15 +9134,19 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                         // and hence retransmit without the EDNS0/DOK option.
                         if (DNSSECOptionalQuestion(qptr) && qptr->qDNSServer && !qptr->qDNSServer->DNSSECAware)
                         {
-                            LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query %##s (%s), clear DO flag",
-                                    qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
+                            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                                   "[R%d->Q%d] mDNSCoreReceiveResponse: Server %p responded with code %d to DNSSEC Query " PRI_DM_NAME " (" PUB_S "), clear DO flag",
+                                   qptr->request_id, mDNSVal16(qptr->TargetQID), qptr->qDNSServer, rcode,
+                                   DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
                             qptr->qDNSServer->req_DO = mDNSfalse;
                         }
                         // For Unicast DNS Queries, penalize the DNSServer
                         else
                         {
-                            LogInfo("mDNSCoreReceiveResponse: Server %p responded with code %d to query %##s (%s)",
-                                    qptr->qDNSServer, rcode, q.qname.c, DNSTypeName(q.qtype));
+                            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                                   "[R%d->Q%d] mDNSCoreReceiveResponse: Server %p responded with code %d to query " PRI_DM_NAME " (" PUB_S ")",
+                                   qptr->request_id, mDNSVal16(qptr->TargetQID), qptr->qDNSServer, rcode,
+                                   DM_NAME_PARAM(q.qname.c), DNSTypeName(q.qtype));
                             PenalizeDNSServer(m, qptr, response->h.flags);
                         }
                     }
@@ -9116,19 +9156,28 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
             else if (!InterfaceID && suspiciousForQ)
             {
                 // If a response is suspicious for a question, then reissue the question via TCP
-                LogInfo("mDNSCoreReceiveResponse: Server %p responded suspiciously to query %##s (%s) qID %d != rID: %d",
+                LogInfo("[R%d->Q%d] mDNSCoreReceiveResponse: Server %p responded suspiciously to query %##s (%s) qID %d != rID: %d",
+                        suspiciousForQ->request_id, mDNSVal16(suspiciousForQ->TargetQID),
                         suspiciousForQ->qDNSServer, q.qname.c, DNSTypeName(q.qtype),
                         mDNSVal16(suspiciousForQ->TargetQID), mDNSVal16(response->h.id));
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+                m->NextSuspiciousTimeout = NonZeroTime(m->timenow + (SUSPICIOUS_REPLY_DEFENSE_SECS * mDNSPlatformOneSecond));
+#endif
                 uDNS_RestartQuestionAsTCP(m, suspiciousForQ, srcaddr, srcport);
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+                suspiciousForQ->metrics.dnsOverTCPState = DNSOverTCP_Suspicious;
+#endif
                 return;
             }
         }
         if (returnEarly)
         {
-            LogInfo("Ignoring %2d Answer%s %2d Authorit%s %2d Additional%s",
-                    response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
-                    response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
-                    response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                   "[Q%d] Ignoring %2d Answer" PUB_S " %2d Authorit" PUB_S " %2d Additional" PUB_S,
+                   mDNSVal16(response->h.id),
+                   response->h.numAnswers,     response->h.numAnswers     == 1 ? ", " : "s,",
+                   response->h.numAuthorities, response->h.numAuthorities == 1 ? "y,  " : "ies,",
+                   response->h.numAdditionals, response->h.numAdditionals == 1 ? "" : "s");
             // not goto exit because we won't have any CacheFlushRecords and we do not want to
             // generate negative cache entries (we want to query the next server)
             return;
@@ -9262,7 +9311,9 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                     {
                         // Accept all remaining records in this unicast response to an mDNS query.
                         recordAcceptedInResponse = mDNStrue;
-                        LogInfo("mDNSCoreReceiveResponse: Accepting response for query: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                               "[R%d->Q%d] mDNSCoreReceiveResponse: Accepting response for query: " PRI_DM_NAME " (" PUB_S ")",
+                               q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
                     }
                 }
                 else
@@ -9349,7 +9400,8 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                     // 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))
                     {
-                        LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s", m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r));
+                        LogInfo("mDNSCoreReceiveResponse: Pkt Record: %08lX %s (interface %d)",
+                            m->rec.r.resrec.rdatahash, CRDisplayString(m, &m->rec.r), IIDPrintable(InterfaceID));
                         LogInfo("mDNSCoreReceiveResponse: Our Record: %08lX %s", rr->resrec.rdatahash, ARDisplayString(m, rr));
 
                         // If this record is marked DependentOn another record for conflict detection purposes,
@@ -9391,30 +9443,34 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                                 // Before we call deregister, check if this is a packet we registered with the sleep proxy.
                                 if (!mDNSCoreRegisteredProxyRecord(m, rr))
                                 {
-                                    // This may be a conflict due to stale packets on the network. Delay probing by a second.
-                                    // If there are conflicts after 3 such attempts, then it is a true conflict.
-                                    if (m->DelayConflictProcessing)
-                                    {
-                                        m->DelayConflictProcessing--;
-                                        LogMsg("Possible spurious conflict for %s. Attempt %d at suppressing probes for one second",
-                                               ARDisplayString(m, rr), (MAX_CONFLICT_PROCESSING_DELAYS - m->DelayConflictProcessing));
-                                        rr->ProbeCount     = DefaultProbeCountForTypeUnique + 1;
-                                        rr->AnnounceCount  = InitialAnnounceCount;
-                                        m->SuppressProbes  = NonZeroTime(m->timenow + mDNSPlatformOneSecond);
-                                        InitializeLastAPTime(m, rr);
-                                        RecordProbeFailure(m, rr);  // Repeated late conflicts also cause us to back off to the slower probing rate
-                                    }
-                                    else
+                                    if ((rr->ProbingConflictCount == 0) || (m->MPktNum != rr->LastConflictPktNum))
                                     {
-                                        LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s", rr->ProbeCount, ARDisplayString(m, rr));
-                                        m->mDNSStats.NameConflicts++;
-#if APPLE_OSX_mDNSResponder
-                                        // See if this record was also registered with any D2D plugins.
-                                        D2D_stop_advertising_record(rr);
+                                        const NetworkInterfaceInfo *const intf = FirstInterfaceForID(m, InterfaceID);
+                                        rr->ProbingConflictCount++;
+                                        rr->LastConflictPktNum = m->MPktNum;
+                                        if (ResponseMCast && (!intf || intf->SupportsUnicastMDNSResponse) &&
+                                            (rr->ProbingConflictCount <= kMaxAllowedMCastProbingConflicts))
+                                        {
+                                            LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; restarting probing after %d-tick pause due to possibly "
+                                                "spurious multicast conflict (%d/%d) via interface %d for %s",
+                                                rr->ProbeCount, kProbingConflictPauseDuration, rr->ProbingConflictCount,
+                                                kMaxAllowedMCastProbingConflicts, IIDPrintable(InterfaceID), ARDisplayString(m, rr));
+                                            rr->ProbeCount = DefaultProbeCountForTypeUnique;
+                                            rr->LastAPTime = m->timenow + kProbingConflictPauseDuration - rr->ThisAPInterval;
+                                            SetNextAnnounceProbeTime(m, rr);
+                                        }
+                                        else
+                                        {
+                                            LogMsg("mDNSCoreReceiveResponse: ProbeCount %d; will deregister %s due to %scast conflict via interface %d",
+                                                rr->ProbeCount, ARDisplayString(m, rr), ResponseMCast ? "multi" : "uni", IIDPrintable(InterfaceID));
+                                            m->mDNSStats.NameConflicts++;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+                                            // See if this record was also registered with any D2D plugins.
+                                            D2D_stop_advertising_record(rr);
 #endif
-                                        mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
+                                            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
@@ -9426,7 +9482,7 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                             {
                                 LogMsg("mDNSCoreReceiveResponse: Unexpected conflict discarding %s", ARDisplayString(m, rr));
                                 m->mDNSStats.KnownUniqueNameConflicts++;
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
                                 D2D_stop_advertising_record(rr);
 #endif
                                 mDNS_Deregister_internal(m, rr, mDNS_Dereg_conflict);
@@ -9456,16 +9512,16 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
         // 2. See if we want to add this packet resource record to our cache
         // We only try to cache answers if we have a cache to put them in
         // Also, we ignore any apparent attempts at cache poisoning unicast to us that do not answer any outstanding active query
-        if (!AcceptableResponse) LogInfo("mDNSCoreReceiveResponse ignoring %s", CRDisplayString(m, &m->rec.r));
+        if (!AcceptableResponse) {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[Q%d] mDNSCoreReceiveResponse ignoring " PRI_S,
+                   mDNSVal16(response->h.id), CRDisplayString(m, &m->rec.r));
+        }
         if (m->rrcache_size && AcceptableResponse)
         {
             const mDNSu32 slot = HashSlotFromNameHash(m->rec.r.resrec.namehash);
             CacheGroup *cg = CacheGroupForRecord(m, &m->rec.r.resrec);
             CacheRecord *rr = mDNSNULL;
 
-            if (McastNSEC3Records)
-                InitializeAnonInfoForCR(m, &McastNSEC3Records, &m->rec.r);
-
             // 2a. Check if this packet resource record is already in our cache.
             //
             // If this record should go in the nseclist, don't look in the cache for updating it.
@@ -9508,8 +9564,10 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                     rr->CRDNSSECQuestion = 0;
                     if (unicastQuestion && DNSSECQuestion(unicastQuestion))
                     {
-                        LogInfo("mDNSCoreReceiveResponse: CRDNSSECQuestion set for new record %s, question %##s (%s)", CRDisplayString(m, rr),
-                            unicastQuestion->qname.c, DNSTypeName(unicastQuestion->qtype));
+                        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                               "[R%d->Q%d] mDNSCoreReceiveResponse: CRDNSSECQuestion set for new record " PRI_S ", question " PRI_DM_NAME " (" PUB_S ")",
+                               unicastQuestion->request_id, mDNSVal16(unicastQuestion->TargetQID), CRDisplayString(m, rr),
+                               DM_NAME_PARAM(unicastQuestion->qname.c), DNSTypeName(unicastQuestion->qtype));
                         rr->CRDNSSECQuestion = 1;
                     }
                     // NSEC/NSEC3 records and its signatures are cached with the negative cache entry
@@ -9533,13 +9591,6 @@ mDNSlocal void mDNSCoreReceiveResponse(mDNS *const m,
                     }
                 }
             }
-            else
-            {
-                if (rr && rr->resrec.AnonInfo && m->rec.r.resrec.AnonInfo)
-                {
-                    CopyAnonInfoForCR(m, rr, &m->rec.r);
-                }
-            }
         }
         mDNSCoreResetRecord(m);
     }
@@ -9686,14 +9737,14 @@ exit:
                 }
                 else
                 {
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
                     if (r2->resrec.mortality == Mortality_Ghost)
                     {
                         DNSQuestion * q;
                         for (q = m->Questions; q; q=q->next)
                         {
                             if (!q->LongLived && ActiveQuestion(q) &&
-                                ResourceRecordAnswersQuestion(&r2->resrec, q) &&
+                                CacheRecordAnswersQuestion(r2, q) &&
                                 q->metrics.expiredAnswerState == ExpiredAnswer_AnsweredWithExpired)
                             {
                                 q->metrics.expiredAnswerState = ExpiredAnswer_ExpiredAnswerChanged;
@@ -9720,7 +9771,9 @@ exit:
             {
                 if (!NSECCachePtr)
                 {
-                    LogInfo("mDNSCoreReceiveResponse: Updating NSECCachePtr to %s", CRDisplayString(m, r1));
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                           "[R%d->Q%d] mDNSCoreReceiveResponse: Updating NSECCachePtr to " PRI_S,
+                           unicastQuestion->request_id, mDNSVal16(unicastQuestion->TargetQID), CRDisplayString(m, r1));
                     NSECCachePtr = r1;
                 }
                 // Note: We need to do this before we call CacheRecordDeferredAdd as this
@@ -10321,7 +10374,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
     if (!InterfaceID || !m->SPSSocket || !mDNSSameIPPort(dstport, m->SPSSocket->port)) return;
 
     if (mDNS_PacketLoggingEnabled)
-        DumpPacket(mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+        DumpPacket(mStatus_NoError, mDNSfalse, "UDP", srcaddr, srcport, dstaddr, dstport, msg, end, InterfaceID);
 
     ptr = LocateOptRR(msg, end, DNSOpt_LeaseData_Space + DNSOpt_OwnerData_ID_Space);
     if (ptr)
@@ -10386,7 +10439,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
             if (ptr && m->rec.r.resrec.RecordType != kDNSRecordTypePacketNegative)
             {
                 mDNSu16 RDLengthMem = GetRDLengthMem(&m->rec.r.resrec);
-                AuthRecord *ar = mDNSPlatformMemAllocate(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
+                AuthRecord *ar = (AuthRecord *) mDNSPlatformMemAllocateClear(sizeof(AuthRecord) - sizeof(RDataBody) + RDLengthMem);
                 if (!ar)
                 {
                     m->omsg.h.flags.b[1] |= kDNSFlag1_RC_Refused;
@@ -10450,7 +10503,7 @@ mDNSlocal void mDNSCoreReceiveUpdate(mDNS *const m,
         }
     }
 
-    if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+    if (p) mDNSSendDNSMessage(m, &m->omsg, p, InterfaceID, mDNSNULL, m->SPSSocket, srcaddr, srcport, mDNSNULL, mDNSfalse);
     mDNS_SendKeepalives(m);
 }
 
@@ -10649,7 +10702,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 
     // 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 (srcaddr && !mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
+    if (!mDNSAddressIsValid(srcaddr)) { debugf("mDNSCoreReceive ignoring packet from %#a", srcaddr); return; }
 
     mDNS_Lock(m);
     m->PktNum++;
@@ -10674,7 +10727,7 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
         {
             ifid = mDNSInterface_Any;
             if (mDNS_PacketLoggingEnabled)
-                DumpPacket(mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end);
+                DumpPacket(mStatus_NoError, mDNSfalse, TLS ? "TLS" : !dstaddr ? "TCP" : "UDP", srcaddr, srcport, dstaddr, dstport, msg, end, InterfaceID);
             uDNS_ReceiveMsg(m, msg, end, srcaddr, srcport);
             // Note: mDNSCore also needs to get access to received unicast responses
         }
@@ -10717,17 +10770,6 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 #pragma mark - Searcher Functions
 #endif
 
-// 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)))
-
-// SameQuestionKind is true if *both* questions are either multicast or unicast
-// TargetQID is used for this determination.
-#define SameQuestionKind(A,B) ((mDNSOpaque16IsZero(A) && mDNSOpaque16IsZero(B)) || \
-                               ((!mDNSOpaque16IsZero(A)) && (!mDNSOpaque16IsZero(B))))
-
 // Note: We explicitly disallow making a public query be a duplicate of a private one. This is to avoid the
 // circular deadlock where a client does a query for something like "dns-sd -Q _dns-query-tls._tcp.company.com SRV"
 // and we have a key for company.com, so we try to locate the private query server for company.com, which necessarily entails
@@ -10747,8 +10789,9 @@ mDNSexport void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNS
 // (a) long-lived and
 // (b) being performed by a unicast DNS long-lived query (either full LLQ, or polling)
 // for multicast questions, we don't want to treat LongLived as anything special
-#define IsLLQ(Q) ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
-#define IsAWDLIncluded(Q) (((Q)->flags & kDNSServiceFlagsIncludeAWDL) != 0)
+#define IsLLQ(Q)                 ((Q)->LongLived && !mDNSOpaque16IsZero((Q)->TargetQID))
+#define AWDLIsIncluded(Q)        (((Q)->flags & kDNSServiceFlagsIncludeAWDL) != 0)
+#define SameQuestionKind(Q1, Q2) (mDNSOpaque16IsZero((Q1)->TargetQID) == mDNSOpaque16IsZero((Q2)->TargetQID))
 
 mDNSlocal DNSQuestion *FindDuplicateQuestion(const mDNS *const m, const DNSQuestion *const question)
 {
@@ -10757,24 +10800,23 @@ 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 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,
-            IsLLQ(q)      == IsLLQ(question)        &&          // and long-lived status matches
-            (!q->AuthInfo || question->AuthInfo)    &&          // to avoid deadlock, don't make public query dup of a private one
-            (q->AnonInfo  == question->AnonInfo)    &&          // Anonymous query not a dup of normal query
-            (q->SuppressQuery == question->SuppressQuery) &&    // Questions that are suppressed/not suppressed
-            (q->ValidationRequired == question->ValidationRequired) &&  // Questions that require DNSSEC validation
-            (q->ValidatingResponse == question->ValidatingResponse) &&  // Questions that are validating responses using DNSSEC
-            (q->DisallowPID == question->DisallowPID)     &&            // Disallowing a PID should not affect a PID that is allowed
-            (q->BrowseThreshold == question->BrowseThreshold) &&  // browse thresholds must match
-            q->qnamehash  == question->qnamehash    &&
-            (IsAWDLIncluded(q) == IsAWDLIncluded(question)) &&     // Inclusion of AWDL interface must match
-            SameQuestionKind(q->TargetQID, question->TargetQID) && // mDNS or uDNS must match
-            SameDomainName(&q->qname, &question->qname))           // and name
-            return(q);
+    for (q = m->Questions; q && (q != question); q = q->next)
+    {
+        if (!SameQuestionKind(q, question))                         continue;
+        if (q->qnamehash          != question->qnamehash)           continue;
+        if (q->InterfaceID        != question->InterfaceID)         continue;
+        if (q->qtype              != question->qtype)               continue;
+        if (q->qclass             != question->qclass)              continue;
+        if (IsLLQ(q)              != IsLLQ(question))               continue;
+        if (q->AuthInfo && !question->AuthInfo)                     continue;
+        if (q->ValidationRequired != question->ValidationRequired)  continue;
+        if (q->ValidatingResponse != question->ValidatingResponse)  continue;
+        if (!q->Suppressed        != !question->Suppressed)         continue;
+        if (q->BrowseThreshold    != question->BrowseThreshold)     continue;
+        if (AWDLIsIncluded(q)     != AWDLIsIncluded(question))      continue;
+        if (!SameDomainName(&q->qname, &question->qname))           continue;
+        return(q);
+    }
     return(mDNSNULL);
 }
 
@@ -10788,9 +10830,11 @@ mDNSlocal void UpdateQuestionDuplicates(mDNS *const m, DNSQuestion *const questi
     // question as a duplicate.
     if (question->DuplicateOf)
     {
-        LogInfo("UpdateQuestionDuplicates: question %p %##s (%s) duplicate of %p %##s (%s)",
-                question, question->qname.c, DNSTypeName(question->qtype),
-                question->DuplicateOf, question->DuplicateOf->qname.c, DNSTypeName(question->DuplicateOf->qtype));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d->DupQ%d->Q%d] UpdateQuestionDuplicates: question %p " PRI_DM_NAME " (" PUB_S ") duplicate of %p " PRI_DM_NAME " (" PUB_S ")",
+               question->request_id, mDNSVal16(question->DuplicateOf->TargetQID), mDNSVal16(question->TargetQID),
+               question, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype), question->DuplicateOf,
+               DM_NAME_PARAM(question->DuplicateOf->qname.c), DNSTypeName(question->DuplicateOf->qtype));
         return;
     }
 
@@ -10865,7 +10909,8 @@ mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname
 
     if (!d) d = (const domainname *)"";
 
-    LogInfo("mDNS_AddMcastResolver: Adding %##s, InterfaceID %p, timeout %u", d->c, interface, timeout);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+        "mDNS_AddMcastResolver: Adding " PUB_DM_NAME ", InterfaceID %p, timeout %u", DM_NAME_PARAM(d), interface, timeout);
 
     mDNS_CheckLock(m);
 
@@ -10887,7 +10932,7 @@ mDNSexport McastResolver *mDNS_AddMcastResolver(mDNS *const m, const domainname
     else
     {
         // allocate, add to list
-        *p = mDNSPlatformMemAllocate(sizeof(**p));
+        *p = (McastResolver *) mDNSPlatformMemAllocateClear(sizeof(**p));
         if (!*p) LogMsg("mDNS_AddMcastResolver: ERROR!! - malloc");
         else
         {
@@ -11055,11 +11100,8 @@ mDNSlocal mDNSBool DNSServerMatch(DNSServer *d, mDNSInterfaceID InterfaceID, mDN
     //
     // - DNSServer is scoped and InterfaceID is not NULL - the InterfaceID of the question and the DNSServer
     //   should match (Refer to (2) above).
-    //
-    // Note: mDNSInterface_Unicast is used only by .local unicast questions and are treated as unscoped.
-    // If a question is scoped both to InterfaceID and ServiceID, the question will be scoped to InterfaceID.
 
-    if (((d->scopeType == kScopeNone) && ((!InterfaceID && ServiceID == -1) || InterfaceID == mDNSInterface_Unicast)) ||
+    if (((d->scopeType == kScopeNone) && (!InterfaceID && ServiceID == -1))  ||
         ((d->scopeType == kScopeInterfaceID) && d->interface == InterfaceID) ||
         ((d->scopeType == kScopeServiceID) && d->serviceID == ServiceID))
     {
@@ -11082,11 +11124,11 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
     DEQuery = DomainEnumQuery(&question->qname);
     for (curr = m->DNSServers; curr; curr = curr->next)
     {
-        debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scoped);
+        debugf("SetValidDNSServers: Parsing DNS server Address %#a (Domain %##s), Scope: %d", &curr->addr, curr->domain.c, curr->scopeType);
         // skip servers that will soon be deleted
-        if (curr->flags & DNSServer_FlagDelete)
+        if (curr->flags & DNSServerFlag_Delete)
         {
-            debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped);
+            debugf("SetValidDNSServers: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scopeType);
             continue;
         }
 
@@ -11108,9 +11150,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
         }
 
         currcount = CountLabels(&curr->domain);
-        if ((!curr->isCell || (!DEQuery && !(question->flags & kDNSServiceFlagsDenyCellular))) &&
-            (!curr->isExpensive || !(question->flags & kDNSServiceFlagsDenyExpensive)) &&
-            DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
+        if ((!DEQuery || !curr->isCell) && DNSServerMatch(curr, question->InterfaceID, question->ServiceID))
         {
             bettermatch = BetterMatchForName(&question->qname, namecount, &curr->domain, currcount, bestmatchlen);
 
@@ -11128,7 +11168,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
                     timeout = 0;
                 }
                 debugf("SetValidDNSServers: question %##s Setting the bit for DNS server Address %#a (Domain %##s), Scoped:%d index %d,"
-                       " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scoped, index, curr->timeout,
+                       " Timeout %d, interface %p", question->qname.c, &curr->addr, curr->domain.c, curr->scopeType, index, curr->timeout,
                        curr->interface);
                 timeout += curr->timeout;
                 if (DEQuery)
@@ -11140,7 +11180,7 @@ mDNSexport mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question)
     }
     question->noServerResponse = 0;
 
-    debugf("SetValidDNSServers: ValidDNSServer bits  0x%x%x%x%x for question %p %##s (%s)",
+    debugf("SetValidDNSServers: ValidDNSServer bits 0x%08x%08x%08x%08x for question %p %##s (%s)",
            question->validDNSServers.l[3], question->validDNSServers.l[2], question->validDNSServers.l[1], question->validDNSServers.l[0], question, question->qname.c, DNSTypeName(question->qtype));
     // If there are no matching resolvers, then use the default timeout value.
     // For ProxyQuestion, shorten the timeout so that dig does not timeout on us in case of no response.
@@ -11165,9 +11205,9 @@ mDNSlocal DNSServer *GetBestServer(mDNS *m, const domainname *name, mDNSInterfac
     for (curr = m->DNSServers; curr; curr = curr->next)
     {
         // skip servers that will soon be deleted
-        if (curr->flags & DNSServer_FlagDelete)
+        if (curr->flags & DNSServerFlag_Delete)
         {
-            debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scoped);
+            debugf("GetBestServer: Delete set for index %d, DNS server %#a (Domain %##s), scoped %d", index, &curr->addr, curr->domain.c, curr->scopeType);
             continue;
         }
 
@@ -11230,7 +11270,7 @@ mDNSlocal DNSServer *GetServerForName(mDNS *m, const domainname *name, mDNSInter
     char *ifname = mDNSNULL;    // for logging purposes only
     mDNSOpaque128 allValid;
 
-    if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+    if (InterfaceID == mDNSInterface_LocalOnly)
         InterfaceID = mDNSNULL;
 
     if (InterfaceID) ifname = InterfaceNameForID(m, InterfaceID);
@@ -11259,7 +11299,7 @@ mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question)
     const domainname *name = &question->qname;
     int currindex;
 
-    if ((InterfaceID == mDNSInterface_Unicast) || (InterfaceID == mDNSInterface_LocalOnly))
+    if (InterfaceID == mDNSInterface_LocalOnly)
         InterfaceID = mDNSNULL;
 
     if (InterfaceID)
@@ -11274,24 +11314,23 @@ mDNSexport DNSServer *GetServerForQuestion(mDNS *m, DNSQuestion *question)
 
     if (curmatch != mDNSNULL)
     {
-        LogInfo("GetServerForQuestion: %p DNS server (%p) %#a:%d (Penalty Time Left %d) (Scope %s:%p:%d) for %##s (%s)",
-                question, curmatch, &curmatch->addr, mDNSVal16(curmatch->port),
-                (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0), ifname ? ifname : "None",
-                InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d->Q%d] GetServerForQuestion: %p DNS server (%p) " PRI_IP_ADDR ":%d (Penalty Time Left %d) (Scope " PUB_S ":%p:%d) for " PRI_DM_NAME " (" PUB_S ")",
+               question->request_id, mDNSVal16(question->TargetQID), question, curmatch, &curmatch->addr,
+               mDNSVal16(curmatch->port), (curmatch->penaltyTime ? (curmatch->penaltyTime - m->timenow) : 0),
+               ifname ? ifname : "None", InterfaceID, question->ServiceID, DM_NAME_PARAM(name), DNSTypeName(question->qtype));
     }
     else
     {
-        LogInfo("GetServerForQuestion: %p no DNS server (Scope %s:%p:%d) for %##s (%s)",
-            question, ifname ? ifname : "None", InterfaceID, question->ServiceID, name, DNSTypeName(question->qtype));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d->Q%d] GetServerForQuestion: %p no DNS server (Scope " PUB_S ":%p:%d) for " PRI_DM_NAME " (" PUB_S ")",
+               question->request_id, mDNSVal16(question->TargetQID), question, ifname ? ifname : "None", InterfaceID,
+               question->ServiceID, DM_NAME_PARAM(name), DNSTypeName(question->qtype));
     }
 
     return(curmatch);
 }
 
-
-#define ValidQuestionTarget(Q) (((Q)->Target.type == mDNSAddrType_IPv4 || (Q)->Target.type == mDNSAddrType_IPv6) && \
-                                (mDNSSameIPPort((Q)->TargetPort, UnicastDNSPort) || mDNSSameIPPort((Q)->TargetPort, MulticastDNSPort)))
-
 // Called in normal client context (lock not held)
 mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
 {
@@ -11302,221 +11341,125 @@ mDNSlocal void LLQNATCallback(mDNS *m, NATTraversalInfo *n)
     for (q = m->Questions; q; q=q->next)
         if (ActiveQuestion(q) && !mDNSOpaque16IsZero(q->TargetQID) && q->LongLived)
             startLLQHandshake(m, q);    // If ExternalPort is zero, will do StartLLQPolling instead
-#if APPLE_OSX_mDNSResponder
-    UpdateAutoTunnelDomainStatuses(m);
-#endif
     mDNS_Unlock(m);
 }
 
-mDNSlocal mDNSBool IsPrivateDomain(mDNS *const m, DNSQuestion *q)
-{
-    DomainAuthInfo *AuthInfo;
-    // Skip Private domains as we have special addresses to get the hosts in the Private domain
-    AuthInfo = GetAuthInfoForName_internal(m, &q->qname);
-    if (AuthInfo && !AuthInfo->deltime && AuthInfo->AutoTunnel)
-    {
-        debugf("IsPrivateDomain: %##s true", q->qname.c);
-        return mDNStrue;
-    }
-    else
-    {
-        debugf("IsPrivateDomain: %##s false", q->qname.c);
-        return mDNSfalse;
-    }
-}
-
-#define TrueFalseStr(X) ((X) ? "true" : "false")
-
 // This function takes the DNSServer as a separate argument because sometimes the
-// caller has not yet assigned the DNSServer, but wants to evaluate the SuppressQuery
+// caller has not yet assigned the DNSServer, but wants to evaluate the Suppressed
 // status before switching to it.
-mDNSlocal mDNSBool ShouldSuppressUnicastQuery(mDNS *const m, DNSQuestion *q, DNSServer *d)
+mDNSlocal mDNSBool ShouldSuppressUnicastQuery(const DNSQuestion *const q, const DNSServer *const server)
 {
-    // Some callers don't check for the qtype
-    if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA)
-    {
-        LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype));
-        return mDNSfalse;
-    }
-
-    // Private domains are exempted irrespective of what the DNSServer says
-    if (IsPrivateDomain(m, q))
-    {
-        LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, Private Domain", q->qname.c, DNSTypeName(q->qtype));
-        return mDNSfalse;
-    }
+    mDNSBool suppress = mDNSfalse;
+    const char *reason = NULL;
 
-    if (!d)
+    if (q->BlockedByPolicy)
     {
-        LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, as the DNS server is NULL", q->qname.c, DNSTypeName(q->qtype));
-        return mDNStrue;
+        suppress = mDNStrue;
+        reason   = " (blocked by policy)";
     }
-
-    // Check if the DNS Configuration allows A/AAAA queries to be sent
-    if ((q->qtype == kDNSType_A) && d->req_A)
+    else if (!server)
     {
-        // The server's configuration allows A record queries, so don't suppress this query unless
-        //     1. the interface associated with the server is CLAT46; and
-        //     2. the query has the kDNSServiceFlagsPathEvaluationDone flag, which indicates that it came from libnetcore.
-        // See <rdar://problem/42672030> for more info.
-        if (!(d->isCLAT46 && (q->flags & kDNSServiceFlagsPathEvaluationDone)))
+        if (!q->IsUnicastDotLocal)
         {
-            LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows A queries", q->qname.c,
-                     DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port));
-            return mDNSfalse;
+            suppress = mDNStrue;
+            reason   = " (no DNS server)";
         }
     }
-    if ((q->qtype == kDNSType_AAAA) && d->req_AAAA)
+    else if (server->isCell && (q->flags & kDNSServiceFlagsDenyCellular))
     {
-        LogDebug("ShouldSuppressUnicastQuery: Query not suppressed for %##s, qtype %s, DNSServer %##s %#a:%d allows AAAA queries", q->qname.c,
-                DNSTypeName(q->qtype), d->domain.c, &d->addr, mDNSVal16(d->port));
-        return mDNSfalse;
+        suppress = mDNStrue;
+        reason   = " (interface is cellular)";
     }
-#if USE_DNS64
-    if (DNS64IsQueryingARecord(q->dns64.state))
+    else if (server->isExpensive && (q->flags & kDNSServiceFlagsDenyExpensive))
     {
-        LogDebug("ShouldSuppressUnicastQuery: DNS64 query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
-        return mDNSfalse;
+        suppress = mDNStrue;
+        reason   = " (interface is expensive)";
     }
+    else if (server->isConstrained && (q->flags & kDNSServiceFlagsDenyConstrained))
+    {
+        suppress = mDNStrue;
+        reason   = " (interface is constrained)";
+    }
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
+    else if (q->SuppressUnusable && !DNS64IsQueryingARecord(q->dns64.state))
+#else
+    else if (q->SuppressUnusable)
 #endif
-
-    LogInfo("ShouldSuppressUnicastQuery: Query suppressed for %##s, qtype %s, since DNS Configuration does not allow (req_A %s, req_AAAA %s, CLAT46 %s)",
-        q->qname.c, DNSTypeName(q->qtype), TrueFalseStr(d->req_A), TrueFalseStr(d->req_AAAA), TrueFalseStr(d->isCLAT46));
-
-    return mDNStrue;
-}
-
-mDNSlocal mDNSBool ShouldSuppressDotLocalQuery(mDNS *const m, DNSQuestion *q)
-{
-    NetworkInterfaceInfo *intf;
-    AuthRecord *rr;
-    mDNSBool ret;
-
-    // Check to see if there is at least one interface other than loopback and don't suppress
-    // .local questions if you find one. If we have at least one interface, it means that
-    // we can send unicast queries for the .local name and we don't want to suppress
-    // multicast in that case as upper layers don't know how to handle if we return a 
-    // negative response for multicast followed by a positive response for unicast.
-    //
-    // Note: we used to check for multicast capable interfaces instead of just any interface
-    // present. That did not work in the case where we have a valid interface for unicast
-    // but not multicast capable e.g., cellular, as we ended up delivering a negative response 
-    // first and the upper layer did not wait for the positive response that came later.
-    for (intf = m->HostInterfaces; intf; intf = intf->next)
     {
-        if (intf->InterfaceActive && !intf->Loopback)
+        if (q->qtype == kDNSType_A)
         {
-            LogInfo("ShouldSuppressDotLocalQuery: Found interface %s, not suppressing", intf->ifname);
-            return mDNSfalse;
+            if (!server->usableA)
+            {
+                suppress = mDNStrue;
+                reason   = " (A records are unusable)";
+            }
+            // If the server's configuration allows A record queries, suppress this query if
+            //     1. the interface associated with the server is CLAT46; and
+            //     2. the query has the kDNSServiceFlagsPathEvaluationDone flag, indicating that it's from libnetwork.
+            // See <rdar://problem/42672030> for more info.
+            else if (server->isCLAT46 && (q->flags & kDNSServiceFlagsPathEvaluationDone))
+            {
+                suppress = mDNStrue;
+                reason   = " (CLAT46 A records are unusable)";
+            }
         }
-    }
-
-    // 1. If we find a LocalOnly or P2P record answering this question, then don't suppress it.
-    //    Set m->CurrentQuestion as it is required by AnswerQuestionWithLORecord.
-    m->CurrentQuestion = q;
-    ret = AnswerQuestionWithLORecord(m, q, mDNStrue);
-    m->CurrentQuestion = mDNSNULL;
-
-    if (ret)
-    {
-        LogInfo("ShouldSuppressDotLocalQuery: Found LocalOnly record for %##s (%s), not suppressing", q->qname.c,
-            DNSTypeName(q->qtype));
-        return mDNSfalse;
-    }
-
-    // 2. If we find a local AuthRecord answering this question, then don't suppress it. 
-    for (rr = m->ResourceRecords; rr; rr = rr->next)
-    {
-        if (ResourceRecordAnswersQuestion(&rr->resrec, q))
+        else if (q->qtype == kDNSType_AAAA)
         {
-            LogInfo("ShouldSuppressDotLocalQuery: Found resource record %s for %##s (%s) not suppressing", ARDisplayString(m, rr),
-                q->qname.c, DNSTypeName(q->qtype));
-            return mDNSfalse;
+            if (!server->usableAAAA)
+            {
+                suppress = mDNStrue;
+                reason   = " (AAAA records are unusable)";
+            }
         }
     }
-    return mDNStrue;
+    if (suppress)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "[Q%u] ShouldSuppressUnicastQuery: Query suppressed for " PRI_DM_NAME " " PUB_S PUB_S,
+            mDNSVal16(q->TargetQID), DM_NAME_PARAM(&q->qname), DNSTypeName(q->qtype), reason ? reason : "");
+    }
+    return suppress;
 }
 
-mDNSlocal mDNSBool ShouldSuppressQuery(mDNS *const m, DNSQuestion *q)
+mDNSlocal mDNSBool ShouldSuppressQuery(DNSQuestion *q)
 {
     if (q->InterfaceID == mDNSInterface_LocalOnly)
     {
-        LogInfo("ShouldSuppressQuery: LocalOnly query not suppressed for %##s, qtype %s", q->qname.c, DNSTypeName(q->qtype));
         return mDNSfalse;
     }
-
-    if (q->qtype != kDNSType_A && q->qtype != kDNSType_AAAA)
+    if (!q->IsUnicastDotLocal && IsLocalDomain(&q->qname))
     {
-        LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, not A/AAAA type", q->qname.c, DNSTypeName(q->qtype));
         return mDNSfalse;
     }
-
-    // We still want the ability to be able to listen to the local services and hence
-    // don't fail .local query if we have local records that can potentially answer
-    // the question.
-    if (q->InterfaceID != mDNSInterface_Unicast && IsLocalDomain(&q->qname))
-    {
-        if (!ShouldSuppressDotLocalQuery(m, q))
-        {
-            LogInfo("ShouldSuppressQuery: Query not suppressed for %##s, qtype %s, Local question", q->qname.c, DNSTypeName(q->qtype));
-            return mDNSfalse;
-        }
-        else
-        {
-            LogInfo("ShouldSuppressQuery: Query suppressed for %##s, qtype %s, Local question", q->qname.c, DNSTypeName(q->qtype));
-            return mDNStrue;
-        }
-    }
-
-    return (ShouldSuppressUnicastQuery(m, q, q->qDNSServer));
+    return (ShouldSuppressUnicastQuery(q, q->qDNSServer));
 }
 
 mDNSlocal void CacheRecordRmvEventsForCurrentQuestion(mDNS *const m, DNSQuestion *q)
 {
-    CacheRecord *rr;
+    CacheRecord *cr;
     CacheGroup *cg;
 
     cg = CacheGroupForName(m, q->qnamehash, &q->qname);
-    for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
+    for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
     {
         // Don't deliver RMV events for negative records
-        if (rr->resrec.RecordType == kDNSRecordTypePacketNegative)
+        if (cr->resrec.RecordType == kDNSRecordTypePacketNegative)
         {
-            LogInfo("CacheRecordRmvEventsForCurrentQuestion: CacheRecord %s Suppressing RMV events for question %p %##s (%s), CRActiveQuestion %p, CurrentAnswers %d",
-                    CRDisplayString(m, rr), q, q->qname.c, DNSTypeName(q->qtype), rr->CRActiveQuestion, q->CurrentAnswers);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                      "[R%u->Q%u] CacheRecordRmvEventsForCurrentQuestion: CacheRecord " PRI_S " Suppressing RMV events for question %p " PRI_DM_NAME " (" PUB_S "), CRActiveQuestion %p, CurrentAnswers %d",
+                      q->request_id, mDNSVal16(q->TargetQID), CRDisplayString(m, cr), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), cr->CRActiveQuestion, q->CurrentAnswers);
             continue;
         }
 
-        if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+        if (SameNameCacheRecordAnswersQuestion(cr, q))
         {
             LogInfo("CacheRecordRmvEventsForCurrentQuestion: Calling AnswerCurrentQuestionWithResourceRecord (RMV) for question %##s using resource record %s LocalAnswers %d",
-                    q->qname.c, CRDisplayString(m, rr), q->LOAddressAnswers);
+                    q->qname.c, CRDisplayString(m, cr), q->LOAddressAnswers);
 
             q->CurrentAnswers--;
-            if (rr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
-            if (rr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
-
-            if (rr->CRActiveQuestion == q)
-            {
-                DNSQuestion *qptr;
-                // If this was the active question for this cache entry, it was the one that was
-                // responsible for keeping the cache entry fresh when the cache entry was reaching
-                // its expiry. We need to handover the responsibility to someone else. Otherwise,
-                // when the cache entry is about to expire, we won't find an active question
-                // (pointed by CRActiveQuestion) to refresh the cache.
-                for (qptr = m->Questions; qptr; qptr=qptr->next)
-                    if (qptr != q && ActiveQuestion(qptr) && ResourceRecordAnswersQuestion(&rr->resrec, qptr))
-                        break;
-
-                if (qptr)
-                    LogInfo("CacheRecordRmvEventsForCurrentQuestion: Updating CRActiveQuestion to %p for cache record %s, "
-                            "Original question CurrentAnswers %d, new question CurrentAnswers %d, SuppressUnusable %d, SuppressQuery %d",
-                            qptr, CRDisplayString(m,rr), q->CurrentAnswers, qptr->CurrentAnswers, qptr->SuppressUnusable, qptr->SuppressQuery);
-
-                rr->CRActiveQuestion = qptr;        // Question used to be active; new value may or may not be null
-                if (!qptr) m->rrcache_active--; // If no longer active, decrement rrcache_active count
-            }
-            AnswerCurrentQuestionWithResourceRecord(m, rr, QC_rmv);
+            if (cr->resrec.rdlength > SmallRecordLimit) q->LargeAnswers--;
+            if (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) q->UniqueAnswers--;
+            AnswerCurrentQuestionWithResourceRecord(m, cr, QC_rmv);
             if (m->CurrentQuestion != q) break;     // If callback deleted q, then we're finished here
         }
     }
@@ -11595,24 +11538,28 @@ mDNSlocal void SuppressStatusChanged(mDNS *const m, DNSQuestion *q, DNSQuestion
     // NOTE: CacheRecordRmvEventsForQuestion will not generate RMV events for queries that have non-zero
     // LOAddressAnswers. Hence it is important that we call CacheRecordRmvEventsForQuestion before
     // LocalRecordRmvEventsForQuestion (which decrements LOAddressAnswers)
-    if (q->SuppressQuery)
+    if (q->Suppressed)
     {
-        q->SuppressQuery = mDNSfalse;
+        q->Suppressed = mDNSfalse;
         if (!CacheRecordRmvEventsForQuestion(m, q))
         {
-            LogInfo("SuppressStatusChanged: Question deleted while delivering RMV events from cache");
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "[R%u->Q%u] SuppressStatusChanged: Question deleted while delivering RMV events from cache",
+                q->request_id, mDNSVal16(q->TargetQID));
             return;
         }
-        q->SuppressQuery = mDNStrue;
+        q->Suppressed = mDNStrue;
     }
 
     // SuppressUnusable does not affect questions that are answered from the local records (/etc/hosts)
-    // and SuppressQuery status does not mean anything for these questions. As we are going to stop the
+    // and Suppressed status does not mean anything for these questions. As we are going to stop the
     // question below, we need to deliver the RMV events so that the ADDs that will be delivered during
     // the restart will not be a duplicate ADD
     if (!LocalRecordRmvEventsForQuestion(m, q))
     {
-        LogInfo("SuppressStatusChanged: Question deleted while delivering RMV events from Local AuthRecords");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "[R%u->Q%u] SuppressStatusChanged: Question deleted while delivering RMV events from Local AuthRecords",
+            q->request_id, mDNSVal16(q->TargetQID));
         return;
     }
 
@@ -11626,9 +11573,9 @@ mDNSlocal void SuppressStatusChanged(mDNS *const m, DNSQuestion *q, DNSQuestion
     //
     // 2. Previously it was not suppressed and now it is suppressed. We need to restart the questions
     // so that we redo the duplicate checks in mDNS_StartQuery_internal. A SuppressUnusable question
-    // is a duplicate of non-SuppressUnusable question if it is not suppressed (SuppressQuery is false).
+    // is a duplicate of non-SuppressUnusable question if it is not suppressed (Suppressed is false).
     // A SuppressUnusable question is not a duplicate of non-SuppressUnusable question if it is suppressed
-    // (SuppressQuery is true). The reason for this is that when a question is suppressed, we want an
+    // (Suppressed is true). The reason for this is that when a question is suppressed, we want an
     // immediate response and not want to be blocked behind a question that is querying DNS servers. When
     // the question is not suppressed, we don't want two active questions sending packets on the wire.
     // This affects both efficiency and also the current design where there is only one active question
@@ -11643,7 +11590,9 @@ mDNSlocal void SuppressStatusChanged(mDNS *const m, DNSQuestion *q, DNSQuestion
     //
     // It is much cleaner and less error prone to build a list of questions and restart at the end.
 
-    LogInfo("SuppressStatusChanged: Stop question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+        "[R%u->Q%u] SuppressStatusChanged: Stop question %p " PRI_DM_NAME " (" PUB_S ")",
+        q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
     mDNS_StopQuery_internal(m, q);
     q->next = *restart;
     *restart = q;
@@ -11659,7 +11608,7 @@ mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
     // we potentially restart questions here in this function that ends up as new questions,
     // which may be suppressed at this instance. Before it is handled we get another network
     // event that changes the status e.g., address becomes available. If we did not process
-    // new questions, we would never change its SuppressQuery status.
+    // new questions, we would never change its Suppressed status.
     //
     // CurrentQuestion is used by RmvEventsForQuestion below. While delivering RMV events, the
     // application callback can potentially stop the current question (detected by CurrentQuestion) or
@@ -11676,9 +11625,9 @@ mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
         m->RestartQuestion = q->next;
         if (q->SuppressUnusable)
         {
-            mDNSBool old = q->SuppressQuery;
-            q->SuppressQuery = ShouldSuppressQuery(m, q);
-            if (q->SuppressQuery != old)
+            const mDNSBool old = q->Suppressed;
+            q->Suppressed = ShouldSuppressQuery(q);
+            if (q->Suppressed != old)
             {
                 // Previously it was not suppressed, Generate RMV events for the ADDs that we might have delivered before
                 // followed by a negative cache response. Temporarily turn off suppression so that
@@ -11700,7 +11649,7 @@ mDNSexport void CheckSuppressUnusableQuestions(mDNS *const m)
 mDNSlocal void RestartUnicastQuestions(mDNS *const m)
 {
     DNSQuestion *q;
-    DNSQuestion *restart = mDNSNULL;
+    DNSQuestion *restartList = mDNSNULL;
 
     if (m->RestartQuestion)
         LogMsg("RestartUnicastQuestions: ERROR!! m->RestartQuestion already set: %##s (%s)",
@@ -11715,37 +11664,25 @@ mDNSlocal void RestartUnicastQuestions(mDNS *const m)
             if (mDNSOpaque16IsZero(q->TargetQID))
                 LogMsg("RestartUnicastQuestions: ERROR!! Restart set for multicast question %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
-            q->Restart = 0;
-            SuppressStatusChanged(m, q, &restart);
+            q->Restart = mDNSfalse;
+            SuppressStatusChanged(m, q, &restartList);
         }
     }
-    while (restart)
+    while ((q = restartList) != mDNSNULL)
     {
-        q = restart;
-        restart = restart->next;
+        restartList = q->next;
         q->next = mDNSNULL;
-        LogInfo("RestartUnicastQuestions: Start question %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "[R%u->Q%u] RestartUnicastQuestions: Start question %p " PRI_DM_NAME " (" PUB_S ")",
+             q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
         mDNS_StartQuery_internal(m, q);
     }
 }
 
-
 // ValidateParameters() is called by mDNS_StartQuery_internal() to check the client parameters of 
 // DNS Question that are already set by the client before calling mDNS_StartQuery() 
 mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question)
 {
-
-    if (question->Target.type && !ValidQuestionTarget(question))
-    {
-        LogMsg("ValidateParameters: Warning! Target.type = %ld port = %u (Client forgot to initialize before calling mDNS_StartQuery? for question %##s)",
-               question->Target.type, mDNSVal16(question->TargetPort), question->qname.c);
-        question->Target.type = mDNSAddrType_None;
-    }
-
-    // If no question->Target specified, clear TargetPort
-    if (!question->Target.type)
-        question->TargetPort = zeroIPPort;
-
     if (!ValidateDomainName(&question->qname))
     {
         LogMsg("ValidateParameters: Attempt to start query with invalid qname %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
@@ -11753,12 +11690,12 @@ mDNSlocal mStatus ValidateParameters(mDNS *const m, DNSQuestion *const question)
     }
 
     // If this question is referencing a specific interface, verify it exists 
-    if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID) && question->InterfaceID != mDNSInterface_Unicast)
+    if (question->InterfaceID && !LocalOnlyOrP2PInterface(question->InterfaceID))
     {
         NetworkInterfaceInfo *intf = FirstInterfaceForID(m, question->InterfaceID);
         if (!intf)
             LogInfo("ValidateParameters: Note: InterfaceID %d for question %##s (%s) not currently found in active interface list",
-                    (uint32_t)question->InterfaceID, question->qname.c, DNSTypeName(question->qtype));
+                    IIDPrintable(question->InterfaceID), question->qname.c, DNSTypeName(question->qtype));
     }
 
     return(mStatus_NoError);
@@ -11771,10 +11708,10 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
     // First reset all DNS Configuration
     question->qDNSServer          = mDNSNULL;
     question->validDNSServers     = zeroOpaque128;
-    question->triedAllServersOnce = 0;
-    question->noServerResponse    = 0;
+    question->triedAllServersOnce = mDNSfalse;
+    question->noServerResponse    = mDNSfalse;
     question->StopTime            = (question->TimeoutQuestion) ? question->StopTime : 0;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     mDNSPlatformMemZero(&question->metrics, sizeof(question->metrics));
     question->metrics.expiredAnswerState = (question->allowExpired != AllowExpired_None) ? ExpiredAnswer_Allowed : ExpiredAnswer_None;
 #endif
@@ -11793,14 +11730,17 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
         if (question->TimeoutQuestion && !question->StopTime)
         {
             question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
-            LogInfo("InitDNSConfig: Setting StopTime on the uDNS question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "[Q%u] InitDNSConfig: Setting StopTime on the uDNS question %p " PRI_DM_NAME " (" PUB_S ")",
+                mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype));
         }
 
         question->qDNSServer = GetServerForQuestion(m, question);
-        LogDebug("InitDNSConfig: question %p %##s (%s) Timeout %d, DNS Server %#a:%d",
-                 question, question->qname.c, DNSTypeName(question->qtype), timeout,
-                 question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
-                 mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+            "[R%u->Q%u] InitDNSConfig: question %p " PRI_DM_NAME " " PUB_S " Timeout %d, DNS Server " PRI_IP_ADDR ":%d",
+            question->request_id, mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(question->qname.c),
+            DNSTypeName(question->qtype), timeout, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+            mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
     }
     else if (question->TimeoutQuestion && !question->StopTime)
     {
@@ -11809,7 +11749,9 @@ mDNSlocal void InitDNSConfig(mDNS *const m, DNSQuestion *const question)
         mDNSu32 timeout = LocalOnlyOrP2PInterface(question->InterfaceID) ?
                             DEFAULT_LO_OR_P2P_TIMEOUT : GetTimeoutForMcastQuestion(m, question);
         question->StopTime = NonZeroTime(m->timenow + timeout * mDNSPlatformOneSecond);
-        LogInfo("InitDNSConfig: Setting StopTime on question %p %##s (%s)", question, question->qname.c, DNSTypeName(question->qtype));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                  "[R%u->Q%u] InitDNSConfig: Setting StopTime on the uDNS question %p " PRI_DM_NAME " (" PUB_S ")",
+                  question->request_id, mDNSVal16(question->TargetQID), question, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype));
     }
     // Set StopTime here since it is a part of DNS Configuration 
     if (question->StopTime)
@@ -11891,17 +11833,10 @@ mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question)
     InitDNSConfig(m, question);
 
     question->AuthInfo          = GetAuthInfoForQuestion(m, question);
-    question->SuppressQuery     = 0;
-    if (question->SuppressUnusable)
-        question->SuppressQuery = ShouldSuppressQuery(m, question);
-
-    // If ServiceID is 0 or the policy disallows making DNS requests,
-    // set DisallowPID
-    question->DisallowPID       = (question->ServiceID == 0 || isBlocked);
-    if (question->DisallowPID)
-        LogInfo("InitCommonState: Query suppressed for %##s (%s), PID %d/ServiceID %d not allowed", question->qname.c,
-            DNSTypeName(question->qtype), question->pid, question->ServiceID);
 
+    // The question's BlockedByPolicy value must be set before calling ShouldSuppressQuery().
+    question->BlockedByPolicy   = isBlocked ? mDNStrue : mDNSfalse;
+    question->Suppressed        = ShouldSuppressQuery(question);
     question->NextInDQList      = mDNSNULL;
     question->SendQNow          = mDNSNULL;
     question->SendOnAll         = mDNSfalse;
@@ -11929,7 +11864,7 @@ mDNSlocal void InitCommonState(mDNS *const m, DNSQuestion *const question)
     for (i=0; i<DupSuppressInfoSize; i++)
         question->DupSuppress[i].InterfaceID = mDNSNULL;
 
-    question->Restart = 0;
+    question->Restart = mDNSfalse;
 
     debugf("InitCommonState: Question %##s (%s) Interface %p Now %d Send in %d Answer in %d (%p) %s (%p)",
             question->qname.c, DNSTypeName(question->qtype), question->InterfaceID, m->timenow,
@@ -11974,20 +11909,13 @@ mDNSlocal void InitLLQNATState(mDNS *const m)
 
 mDNSlocal void InitLLQState(DNSQuestion *const question)
 {
-    question->state             = LLQ_InitialRequest;
+    question->state             = LLQ_Init;
     question->ReqLease          = 0;
     question->expire            = 0;
     question->ntries            = 0;
     question->id                = zeroOpaque64;
 }
 
-#ifdef DNS_PUSH_ENABLED
-mDNSlocal void InitDNSPNState(DNSQuestion *const question)
-{
-    question->dnsPushState = DNSPUSH_INIT;
-}
-#endif // DNS_PUSH_ENABLED
-
 // InitDNSSECProxyState() is called by mDNS_StartQuery_internal() to initialize
 // DNSSEC & DNS Proxy fields of the DNS Question. 
 mDNSlocal void InitDNSSECProxyState(mDNS *const m, DNSQuestion *const question)
@@ -12031,17 +11959,23 @@ mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question)
         // then we log a line as it could indicate an issue
         if (question->DuplicateOf->qDNSServer == mDNSNULL)
         {
-            if (question->qDNSServer)
-                LogInfo("FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(%#a:%d) but original question(%p) has no DNS Server! %##s (%s)",
-                        question, question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
-                        mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort),
-                        question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype));
+            if (question->qDNSServer) {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                       "[R%d->Q%d] FinalizeUnicastQuestion: Current(dup) question %p has DNSServer(" PRI_IP_ADDR ":%d) but original question(%p) has no DNS Server! " PRI_DM_NAME " (" PUB_S ")",
+                       question->request_id, mDNSVal16(question->TargetQID), question,
+                       question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+                       mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort), question->DuplicateOf,
+                       DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype));
+            }
+
         }
         question->qDNSServer = question->DuplicateOf->qDNSServer;
-        LogInfo("FinalizeUnicastQuestion: Duplicate question %p (%p) %##s (%s), DNS Server %#a:%d",
-                 question, question->DuplicateOf, question->qname.c, DNSTypeName(question->qtype),
-                 question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
-                 mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d->DupQ%d->Q%d] FinalizeUnicastQuestion: Duplicate question %p (%p) " PRI_DM_NAME " (" PUB_S "), DNS Server " PRI_IP_ADDR ":%d",
+               question->request_id, mDNSVal16(question->DuplicateOf->TargetQID), mDNSVal16(question->TargetQID),
+               question, question->DuplicateOf, DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype),
+               question->qDNSServer ? &question->qDNSServer->addr : mDNSNULL,
+               mDNSVal16(question->qDNSServer ? question->qDNSServer->port : zeroIPPort));
     }
 
     ActivateUnicastQuery(m, question, mDNSfalse);
@@ -12059,9 +11993,6 @@ mDNSlocal void FinalizeUnicastQuestion(mDNS *const m, DNSQuestion *question)
         // the LLQ NAT state only for unicast. Otherwise we will unnecessarily
         // start the NAT traversal that is not needed.
         InitLLQNATState(m);
-#if APPLE_OSX_mDNSResponder
-        UpdateAutoTunnelDomainStatuses(m);
-#endif
     }
 }
 
@@ -12081,6 +12012,8 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
 #ifdef USE_LIBIDN
     // If the TLD includes high-ascii bytes, assume it will need to be converted to Punycode.
     // (In the future the root name servers may answer UTF-8 queries directly, but for now they do not.)
+    // This applies to the top label (TLD) only
+    // -- for the second level and down we try UTF-8 first, and then fall back to Punycode only if UTF-8 fails.
     if (IsHighASCIILabel(LastLabel(&question->qname)))
     {
         domainname newname;
@@ -12089,11 +12022,11 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
     }
 #endif // USE_LIBIDN
 
-    question->TargetQID =
 #ifndef UNICAST_DISABLED
-                          (question->Target.type || Question_uDNS(question)) ? mDNS_NewMessageID(m) :
-#endif // UNICAST_DISABLED
-                          zeroID;
+    question->TargetQID = Question_uDNS(question) ? mDNS_NewMessageID(m) : zeroID;
+#else
+    question->TargetQID = zeroID;
+#endif
     debugf("mDNS_StartQuery_internal: %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
 
     // Note: It important that new questions are appended at the *end* of the list, not prepended at the start
@@ -12119,9 +12052,6 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
     InitCommonState(m, question);
     InitWABState(question);
     InitLLQState(question);
-#ifdef DNS_PUSH_ENABLED
-    InitDNSPNState(question);
-#endif // DNS_PUSH_ENABLED
     InitDNSSECProxyState(m, question);
 
     // FindDuplicateQuestion should be called last after all the intialization
@@ -12153,10 +12083,11 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
         }
         else
         {
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
             m->NumAllInterfaceQuestions++;
-            LogInfo("mDNS_StartQuery_internal: NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
-                m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "mDNS_StartQuery_internal: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_DM_NAME " (" PUB_S ")",
+                m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
             if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
             {
                 m->NextBonjourDisableTime = 0;
@@ -12168,7 +12099,7 @@ mDNSexport mStatus mDNS_StartQuery_internal(mDNS *const m, DNSQuestion *const qu
                     m->NetworkChanged = m->timenow;
                 }
             }
-#endif // BONJOUR_ON_DEMAND
+#endif
             if (question->WakeOnResolve)
             {
                 LogInfo("mDNS_StartQuery_internal: Purging for %##s", question->qname.c);
@@ -12199,7 +12130,7 @@ mDNSexport void CancelGetZoneData(mDNS *const m, ZoneData *nta)
 mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const question)
 {
     CacheGroup *cg = CacheGroupForName(m, question->qnamehash, &question->qname);
-    CacheRecord *rr;
+    CacheRecord *cr;
     DNSQuestion **qp = &m->Questions;
 
     //LogInfo("mDNS_StopQuery_internal %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
@@ -12217,18 +12148,19 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
         return(mStatus_BadReferenceErr);
     }
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     if (!LocalOnlyOrP2PInterface(question->InterfaceID) && mDNSOpaque16IsZero(question->TargetQID))
     {
         if (m->NumAllInterfaceRecords + m->NumAllInterfaceQuestions == 1)
             m->NextBonjourDisableTime = NonZeroTime(m->timenow + (BONJOUR_DISABLE_DELAY * mDNSPlatformOneSecond));
         m->NumAllInterfaceQuestions--;
-        LogInfo("mDNS_StopQuery_internal:  NumAllInterfaceRecords %d NumAllInterfaceQuestions %d %##s (%s)",
-            m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, question->qname.c, DNSTypeName(question->qtype));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "mDNS_StopQuery_internal: NumAllInterfaceRecords %u NumAllInterfaceQuestions %u " PRI_DM_NAME " (" PUB_S ")",
+            m->NumAllInterfaceRecords, m->NumAllInterfaceQuestions, DM_NAME_PARAM(&question->qname), DNSTypeName(question->qtype));
     }
-#endif // BONJOUR_ON_DEMAND
+#endif
 
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     if (Question_uDNS(question) && !question->metrics.answered && (question->metrics.querySendCount > 0))
     {
         const domainname *  queryName;
@@ -12238,7 +12170,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
         queryName  = question->metrics.originalQName ? question->metrics.originalQName : &question->qname;
         isForCell  = (question->qDNSServer && question->qDNSServer->isCell);
         durationMs = ((m->timenow - question->metrics.firstQueryTime) * 1000) / mDNSPlatformOneSecond;
-        MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, question->metrics.expiredAnswerState, durationMs, isForCell);
+        MetricsUpdateDNSQueryStats(queryName, question->qtype, mDNSNULL, question->metrics.querySendCount, question->metrics.expiredAnswerState, question->metrics.dnsOverTCPState, durationMs, isForCell);
     }
 #endif
     // Take care to cut question from list *before* calling UpdateQuestionDuplicates
@@ -12248,9 +12180,9 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
 
     // 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)
+    for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
     {
-        if (rr->CRActiveQuestion == question)
+        if (cr->CRActiveQuestion == question)
         {
             DNSQuestion *q;
             DNSQuestion *replacement = mDNSNULL;
@@ -12260,7 +12192,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
             // via CacheRecordRmv() when the cache record expires.
             for (q = m->Questions; q && (q != m->NewQuestions); q = q->next)
             {
-                if (!q->DuplicateOf && !QuerySuppressed(q) && ResourceRecordAnswersQuestion(&rr->resrec, q))
+                if (!q->DuplicateOf && !q->Suppressed && CacheRecordAnswersQuestion(cr, q))
                 {
                     if (q->ThisQInterval > 0)
                     {
@@ -12275,8 +12207,8 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
             }
             if (replacement)
                 debugf("mDNS_StopQuery_internal: Updating CRActiveQuestion to %p for cache record %s, Original question CurrentAnswers %d, new question "
-                       "CurrentAnswers %d, SuppressQuery %d", replacement, CRDisplayString(m,rr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->SuppressQuery);
-            rr->CRActiveQuestion = replacement;    // Question used to be active; new value may or may not be null
+                       "CurrentAnswers %d, Suppressed %d", replacement, CRDisplayString(m,cr), question->CurrentAnswers, replacement->CurrentAnswers, replacement->Suppressed);
+            cr->CRActiveQuestion = replacement;    // Question used to be active; new value may or may not be null
             if (!replacement) m->rrcache_active--; // If no longer active, decrement rrcache_active count
         }
     }
@@ -12360,19 +12292,11 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
                 question->tcp           = mDNSNULL;
             }
         }
-#ifdef DNS_PUSH_ENABLED
-        else if (question->dnsPushState == DNSPUSH_ESTABLISHED)
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+        else if (question->dnsPushServer != mDNSNULL)
         {
-            if (question->tcp)
-            {
-                UnSubscribeToDNSPushNotificationServer(m, q);
-                question->tcp->question = mDNSNULL;
-                question->tcp           = mDNSNULL;
-            }
+            UnSubscribeToDNSPushNotificationServer(m, question);
         }
-#endif // DNS_PUSH_ENABLED
-#if APPLE_OSX_mDNSResponder
-        UpdateAutoTunnelDomainStatuses(m);
 #endif
     }
     // wait until we send the refresh above which needs the nta
@@ -12384,12 +12308,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
         question->DAIFreeCallback(m, question->DNSSECAuthInfo);
         question->DNSSECAuthInfo = mDNSNULL;
     }
-    if (question->AnonInfo)
-    {
-        FreeAnonInfo(question->AnonInfo);
-        question->AnonInfo = mDNSNULL;
-    }
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     if (question->metrics.originalQName)
     {
         mDNSPlatformMemFree(question->metrics.originalQName);
@@ -12397,7 +12316,7 @@ mDNSexport mStatus mDNS_StopQuery_internal(mDNS *const m, DNSQuestion *const que
     }
 #endif
 
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
     DNS64ResetState(question);
 #endif
 
@@ -12438,16 +12357,18 @@ mDNSexport mStatus mDNS_StopQueryWithRemoves(mDNS *const m, DNSQuestion *const q
     status = mDNS_StopQuery_internal(m, question);
     if (status == mStatus_NoError && !qq)
     {
-        const CacheRecord *rr;
+        const CacheRecord *cr;
         CacheGroup *const cg = CacheGroupForName(m, question->qnamehash, &question->qname);
         LogInfo("Generating terminal removes for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-        for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
-            if (rr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameRecordAnswersQuestion(&rr->resrec, question))
+        for (cr = cg ? cg->members : mDNSNULL; cr; cr=cr->next)
+        {
+            if (cr->resrec.RecordType != kDNSRecordTypePacketNegative && SameNameCacheRecordAnswersQuestion(cr, question))
             {
                 // Don't use mDNS_DropLockBeforeCallback() here, since we don't allow API calls
                 if (question->QuestionCallback)
-                    question->QuestionCallback(m, question, &rr->resrec, mDNSfalse);
+                    question->QuestionCallback(m, question, &cr->resrec, mDNSfalse);
             }
+        }
     }
     mDNS_Unlock(m);
     return(status);
@@ -12478,13 +12399,12 @@ mDNSexport mStatus mDNS_ReconfirmByValue(mDNS *const m, ResourceRecord *const rr
 
 mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const question,
                                             const domainname *const srv, const domainname *const domain,
-                                            const mDNSu8 *anondata, const mDNSInterfaceID InterfaceID, mDNSu32 flags,
+                                            const mDNSInterfaceID InterfaceID, mDNSu32 flags,
                                             mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
                                             mDNSQuestionCallback *Callback, void *Context)
 {
     question->InterfaceID      = InterfaceID;
     question->flags            = flags;
-    question->Target           = zeroAddr;
     question->qtype            = kDNSType_PTR;
     question->qclass           = kDNSClass_IN;
     question->LongLived        = mDNStrue;
@@ -12492,42 +12412,31 @@ mDNSlocal mStatus mDNS_StartBrowse_internal(mDNS *const m, DNSQuestion *const qu
     question->ForceMCast       = ForceMCast;
     question->ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
     question->SuppressUnusable = mDNSfalse;
-    question->SearchListIndex  = 0;
-    question->AppendSearchDomains = 0;
-    question->RetryWithSearchDomains = mDNSfalse;
+    question->AppendSearchDomains = mDNSfalse;
     question->TimeoutQuestion  = 0;
     question->WakeOnResolve    = 0;
-    question->UseBackgroundTrafficClass = useBackgroundTrafficClass;
+    question->UseBackgroundTraffic = useBackgroundTrafficClass;
     question->ValidationRequired = 0;
     question->ValidatingResponse = 0;
     question->ProxyQuestion    = 0;
-    question->qnameOrig        = mDNSNULL;
-    question->AnonInfo         = mDNSNULL;
     question->QuestionCallback = Callback;
     question->QuestionContext  = Context;
 
     if (!ConstructServiceName(&question->qname, mDNSNULL, srv, domain))
         return(mStatus_BadParamErr);
 
-    if (anondata)
-    {
-        question->AnonInfo = AllocateAnonInfo(&question->qname, anondata, mDNSPlatformStrLen(anondata), mDNSNULL);
-        if (!question->AnonInfo)
-            return(mStatus_BadParamErr);
-    }
-
     return(mDNS_StartQuery_internal(m, question));
 }
 
 mDNSexport mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
                                     const domainname *const srv, const domainname *const domain,
-                                    const mDNSu8 *anondata, const mDNSInterfaceID InterfaceID, mDNSu32 flags,
+                                    const mDNSInterfaceID InterfaceID, mDNSu32 flags,
                                     mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
                                     mDNSQuestionCallback *Callback, void *Context)
 {
     mStatus status;
     mDNS_Lock(m);
-    status = mDNS_StartBrowse_internal(m, question, srv, domain, anondata, InterfaceID, flags, ForceMCast, useBackgroundTrafficClass, Callback, Context);
+    status = mDNS_StartBrowse_internal(m, question, srv, domain, InterfaceID, flags, ForceMCast, useBackgroundTrafficClass, Callback, Context);
     mDNS_Unlock(m);
     return(status);
 }
@@ -12538,7 +12447,6 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
 {
     question->InterfaceID      = InterfaceID;
     question->flags            = 0;
-    question->Target           = zeroAddr;
     question->qtype            = kDNSType_PTR;
     question->qclass           = kDNSClass_IN;
     question->LongLived        = mDNSfalse;
@@ -12546,17 +12454,13 @@ mDNSexport mStatus mDNS_GetDomains(mDNS *const m, DNSQuestion *const question, m
     question->ForceMCast       = mDNSfalse;
     question->ReturnIntermed   = mDNSfalse;
     question->SuppressUnusable = mDNSfalse;
-    question->SearchListIndex  = 0;
-    question->AppendSearchDomains = 0;
-    question->RetryWithSearchDomains = mDNSfalse;
+    question->AppendSearchDomains = mDNSfalse;
     question->TimeoutQuestion  = 0;
     question->WakeOnResolve    = 0;
-    question->UseBackgroundTrafficClass = mDNSfalse;
+    question->UseBackgroundTraffic = mDNSfalse;
     question->ValidationRequired = 0;
     question->ValidatingResponse = 0;
     question->ProxyQuestion    = 0;
-    question->qnameOrig        = mDNSNULL;
-    question->AnonInfo         = mDNSNULL;
     question->pid              = mDNSPlatformGetPID();
     question->euid             = 0;
     question->QuestionCallback = Callback;
@@ -12662,6 +12566,9 @@ mDNSexport mStatus mDNS_Deregister(mDNS *const m, AuthRecord *const rr)
 
 // 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);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void mDNS_RandomizedHostNameCallback(mDNS *m, AuthRecord *rr, mStatus result);
+#endif
 
 mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
 {
@@ -12673,47 +12580,75 @@ mDNSlocal NetworkInterfaceInfo *FindFirstAdvertisedInterface(mDNS *const m)
 
 // The parameter "set" here refers to the set of AuthRecords used to advertise this interface.
 // (It's a set of records, not a set of interfaces.)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, mDNSBool useRandomizedHostname)
+#else
 mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+#endif
 {
-    char buffer[MAX_REVERSE_MAPPING_NAME];
     NetworkInterfaceInfo *primary;
-    mDNSu8 recordType;
+    const domainname *hostname;
+    mDNSRecordCallback *hostnameCallback;
+    AuthRecord *addrAR;
+    AuthRecord *ptrAR;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    const mDNSBool interfaceIsAWDL = mDNSPlatformInterfaceIsAWDL(set->InterfaceID);
+#endif
+    mDNSu8 addrRecordType;
+    char buffer[MAX_REVERSE_MAPPING_NAME];
 
-    if (m->AutoTargetServices == 0)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if (interfaceIsAWDL || useRandomizedHostname)
     {
-        LogInfo("AdvertiseInterface: Returning due to AutoTargetServices zero for %s", set->ifname);
-        return;
+        hostname         = &m->RandomizedHostname;
+        hostnameCallback = mDNS_RandomizedHostNameCallback;
+    }
+    else
+#endif
+    {
+        hostname         = &m->MulticastHostname;
+        hostnameCallback = mDNS_HostNameCallback;
     }
 
-    primary = FindFirstAdvertisedInterface(m);
-    if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
-    // We should never have primary be NULL, because even if there is
-    // no other interface yet, we should always find ourself in the list.
-
-    // If interface is marked as a direct link, we can assume the address record is unique
-    // and does not need to go through the probe phase of the probe/announce packet sequence.
-    recordType = (set->DirectLink ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if (!interfaceIsAWDL && useRandomizedHostname)
+    {
+        addrAR = &set->RR_AddrRand;
+        ptrAR  = mDNSNULL;
+    }
+    else
+#endif
+    {
+        addrAR = &set->RR_A;
+        ptrAR  = &set->RR_PTR;
+    }
+    if (addrAR->resrec.RecordType != kDNSRecordTypeUnregistered) return;
 
-    if (set->DirectLink)
-        LogInfo("AdvertiseInterface: Marking address record as kDNSRecordTypeKnownUnique for %s", set->ifname);
+    addrRecordType = set->DirectLink ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if (hostname == &m->RandomizedHostname) addrRecordType = kDNSRecordTypeKnownUnique;
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+        "AdvertiseInterface: Advertising " PUB_S " hostname on interface " PUB_S,
+        (hostname == &m->RandomizedHostname) ? "randomized" : "normal", set->ifname);
+#else
+    LogInfo("AdvertiseInterface: Advertising for ifname %s", set->ifname);
+#endif
 
     // Send dynamic update for non-linklocal IPv4 Addresses
-    mDNS_SetupResourceRecord(&set->RR_A,     mDNSNULL, set->InterfaceID, kDNSType_A,     kHostNameTTL, recordType,                AuthRecordAny, mDNS_HostNameCallback, set);
-    mDNS_SetupResourceRecord(&set->RR_PTR,   mDNSNULL, set->InterfaceID, kDNSType_PTR,   kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL,              mDNSNULL);
-    mDNS_SetupResourceRecord(&set->RR_HINFO, mDNSNULL, set->InterfaceID, kDNSType_HINFO, kHostNameTTL, kDNSRecordTypeUnique,      AuthRecordAny, mDNSNULL,              mDNSNULL);
+    mDNS_SetupResourceRecord(addrAR, mDNSNULL, set->InterfaceID, kDNSType_A, kHostNameTTL, addrRecordType, AuthRecordAny, hostnameCallback, set);
+    if (ptrAR) mDNS_SetupResourceRecord(ptrAR, mDNSNULL, set->InterfaceID, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
 
 #if ANSWER_REMOTE_HOSTNAME_QUERIES
-    set->RR_A.AllowRemoteQuery  = mDNStrue;
-    set->RR_PTR.AllowRemoteQuery  = mDNStrue;
-    set->RR_HINFO.AllowRemoteQuery  = mDNStrue;
+    addrAR->AllowRemoteQuery = mDNStrue;
+    if (ptrAR) ptrAR->AllowRemoteQuery = mDNStrue;
 #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.namestorage, &m->MulticastHostname);
+    AssignDomainName(&addrAR->namestorage, hostname);
     if (set->ip.type == mDNSAddrType_IPv4)
     {
-        set->RR_A.resrec.rrtype = kDNSType_A;
-        set->RR_A.resrec.rdata->u.ipv4 = set->ip.ip.v4;
+        addrAR->resrec.rrtype        = kDNSType_A;
+        addrAR->resrec.rdata->u.ipv4 = set->ip.ip.v4;
         // 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]);
@@ -12721,8 +12656,8 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
     else if (set->ip.type == mDNSAddrType_IPv6)
     {
         int i;
-        set->RR_A.resrec.rrtype = kDNSType_AAAA;
-        set->RR_A.resrec.rdata->u.ipv6 = set->ip.ip.v6;
+        addrAR->resrec.rrtype        = kDNSType_AAAA;
+        addrAR->resrec.rdata->u.ipv6 = set->ip.ip.v6;
         for (i = 0; i < 16; i++)
         {
             static const char hexValues[] = "0123456789ABCDEF";
@@ -12734,102 +12669,121 @@ mDNSlocal void AdvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
         mDNS_snprintf(&buffer[64], sizeof(buffer)-64, "ip6.arpa.");
     }
 
-    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
+    if (ptrAR)
+    {
+        MakeDomainNameFromDNSNameString(&ptrAR->namestorage, buffer);
+        ptrAR->AutoTarget = Target_AutoHost;    // Tell mDNS that the target of this PTR is to be kept in sync with our host name
+        ptrAR->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
+    primary = FindFirstAdvertisedInterface(m);
+    if (!primary) primary = set; // If no existing advertised interface, this new NetworkInterfaceInfo becomes our new primary
+    // We should never have primary be NULL, because even if there is
+    // no other interface yet, we should always find ourself in the list.
 
-    mDNS_Register_internal(m, &set->RR_A);
-    mDNS_Register_internal(m, &set->RR_PTR);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if (!interfaceIsAWDL && useRandomizedHostname)
+    {
+        addrAR->RRSet = &primary->RR_AddrRand;
+    }
+    else
+#endif
+    {
+        addrAR->RRSet = &primary->RR_A;
+    }
+    mDNS_Register_internal(m, addrAR);
+    if (ptrAR) mDNS_Register_internal(m, ptrAR);
 
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
     // must be after the mDNS_Register_internal() calls so that records have complete rdata fields, etc
     D2D_start_advertising_interface(set);
-#endif // APPLE_OSX_mDNSResponder
+#endif
+}
 
-    if (!NO_HINFO && m->HIHardware.c[0] > 0 && m->HISoftware.c[0] > 0 && m->HIHardware.c[0] + m->HISoftware.c[0] <= 254)
+mDNSlocal void AdvertiseInterfaceIfNeeded(mDNS *const m, NetworkInterfaceInfo *set)
+{
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if (mDNSPlatformInterfaceIsAWDL(set->InterfaceID))
     {
-        mDNSu8 *p = set->RR_HINFO.resrec.rdata->u.data;
-        AssignDomainName(&set->RR_HINFO.namestorage, &m->MulticastHostname);
-        set->RR_HINFO.DependentOn = &set->RR_A;
-        mDNSPlatformMemCopy(p, &m->HIHardware, 1 + (mDNSu32)m->HIHardware.c[0]);
-        p += 1 + (int)p[0];
-        mDNSPlatformMemCopy(p, &m->HISoftware, 1 + (mDNSu32)m->HISoftware.c[0]);
-        mDNS_Register_internal(m, &set->RR_HINFO);
+        if ((m->AutoTargetAWDLIncludedCount > 0) || (m->AutoTargetAWDLOnlyCount > 0))
+        {
+            AdvertiseInterface(m, set, mDNSfalse);
+        }
     }
     else
     {
-        debugf("Not creating HINFO record: platform support layer provided no information");
-        set->RR_HINFO.resrec.RecordType = kDNSRecordTypeUnregistered;
+        if (m->AutoTargetServices          > 0) AdvertiseInterface(m, set, mDNSfalse);
+        if (m->AutoTargetAWDLIncludedCount > 0) AdvertiseInterface(m, set, mDNStrue);
     }
+#else
+    if (m->AutoTargetServices > 0) AdvertiseInterface(m, set);
+#endif
 }
 
-mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set)
+mDNSlocal void DeadvertiseInterface(mDNS *const m, NetworkInterfaceInfo *set, DeadvertiseFlags flags)
 {
-    if (m->AutoTargetServices == 0)
-    {
-        LogInfo("DeadvertiseInterface: Returning due to AutoTargetServices zero for %s", set->ifname);
-        return;
-    }
-
-#if APPLE_OSX_mDNSResponder
-    D2D_stop_advertising_interface(set);
-#endif // APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    const mDNSBool interfaceIsAWDL = mDNSPlatformInterfaceIsAWDL(set->InterfaceID);
+#endif
 
     // Unregister these records.
     // When doing the mDNS_Exit processing, we first call DeadvertiseInterface for each interface, so by the time the platform
     // support layer gets to call mDNS_DeregisterInterface, the address and PTR records have already been deregistered for it.
     // Also, in the event of a name conflict, one or more of our records will have been forcibly deregistered.
     // To avoid unnecessary and misleading warning messages, we check the RecordType before calling mDNS_Deregister_internal().
-    if (set->RR_A    .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_A,     mDNS_Dereg_normal);
-    if (set->RR_PTR  .resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR,   mDNS_Dereg_normal);
-    if (set->RR_HINFO.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_HINFO, mDNS_Dereg_normal);
-}
-
-mDNSlocal void AdvertiseAllInterfaceRecords(mDNS *const m)
-{
-    NetworkInterfaceInfo *intf;
-    for (intf = m->HostInterfaces; intf; intf = intf->next)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if ((!interfaceIsAWDL && (flags & kDeadvertiseFlag_NormalHostname)) ||
+        ( interfaceIsAWDL && (flags & kDeadvertiseFlag_RandHostname)))
+#else
+    if (flags & kDeadvertiseFlag_NormalHostname)
+#endif
     {
-        if (intf->Advertise)
-        {
-            LogInfo("AdvertiseInterface: Advertising for ifname %s", intf->ifname);
-            AdvertiseInterface(m, intf);
-        }
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+            "DeadvertiseInterface: Deadvertising " PUB_S " hostname on interface " PUB_S,
+            (flags & kDeadvertiseFlag_RandHostname) ? "randomized" : "normal", set->ifname);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+        D2D_stop_advertising_interface(set);
+#endif
+        if (set->RR_A.resrec.RecordType)   mDNS_Deregister_internal(m, &set->RR_A,   mDNS_Dereg_normal);
+        if (set->RR_PTR.resrec.RecordType) mDNS_Deregister_internal(m, &set->RR_PTR, mDNS_Dereg_normal);
     }
-}
-
-mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m)
-{
-    NetworkInterfaceInfo *intf;
-    for (intf = m->HostInterfaces; intf; intf = intf->next)
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    if (!interfaceIsAWDL && (flags & kDeadvertiseFlag_RandHostname))
     {
-        if (intf->Advertise)
-        {
-            LogInfo("DeadvertiseInterface: Deadvertising for ifname %s", intf->ifname);
-            DeadvertiseInterface(m, intf);
-        }
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+            "DeadvertiseInterface: Deadvertising randomized hostname on interface " PUB_S, set->ifname);
+        AuthRecord *const ar = &set->RR_AddrRand;
+        if (ar->resrec.RecordType) mDNS_Deregister_internal(m, ar, mDNS_Dereg_normal);
     }
+#endif
 }
 
 // Change target host name for record.  
 mDNSlocal void UpdateTargetHostName(mDNS *const m, AuthRecord *const rr)
 {
-#if APPLE_OSX_mDNSResponder
-        // If this record was also registered with any D2D plugins, stop advertising
-        // the version with the old host name.
-        D2D_stop_advertising_record(rr);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+    // If this record was also registered with any D2D plugins, stop advertising
+    // the version with the old host name.
+    D2D_stop_advertising_record(rr);
 #endif
 
     SetTargetToHostName(m, rr);
 
-#if APPLE_OSX_mDNSResponder
-        // Advertise the record with the updated host name with the D2D plugins if appropriate.
-        D2D_start_advertising_record(rr);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+    // Advertise the record with the updated host name with the D2D plugins if appropriate.
+    D2D_start_advertising_record(rr);
 #endif
 }
 
+mDNSlocal void DeadvertiseAllInterfaceRecords(mDNS *const m, DeadvertiseFlags flags)
+{
+    NetworkInterfaceInfo *intf;
+    for (intf = m->HostInterfaces; intf; intf = intf->next)
+    {
+        if (intf->Advertise) DeadvertiseInterface(m, intf, flags);
+    }
+}
+
 mDNSexport void mDNS_SetFQDN(mDNS *const m)
 {
     domainname newmname;
@@ -12845,8 +12799,8 @@ mDNSexport void mDNS_SetFQDN(mDNS *const m)
     else
     {
         AssignDomainName(&m->MulticastHostname, &newmname);
-        DeadvertiseAllInterfaceRecords(m);
-        AdvertiseAllInterfaceRecords(m);
+        DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_NormalHostname);
+        AdvertiseNecessaryInterfaceRecords(m);
     }
 
     // 3. Make sure that any AutoTarget SRV records (and the like) get updated
@@ -12904,6 +12858,44 @@ mDNSlocal void mDNS_HostNameCallback(mDNS *const m, AuthRecord *const rr, mStatu
         LogMsg("mDNS_HostNameCallback: Unknown error %d for registration of record %s", result,  rr->resrec.name->c);
 }
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSlocal void mDNS_RandomizedHostNameCallback(mDNS *const m, AuthRecord *const addrRecord, const mStatus result)
+{
+    (void)addrRecord;   // Unused parameter
+
+    if (result == mStatus_NameConflict)
+    {
+        AuthRecord *rr;
+        domainlabel newUUIDLabel;
+
+        GetRandomUUIDLabel(&newUUIDLabel);
+        if (SameDomainLabel(newUUIDLabel.c, m->RandomizedHostname.c))
+        {
+            IncrementLabelSuffix(&newUUIDLabel, mDNSfalse);
+        }
+
+        mDNS_Lock(m);
+
+        m->RandomizedHostname.c[0] = 0;
+        AppendDomainLabel(&m->RandomizedHostname, &newUUIDLabel);
+        AppendLiteralLabelString(&m->RandomizedHostname, "local");
+
+        DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_RandHostname);
+        AdvertiseNecessaryInterfaceRecords(m);
+        for (rr = m->ResourceRecords; rr; rr = rr->next)
+        {
+            if (rr->AutoTarget && AuthRecordIncludesOrIsAWDL(rr)) UpdateTargetHostName(m, rr);
+        }
+        for (rr = m->DuplicateRecords; rr; rr = rr->next)
+        {
+            if (rr->AutoTarget && AuthRecordIncludesOrIsAWDL(rr)) UpdateTargetHostName(m, rr);
+        }
+
+        mDNS_Unlock(m);
+    }
+}
+#endif
+
 mDNSlocal void UpdateInterfaceProtocols(mDNS *const m, NetworkInterfaceInfo *active)
 {
     NetworkInterfaceInfo *intf;
@@ -12960,7 +12952,7 @@ mDNSexport void mDNS_ActivateNetWake_internal(mDNS *const m, NetworkInterfaceInf
     if (set->InterfaceActive)
     {
         LogSPS("ActivateNetWake for %s (%#a)", set->ifname, &set->ip);
-        mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, mDNSNULL, set->InterfaceID, 0, mDNSfalse, mDNSfalse, m->SPSBrowseCallback, set);
+        mDNS_StartBrowse_internal(m, &set->NetWakeBrowse, &SleepProxyServiceType, &localdomain, set->InterfaceID, 0, mDNSfalse, mDNSfalse, m->SPSBrowseCallback, set);
     }
 }
 
@@ -13043,12 +13035,11 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
     set->next = mDNSNULL;
     *p = set;
 
-    if (set->Advertise)
-        AdvertiseInterface(m, set);
+    if (set->Advertise) AdvertiseInterfaceIfNeeded(m, set);
 
-    LogInfo("mDNS_RegisterInterface: InterfaceID %d %s (%#a) %s",
-            (uint32_t)set->InterfaceID, set->ifname, &set->ip,
-            set->InterfaceActive ?
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "mDNS_RegisterInterface: InterfaceID %u " PUB_S " (" PRI_IP_ADDR ") " PUB_S,
+            IIDPrintable(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");
 
@@ -13078,12 +13069,14 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                 LogMsg("mDNS_RegisterInterface: Using fast activation for DirectLink interface %s (%#a)", set->ifname, &set->ip);
                 break;
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
             case SlowActivation:
                 probedelay = mDNSPlatformOneSecond * 5;
                 numannounce = (mDNSu8)1;
                 LogMsg("mDNS_RegisterInterface: Frequent transitions for interface %s (%#a), doing slow activation", set->ifname, &set->ip);
                 m->mDNSStats.InterfaceUpFlap++;
                 break;
+#endif
 
             case NormalActivation:
             default:
@@ -13124,7 +13117,7 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
         // us to reconnect to the network. If we do this as part of the wake up code, it is possible
         // that the network link comes UP after 60 seconds and we never set the OWNER option
         m->AnnounceOwner = NonZeroTime(m->timenow + 60 * mDNSPlatformOneSecond);
-        LogInfo("mDNS_RegisterInterface: Setting AnnounceOwner");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "mDNS_RegisterInterface: Setting AnnounceOwner");
 
         m->mDNSStats.InterfaceUp++;
         for (q = m->Questions; q; q=q->next)                                // Scan our list of questions
@@ -13133,11 +13126,16 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
             {
                 if (!q->InterfaceID || q->InterfaceID == set->InterfaceID)      // If non-specific Q, or Q on this specific interface,
                 {                                                               // then reactivate this question
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
                     // If flapping, delay between first and second queries is nine seconds instead of one second
                     mDNSBool dodelay = (activationSpeed == SlowActivation) && (q->FlappingInterface1 == set->InterfaceID || q->FlappingInterface2 == set->InterfaceID);
                     mDNSs32 initial  = dodelay ? InitialQuestionInterval * QuestionIntervalStep2 : InitialQuestionInterval;
                     mDNSs32 qdelay   = dodelay ? kDefaultQueryDelayTimeForFlappingInterface : 0;
                     if (dodelay) LogInfo("No cache records expired for %##s (%s); delaying questions by %d seconds", q->qname.c, DNSTypeName(q->qtype), qdelay);
+#else
+                    mDNSs32 initial  = InitialQuestionInterval;
+                    mDNSs32 qdelay   = 0;
+#endif
 
                     if (!q->ThisQInterval || q->ThisQInterval > initial)
                     {
@@ -13146,8 +13144,6 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
                     }
                     q->LastQTime = m->timenow - q->ThisQInterval + qdelay;
                     q->RecentAnswerPkts = 0;
-                    // Change the salt
-                    ReInitAnonInfo(&q->AnonInfo, &q->qname);
                     SetNextQueryTime(m,q);
                 }
             }
@@ -13159,8 +13155,6 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
         {
             if (!rr->resrec.InterfaceID || rr->resrec.InterfaceID == set->InterfaceID)
             {
-                // Change the salt
-                ReInitAnonInfo(&rr->resrec.AnonInfo, rr->resrec.name);
                 mDNSCoreRestartRegistration(m, rr, numannounce);
             }
         }
@@ -13182,6 +13176,9 @@ mDNSexport mStatus mDNS_RegisterInterface(mDNS *const m, NetworkInterfaceInfo *s
 // 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, InterfaceActivationSpeed activationSpeed)
 {
+#if !MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
+    (void)activationSpeed;   // Unused parameter
+#endif
     NetworkInterfaceInfo **p = &m->HostInterfaces;
     mDNSBool revalidate = mDNSfalse;
     NetworkInterfaceInfo *primary;
@@ -13213,7 +13210,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
         if (intf)
         {
             LogInfo("mDNS_DeregisterInterface: Another representative of InterfaceID %d %s (%#a) exists;"
-                    " making it active", (uint32_t)set->InterfaceID, set->ifname, &set->ip);
+                    " making it active", IIDPrintable(set->InterfaceID), set->ifname, &set->ip);
             if (intf->InterfaceActive)
                 LogMsg("mDNS_DeregisterInterface: ERROR intf->InterfaceActive already set for %s (%#a)", set->ifname, &set->ip);
             intf->InterfaceActive = mDNStrue;
@@ -13236,15 +13233,17 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
             DNSQuestion *q;
 
             LogInfo("mDNS_DeregisterInterface: Last representative of InterfaceID %d %s (%#a) deregistered;"
-                    " marking questions etc. dormant", (uint32_t)set->InterfaceID, set->ifname, &set->ip);
+                    " marking questions etc. dormant", IIDPrintable(set->InterfaceID), set->ifname, &set->ip);
 
             m->mDNSStats.InterfaceDown++;
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
             if (set->McastTxRx && (activationSpeed == SlowActivation))
             {
                 LogMsg("mDNS_DeregisterInterface: Frequent transitions for interface %s (%#a)", set->ifname, &set->ip);
                 m->mDNSStats.InterfaceDownFlap++;
             }
+#endif
 
             // 1. Deactivate any questions specific to this interface, and tag appropriate questions
             // so that mDNS_RegisterInterface() knows how swiftly it needs to reactivate them
@@ -13267,6 +13266,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
             {
                 if (rr->resrec.InterfaceID == set->InterfaceID)
                 {
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
                     // If this interface is deemed flapping,
                     // postpone deleting the cache records in case the interface comes back again
                     if (set->McastTxRx && (activationSpeed == SlowActivation))
@@ -13279,6 +13279,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
                         rr->UnansweredQueries = MaxUnansweredQueries;
                     }
                     else
+#endif
                     {
                         rr->resrec.mortality = Mortality_Mortal;
                         mDNS_PurgeCacheResourceRecord(m, rr);
@@ -13298,7 +13299,7 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
             intf->RR_A.RRSet = A;
 
     // If we were advertising on this interface, deregister those address and reverse-lookup records now
-    if (set->Advertise) DeadvertiseInterface(m, set);
+    if (set->Advertise) DeadvertiseInterface(m, set, kDeadvertiseFlag_All);
 
     // If we have any cache records received on this interface that went away, then re-verify them.
     // In some versions of OS X the IPv6 address remains on an interface even when the interface is turned off,
@@ -13319,52 +13320,6 @@ mDNSexport void mDNS_DeregisterInterface(mDNS *const m, NetworkInterfaceInfo *se
     mDNS_Unlock(m);
 }
 
-mDNSlocal void SetAnonInfoSRS(ServiceRecordSet *sr, int NumSubTypes)
-{
-    int i, len;
-
-    if (!sr->AnonData)
-        return;
-
-    len = mDNSPlatformStrLen(sr->AnonData);
-    if (sr->RR_PTR.resrec.AnonInfo)
-    {
-        LogMsg("SetAnonInfoSRS: Freeing AnonInfo for PTR record %##s, should have been freed already", sr->RR_PTR.resrec.name->c);
-        FreeAnonInfo(sr->RR_PTR.resrec.AnonInfo);
-    }
-    sr->RR_PTR.resrec.AnonInfo = AllocateAnonInfo(sr->RR_PTR.resrec.name, sr->AnonData, len, mDNSNULL);
-    for (i=0; i<NumSubTypes; i++)
-    {
-        if (sr->SubTypes[i].resrec.AnonInfo)
-        {
-            LogMsg("SetAnonInfoSRS: Freeing AnonInfo for subtype record %##s, should have been freed already", sr->SubTypes[i].resrec.name->c);
-            FreeAnonInfo(sr->SubTypes[i].resrec.AnonInfo);
-        }
-        sr->SubTypes[i].resrec.AnonInfo = AllocateAnonInfo(sr->SubTypes[i].resrec.name, sr->AnonData, len, mDNSNULL);
-    }
-}
-
-mDNSlocal void ResetAnonInfoSRS(ServiceRecordSet *sr, int NumSubTypes)
-{
-    int i;
-
-    if (!sr->AnonData)
-        return;
-    if (sr->RR_PTR.resrec.AnonInfo)
-    {
-        FreeAnonInfo(sr->RR_PTR.resrec.AnonInfo);
-        sr->RR_PTR.resrec.AnonInfo = mDNSNULL;
-    }
-    for (i=0; i<NumSubTypes; i++)
-    {
-        if (sr->SubTypes[i].resrec.AnonInfo)
-        {
-            FreeAnonInfo(sr->SubTypes[i].resrec.AnonInfo);
-            sr->SubTypes[i].resrec.AnonInfo = mDNSNULL;
-        }
-    }
-}
-
 mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
 {
     ServiceRecordSet *sr = (ServiceRecordSet *)rr->RecordContext;
@@ -13410,7 +13365,6 @@ mDNSlocal void ServiceCallback(mDNS *const m, AuthRecord *const rr, mStatus resu
             if (e->r.resrec.RecordType != kDNSRecordTypeUnregistered) return;
             e = e->next;
         }
-        ResetAnonInfoSRS(sr, sr->NumSubTypes);
 
         // If this ServiceRecordSet was forcibly deregistered, and now its memory is ready for reuse,
         // then we can now report the NameConflict to the client
@@ -13455,18 +13409,6 @@ mDNSlocal AuthRecType setAuthRecType(mDNSInterfaceID InterfaceID, mDNSu32 flags)
     return artype;
 }
 
-// Used to derive the original D2D specific flags specified by the client in the registration
-// when we don't have access to the original flag (kDNSServiceFlags*) values.
-mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType)
-{
-    mDNSu32 flags = 0;
-    if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
-        flags |= kDNSServiceFlagsIncludeP2P;
-    else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
-        flags |= kDNSServiceFlagsIncludeAWDL;
-    return flags;
-}
-
 // 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.")
@@ -13484,7 +13426,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
 {
     mStatus err;
     mDNSu32 i;
-    mDNSu32 hostTTL;
     AuthRecType artype;
     mDNSu8 recordType = (flags & kDNSServiceFlagsKnownUnique) ? kDNSRecordTypeKnownUnique : kDNSRecordTypeUnique;
 
@@ -13509,12 +13450,7 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
         sr->RR_PTR.AuthFlags = AuthFlagsWakeOnly;
     }
 
-    if (SameDomainName(type, (const domainname *) "\x4" "_ubd" "\x4" "_tcp"))
-        hostTTL = kHostNameSmallTTL;
-    else
-        hostTTL = kHostNameTTL;
-
-    mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, hostTTL, recordType, artype, ServiceCallback, sr);
+    mDNS_SetupResourceRecord(&sr->RR_SRV, mDNSNULL, InterfaceID, kDNSType_SRV, kHostNameTTL, recordType, artype, ServiceCallback, sr);
     mDNS_SetupResourceRecord(&sr->RR_TXT, txtrdata, InterfaceID, kDNSType_TXT, kStandardTTL, recordType, artype, ServiceCallback, sr);
 
     // If port number is zero, that means the client is really trying to do a RegisterNoSuchService
@@ -13561,8 +13497,6 @@ mDNSexport mStatus mDNS_RegisterService(mDNS *const m, ServiceRecordSet *sr,
         sr->SubTypes[i].Additional2 = &sr->RR_TXT;
     }
 
-    SetAnonInfoSRS(sr, NumSubTypes);
-
     // 3. Set up the SRV record rdata.
     sr->RR_SRV.resrec.rdata->u.srv.priority = 0;
     sr->RR_SRV.resrec.rdata->u.srv.weight   = 0;
@@ -13724,6 +13658,9 @@ mDNSexport mStatus mDNS_RenameAndReregisterService(mDNS *const m, ServiceRecordS
         debugf("%##s service renamed from \"%#s\" to \"%#s\"", type.c, name1.c, newname->c);
     else debugf("%##s service (domain %##s) renamed from \"%#s\" to \"%#s\"",type.c, domain.c, name1.c, newname->c);
 
+    // If there's a pending TXT record update at this point, which can happen if a DNSServiceUpdateRecord() call was made
+    // after the TXT record's deregistration, execute it now, otherwise it will be lost during the service re-registration.
+    if (sr->RR_TXT.NewRData) CompleteRDataUpdate(m, &sr->RR_TXT);
     err = mDNS_RegisterService(m, sr, newname, &type, &domain,
                                host, sr->RR_SRV.resrec.rdata->u.srv.port,
                                (sr->RR_TXT.resrec.rdata != &sr->RR_TXT.rdatastorage) ? sr->RR_TXT.resrec.rdata : mDNSNULL,
@@ -13786,7 +13723,6 @@ mDNSexport mStatus mDNS_DeregisterService_drt(mDNS *const m, ServiceRecordSet *s
         // SRV, TXT, or Extra records could have already been automatically deregistered, and that's okay
         mDNS_Deregister_internal(m, &sr->RR_SRV, mDNS_Dereg_repeat);
         mDNS_Deregister_internal(m, &sr->RR_TXT, mDNS_Dereg_repeat);
-
         mDNS_Deregister_internal(m, &sr->RR_ADV, drt);
 
         // We deregister all of the extra records, but we leave the sr->Extras list intact
@@ -14051,10 +13987,10 @@ mDNSlocal void mDNSCoreReceiveRawND(mDNS *const m, const mDNSEthAddr *const sha,
                 static const char msg3[] = "Creating Local NDP Cache entry  ";
                 static const char msg4[] = "Answering NDP Request from      ";
                 static const char msg5[] = "Answering NDP Probe   from      ";
-                const char *const msg = sha && mDNSSameEthAddress(sha, &rr->WakeUp.IMAC) ? msg1 :
-                                        (rr->AnnounceCount == InitialAnnounceCount)      ? msg2 :
-                                        sha && mDNSSameEthAddress(sha, &intf->MAC)       ? msg3 :
-                                        spa && mDNSIPv6AddressIsZero(*spa)               ? msg4 : msg5;
+                const char *const msg = mDNSSameEthAddress(sha, &rr->WakeUp.IMAC)   ? msg1 :
+                                        (rr->AnnounceCount == InitialAnnounceCount) ? msg2 :
+                                        mDNSSameEthAddress(sha, &intf->MAC)         ? msg3 :
+                                        mDNSIPv6AddressIsZero(*spa)                 ? msg4 : msg5;
                 LogSPS("%-7s %s %.6a %.16a for %.16a -- H-MAC %.6a I-MAC %.6a %s",
                        intf->ifname, msg, sha, spa, &ndp->target, &rr->WakeUp.HMAC, &rr->WakeUp.IMAC, ARDisplayString(m, rr));
                 if (msg == msg1)
@@ -14322,7 +14258,7 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
         const mDNSu8 *const trans = p + 14 + (pkt->v4.vlen & 0xF) * 4;
         const mDNSu8 * transEnd = p + 14 + mDNSVal16(pkt->v4.totlen);
         if (transEnd > end) transEnd = end;
-        debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src, &pkt->v4.dst);
+        debugf("Got IPv4 %02X from %.4a to %.4a", pkt->v4.protocol, &pkt->v4.src.b, &pkt->v4.dst.b);
         src.type = mDNSAddrType_IPv4; src.ip.v4 = pkt->v4.src;
         dst.type = mDNSAddrType_IPv4; dst.ip.v4 = pkt->v4.dst;
         if (transEnd >= trans + RequiredCapLen(pkt->v4.protocol))
@@ -14332,7 +14268,7 @@ mDNSexport void mDNSCoreReceiveRawPacket(mDNS *const m, const mDNSu8 *const p, c
     else if (end >= p+54 && mDNSSameOpaque16(eth->ethertype, Ethertype_IPv6))
     {
         const mDNSu8 *const trans = p + 54;
-        debugf("Got IPv6  %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src, &pkt->v6.dst);
+        debugf("Got IPv6  %02X from %.16a to %.16a", pkt->v6.pro, &pkt->v6.src.b, &pkt->v6.dst.b);
         src.type = mDNSAddrType_IPv6; src.ip.v6 = pkt->v6.src;
         dst.type = mDNSAddrType_IPv6; dst.ip.v6 = pkt->v6.dst;
         if (end >= trans + RequiredCapLen(pkt->v6.pro))
@@ -14457,6 +14393,7 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
 
     if (!rrcachestorage) rrcachesize = 0;
 
+    m->next_request_id               = 1;
     m->p                             = p;
     m->NetworkChanged                = 0;
     m->CanReceiveUnicastOn5353       = mDNSfalse; // Assume we can't receive unicasts on 5353, unless platform layer tells us otherwise
@@ -14469,7 +14406,6 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
     m->MainCallback                  = Callback;
     m->MainContext                   = Context;
     m->rec.r.resrec.RecordType       = 0;
-    m->rec.r.resrec.AnonInfo         = mDNSNULL;
 
     // For debugging: To catch and report locking failures
     m->mDNS_busy               = 0;
@@ -14499,12 +14435,14 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
     m->NextScheduledStopTime   = timenow + FutureTime;
     m->NextBLEServiceTime      = 0;    // zero indicates inactive
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     m->NextBonjourDisableTime  = 0; // Timer active when non zero.
     m->BonjourEnabled          = 0; // Set when Bonjour on Demand is enabled and Bonjour is currently enabled.  
-#endif // BONJOUR_ON_DEMAND
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+    m->NextSuspiciousTimeout   = 0;
+#endif
 
-    m->DelayConflictProcessing = MAX_CONFLICT_PROCESSING_DELAYS;
     m->RandomQueryDelay        = 0;
     m->RandomReconfirmDelay    = 0;
     m->PktNum                  = 0;
@@ -14553,6 +14491,9 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
     m->hostlabel.c[0]          = 0;
     m->nicelabel.c[0]          = 0;
     m->MulticastHostname.c[0]  = 0;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    m->RandomizedHostname.c[0] = 0;
+#endif
     m->HIHardware.c[0]         = 0;
     m->HISoftware.c[0]         = 0;
     m->ResourceRecords         = mDNSNULL;
@@ -14581,14 +14522,13 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
     m->StaticHostname.c[0]      = 0;
     m->FQDN.c[0]                = 0;
     m->Hostnames                = mDNSNULL;
-    m->AutoTunnelNAT.clientContext = mDNSNULL;
 
     m->WABBrowseQueriesCount    = 0;
     m->WABLBrowseQueriesCount   = 0;
     m->WABRegQueriesCount       = 0;
     m->AutoTargetServices       = 0;
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     m->NumAllInterfaceRecords   = 0;
     m->NumAllInterfaceQuestions = 0;
 #endif
@@ -14634,17 +14574,12 @@ mDNSlocal mStatus mDNS_InitStorage(mDNS *const m, mDNS_PlatformSupport *const p,
     m->DNSPushZones             = mDNSNULL;
 #endif
 
-#if APPLE_OSX_mDNSResponder
-    m->TunnelClients            = mDNSNULL;
-
-#if !NO_WCF
-    CHECK_WCF_FUNCTION(WCFConnectionNew)
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+    if (WCFConnectionNew)
     {
         m->WCF = WCFConnectionNew();
         if (!m->WCF) { LogMsg("WCFConnectionNew failed"); return -1; }
     }
-#endif
-
 #endif
 
     return(result);
@@ -14657,7 +14592,11 @@ mDNSexport mStatus mDNS_Init(mDNS *const m, mDNS_PlatformSupport *const p,
     mStatus result = mDNS_InitStorage(m, p, rrcachestorage, rrcachesize, AdvertiseLocalAddresses, Callback, Context);
     if (result != mStatus_NoError)
         return(result);
-    
+
+#if MDNS_MALLOC_DEBUGGING
+    static mDNSListValidator lv;
+    mDNSPlatformAddListValidator(&lv, mDNS_ValidateLists, "mDNS_ValidateLists", m);
+#endif
     result = mDNSPlatformInit(m);
 
 #ifndef UNICAST_DISABLED
@@ -14702,7 +14641,7 @@ mDNSlocal void DynDNSHostNameCallback(mDNS *const m, AuthRecord *const rr, mStat
     mDNSPlatformDynDNSHostNameStatusChanged(rr->resrec.name, result);
 }
 
-mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const DNSServer * const ptr, mDNSBool lameduck)
+mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr)
 {
     mDNSBool purge = cr->resrec.RecordType == kDNSRecordTypePacketNegative ||
                      cr->resrec.rrtype     == kDNSType_A ||
@@ -14710,16 +14649,16 @@ mDNSlocal void PurgeOrReconfirmCacheRecord(mDNS *const m, CacheRecord *cr, const
                      cr->resrec.rrtype     == kDNSType_SRV ||
                      cr->resrec.rrtype     == kDNSType_CNAME;
 
-    (void) lameduck;
-    (void) ptr;
-    debugf("PurgeOrReconfirmCacheRecord: %s cache record due to %s server %p %#a:%d (%##s): %s",
+    debugf("PurgeOrReconfirmCacheRecord: %s cache record due to server %#a:%d (%##s): %s",
            purge    ? "purging"   : "reconfirming",
-           lameduck ? "lame duck" : "new",
-           ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, CRDisplayString(m, cr));
+           cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL,
+           cr->resrec.rDNSServer ? mDNSVal16(cr->resrec.rDNSServer->port) : -1,
+           cr->resrec.rDNSServer ? cr->resrec.rDNSServer->domain.c : mDNSNULL, CRDisplayString(m, cr));
 
     if (purge)
     {
         LogInfo("PurgeorReconfirmCacheRecord: Purging Resourcerecord %s, RecordType %x", CRDisplayString(m, cr), cr->resrec.RecordType);
+        cr->resrec.mortality = Mortality_Mortal;
         mDNS_PurgeCacheResourceRecord(m, cr);
     }
     else
@@ -14743,7 +14682,7 @@ mDNSlocal void mDNS_PurgeBeforeResolve(mDNS *const m, DNSQuestion *q)
     }
     for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
     {
-        if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+        if (SameNameCacheRecordAnswersQuestion(rp, q))
         {
             LogInfo("mDNS_PurgeBeforeResolve: Flushing %s", CRDisplayString(m, rp));
             mDNS_PurgeCacheResourceRecord(m, rp);
@@ -14771,7 +14710,7 @@ mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q)
 
     for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
     {
-        if (SameNameRecordAnswersQuestion(&rp->resrec, q))
+        if (SameNameCacheRecordAnswersQuestion(rp, q))
         {
             if (rp->resrec.RecordType != kDNSRecordTypePacketNegative || !rp->nsec)
             {
@@ -14785,29 +14724,6 @@ mDNSlocal void CheckForDNSSECRecords(mDNS *const m, DNSQuestion *q)
     }
 }
 
-// Check for a positive unicast response to the question but with qtype
-mDNSexport mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype)
-{
-    DNSQuestion question;
-    CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
-    CacheRecord *rp;
-
-    // Create an identical question but with qtype
-    mDNS_SetupQuestion(&question, q->InterfaceID, &q->qname, qtype, mDNSNULL, mDNSNULL);
-    question.qDNSServer = q->qDNSServer;
-
-    for (rp = cg ? cg->members : mDNSNULL; rp; rp = rp->next)
-    {
-        if (!rp->resrec.InterfaceID && rp->resrec.RecordType != kDNSRecordTypePacketNegative &&
-            SameNameRecordAnswersQuestion(&rp->resrec, &question))
-        {
-            LogInfo("mDNS_CheckForCacheRecord: Found %s", CRDisplayString(m, rp));
-            return mDNStrue;
-        }
-    }
-    return mDNSfalse;
-}
-
 mDNSexport void DNSServerChangeForQuestion(mDNS *const m, DNSQuestion *q, DNSServer *new)
 {
     DNSQuestion *qptr;
@@ -14837,10 +14753,9 @@ mDNSlocal void SetConfigState(mDNS *const m, mDNSBool delete)
         for (ptr = m->DNSServers; ptr; ptr = ptr->next)
         {
             ptr->penaltyTime = 0;
-            NumUnicastDNSServers--;
-            ptr->flags |= DNSServer_FlagDelete;
-#if APPLE_OSX_mDNSResponder
-            if (ptr->flags & DNSServer_FlagUnreachable)
+            ptr->flags |= DNSServerFlag_Delete;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+            if (ptr->flags & DNSServerFlag_Unreachable)
                 NumUnreachableDNSServers--;
 #endif
         }
@@ -14855,10 +14770,9 @@ mDNSlocal void SetConfigState(mDNS *const m, mDNSBool delete)
         for (ptr = m->DNSServers; ptr; ptr = ptr->next)
         {
             ptr->penaltyTime = 0;
-            NumUnicastDNSServers++;
-            ptr->flags &= ~DNSServer_FlagDelete;
-#if APPLE_OSX_mDNSResponder
-            if (ptr->flags & DNSServer_FlagUnreachable)
+            ptr->flags &= ~DNSServerFlag_Delete;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+            if (ptr->flags & DNSServerFlag_Unreachable)
                 NumUnreachableDNSServers++;
 #endif
         }
@@ -14884,19 +14798,23 @@ mDNSlocal void SetDynDNSHostNameIfChanged(mDNS *const m, domainname *const fqdn)
     }
 }
 
+// Even though this is called “Setup” it is not called just once at startup.
+// It’s actually called multiple times, every time there’s a configuration change.
 mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
 {
     mDNSu32 slot;
     CacheGroup *cg;
     CacheRecord *cr;
-    mDNSBool Restart = mDNSfalse;
     mDNSAddr v4, v6, r;
     domainname fqdn;
     DNSServer   *ptr, **p = &m->DNSServers;
     const DNSServer *oldServers = m->DNSServers;
     DNSQuestion *q;
     McastResolver *mr, **mres = &m->McastResolvers;
-
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+    DNSPushNotificationServer **psp;
+#endif
+    
     debugf("uDNS_SetupDNSConfig: entry");
 
     // Let the platform layer get the current DNS information and setup the WAB queries if needed.
@@ -14968,89 +14886,118 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
     //   cache records and as the resGroupID is different, you can't use the cache record from the scoped DNSServer to answer the
     //   non-scoped question and vice versa.
     //
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
     DNS64RestartQuestions(m);
 #endif
-    for (q = m->Questions; q; q=q->next)
+
+    // First, restart questions whose suppression status will change. The suppression status of each question in a given
+    // question set, i.e., a non-duplicate question and all of its duplicates, if any, may or may not change. For example,
+    // a suppressed (or non-suppressed) question that is currently a duplicate of a suppressed (or non-suppressed) question
+    // may become a non-suppressed (or suppressed) question, while the question that it's a duplicate of may remain
+    // suppressed (or non-suppressed).
+    for (q = m->Questions; q; q = q->next)
     {
-        if (!mDNSOpaque16IsZero(q->TargetQID))
-        {
-            DNSServer *s, *t;
-            DNSQuestion *qptr;
-            if (q->DuplicateOf) continue;
-            SetValidDNSServers(m, q);
-            q->triedAllServersOnce = 0;
-            s = GetServerForQuestion(m, q);
-            t = q->qDNSServer;
-            if (t != s)
-            {
-                mDNSBool old, new;
-                // If DNS Server for this question has changed, reactivate it
-                LogInfo("uDNS_SetupDNSConfig: Updating DNS Server from %#a:%d (%##s) to %#a:%d (%##s) for question %##s (%s) (scope:%p)",
-                        t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), t ? t->domain.c : (mDNSu8*)"",
-                        s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), s ? s->domain.c : (mDNSu8*)"",
-                        q->qname.c, DNSTypeName(q->qtype), q->InterfaceID);
-
-                old = q->SuppressQuery;
-                new = ShouldSuppressUnicastQuery(m, q, s);
-                if (old != new)
-                {
-                    // Changing the DNS server affected the SuppressQuery status. We need to
-                    // deliver RMVs for the previous ADDs (if any) before switching to the new
-                    // DNSServer.  To keep it simple, we walk all the questions and mark them
-                    // to be restarted and then handle all of them at once.
-                    q->Restart = 1;
-                    q->SuppressQuery = new;
-                    for (qptr = q->next ; qptr; qptr = qptr->next)
-                    {
-                        if (qptr->DuplicateOf == q)
-                            qptr->Restart = 1;
-                    }
-                    Restart = mDNStrue;
-                }
-                else
-                {
-                    DNSServerChangeForQuestion(m, q, s);
-                    q->unansweredQueries = 0;
+        DNSServer *s;
+        const DNSServer *t;
+        mDNSBool oldSuppressed;
 
-                    // If we had sent a query out to DNSServer "t" and we are changing to "s", we
-                    // need to ignore the responses coming back from "t" as the DNS configuration
-                    // has changed e.g., when a new interface is coming up and that becomes the primary
-                    // interface, we switch to the DNS servers configured for the primary interface. In
-                    // this case, we should not accept responses associated with the previous interface as
-                    // the "name" could resolve differently on this new primary interface. Hence, discard
-                    // in-flight responses.
-                    q->TargetQID = mDNS_NewMessageID(m);
+        if (mDNSOpaque16IsZero(q->TargetQID)) continue;
 
-                    if (!QuerySuppressed(q))
-                    {
-                        debugf("uDNS_SetupDNSConfig: Activating query %p %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
-                        ActivateUnicastQuery(m, q, mDNStrue);
-                        // ActivateUnicastQuery is called for duplicate questions also as it does something
-                        // special for AutoTunnel questions
-                        for (qptr = q->next ; qptr; qptr = qptr->next)
-                        {
-                            if (qptr->DuplicateOf == q) ActivateUnicastQuery(m, qptr, mDNStrue);
-                        }
-                    }
+        SetValidDNSServers(m, q);
+        q->triedAllServersOnce = mDNSfalse;
+        s = GetServerForQuestion(m, q);
+        t = q->qDNSServer;
+        if (s != t)
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                "[R%u->Q%u] uDNS_SetupDNSConfig: Updating DNS server from " PRI_IP_ADDR ":%d (" PRI_DM_NAME ") to "
+                PRI_IP_ADDR ":%d (" PRI_DM_NAME ") for question " PRI_DM_NAME " (" PUB_S ") (scope:%p)",
+                q->request_id, mDNSVal16(q->TargetQID),
+                t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), DM_NAME_PARAM(t ? t->domain.c : (mDNSu8*)""),
+                s ? &s->addr : mDNSNULL, mDNSVal16(s ? s->port : zeroIPPort), DM_NAME_PARAM(s ? s->domain.c : (mDNSu8*)""),
+                DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), q->InterfaceID);
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+            // If this question had a DNS Push server associated with it, substitute the new server for the
+            // old one.   If there is no new server, then we'll clean up the push server later.
+            if (!q->DuplicateOf && (q->dnsPushServer != mDNSNULL))
+            {
+                if (q->dnsPushServer->qDNSServer == t)
+                {
+                    q->dnsPushServer->qDNSServer = s; // which might be null
+                }
+                // If it is null, do the accounting and drop the push server.
+                if (q->dnsPushServer->qDNSServer == mDNSNULL)
+                {
+                    DNSPushReconcileConnection(m, q);
                 }
             }
-            else
+#endif
+        }
+        oldSuppressed = q->Suppressed;
+        q->Suppressed = ShouldSuppressUnicastQuery(q, s);
+        if (!q->Suppressed != !oldSuppressed) q->Restart = mDNStrue;
+    }
+    RestartUnicastQuestions(m);
+
+    // Now, change the server for each question set, if necessary. Note that questions whose suppression status changed
+    // have already had their server changed by being restarted.
+    for (q = m->Questions; q; q = q->next)
+    {
+        DNSServer *s;
+        const DNSServer *t;
+
+        if (mDNSOpaque16IsZero(q->TargetQID) || q->DuplicateOf) continue;
+
+        SetValidDNSServers(m, q);
+        q->triedAllServersOnce = mDNSfalse;
+        s = GetServerForQuestion(m, q);
+        t = q->qDNSServer;
+        DNSServerChangeForQuestion(m, q, s);
+        if (s == t) continue;
+
+        q->Suppressed = ShouldSuppressUnicastQuery(q, s);
+        q->unansweredQueries = 0;
+        q->TargetQID = mDNS_NewMessageID(m);
+        if (!q->Suppressed) ActivateUnicastQuery(m, q, mDNStrue);
+    }
+
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+    // The above code may have found some DNS Push servers that are no longer valid.   Now that we
+    // are done running through the code, we need to drop our connections to those servers.
+    // When we get here, any such servers should have zero questions associated with them.
+    for (psp = &m->DNSPushServers; *psp != mDNSNULL; )
+    {
+        DNSPushNotificationServer *server = *psp;
+
+        // It's possible that a push server whose DNS server has been deleted could be still connected but
+        // not referenced by any questions.  In this case, we just delete the push server rather than trying
+        // to figure out with which DNS server (if any) to associate it.
+        if (server->qDNSServer != mDNSNULL && server->qDNSServer->flags & DNSServerFlag_Delete)
+        {
+            server->qDNSServer = mDNSNULL;
+        }
+
+        if (server->qDNSServer == mDNSNULL)
+        {
+            // This would be a programming error, so should never happen.
+            if (server->numberOfQuestions != 0)
             {
-                debugf("uDNS_SetupDNSConfig: Not Updating DNS server question %p %##s (%s) DNS server %#a:%d %p %d",
-                       q, q->qname.c, DNSTypeName(q->qtype), t ? &t->addr : mDNSNULL, mDNSVal16(t ? t->port : zeroIPPort), q->DuplicateOf, q->SuppressUnusable);
-                for (qptr = q->next ; qptr; qptr = qptr->next)
-                    if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
+                LogInfo("uDNS_SetupDNSConfig: deleting push server %##s that has questions.", &server->serverName);
             }
+            DNSPushServerDrop(server);
+            *psp = server->next;
+            mDNSPlatformMemFree(server);
+        }
+        else
+        {
+            psp = &(*psp)->next;
         }
     }
-    if (Restart)
-        RestartUnicastQuestions(m);
+#endif
 
     FORALL_CACHERECORDS(slot, cg, cr)
     {
-        if (cr->resrec.InterfaceID)
-            continue;
+        if (cr->resrec.InterfaceID) continue;
 
         // We already walked the questions and restarted/reactivated them if the dns server
         // change affected the question. That should take care of updating the cache. But
@@ -15063,111 +15010,88 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
         // the questions if they were suppressed (see above). To keep it simple, we walk
         // all the cache entries to make sure that there are no stale entries. We use the
         // active question's InterfaceID/ServiceID for looking up the right DNS server.
-        // Note that the unscoped value for ServiceID is -1.
         //
         // Note: If GetServerForName returns NULL, it could either mean that there are no
         // DNS servers or no matching DNS servers for this question. In either case,
         // the cache should get purged below when we process deleted DNS servers.
+        //
+        // If it is a DNSSEC question, purge the cache as the DNSSEC capabilities of the
+        // DNS server may have changed.
 
-        ptr = GetServerForName(m, cr->resrec.name,
-                               (cr->CRActiveQuestion ? cr->CRActiveQuestion->InterfaceID : mDNSNULL),
-                               (cr->CRActiveQuestion ? cr->CRActiveQuestion->ServiceID   : -1));
-
-        // Purge or Reconfirm if this cache entry would use the new DNS server
-        if (ptr && (ptr != cr->resrec.rDNSServer))
+        if (cr->CRActiveQuestion && !DNSSECQuestion(cr->CRActiveQuestion))
         {
-            // As the DNSServers for this cache record is not the same anymore, we don't
-            // want any new questions to pick this old value. If there is no active question,
-            // we can't possibly re-confirm, so purge in that case. If it is a DNSSEC question,
-            // purge the cache as the DNSSEC capabilities of the DNS server may have changed.
-
-            if (cr->CRActiveQuestion == mDNSNULL || DNSSECQuestion(cr->CRActiveQuestion))
+            // Purge or Reconfirm if this cache entry would use the new DNS server
+            ptr = GetServerForName(m, cr->resrec.name, cr->CRActiveQuestion->InterfaceID, cr->CRActiveQuestion->ServiceID);
+            if (ptr && (ptr != cr->resrec.rDNSServer))
             {
-                LogInfo("uDNS_SetupDNSConfig: Purging Resourcerecord %s, New DNS server %#a , Old DNS server %#a", CRDisplayString(m, cr),
-                        &ptr->addr, (cr->resrec.rDNSServer != mDNSNULL ?  &cr->resrec.rDNSServer->addr : mDNSNULL));
-                cr->resrec.mortality = Mortality_Mortal;
-                mDNS_PurgeCacheResourceRecord(m, cr);
+                LogInfo("uDNS_SetupDNSConfig: Purging/Reconfirming Resourcerecord %s, New DNS server %#a, Old DNS server %#a",
+                        CRDisplayString(m, cr), &ptr->addr,
+                        cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL);
+                PurgeOrReconfirmCacheRecord(m, cr);
+                
+                // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration
+                // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events.
+                if (!cr->resrec.rDNSServer && cr->CRActiveQuestion->qDNSServer)
+                {
+                    LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->CRActiveQuestion->qDNSServer->addr, CRDisplayString(m, cr));
+                    cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer;
+                }
             }
-            else
+            
+            if (cr->resrec.rDNSServer && cr->resrec.rDNSServer->flags & DNSServerFlag_Delete)
             {
-                LogInfo("uDNS_SetupDNSConfig: Purging/Reconfirming Resourcerecord %s, New DNS server %#a, Old DNS server %#a", CRDisplayString(m, cr),
-                        &ptr->addr, (cr->resrec.rDNSServer != mDNSNULL ?  &cr->resrec.rDNSServer->addr : mDNSNULL));
-                PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNSfalse);
+                DNSQuestion *qptr = cr->CRActiveQuestion;
+                if (qptr->qDNSServer == cr->resrec.rDNSServer)
+                {
+                    LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s  Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a"
+                           " to be freed", CRDisplayString(m, cr),
+                           qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID,
+                           &cr->resrec.rDNSServer->addr);
+                    qptr->validDNSServers = zeroOpaque128;
+                    qptr->qDNSServer = mDNSNULL;
+                    cr->resrec.rDNSServer = mDNSNULL;
+                }
+                else
+                {
+                    LogInfo("uDNS_SetupDNSConfig: Cache Record %s,  Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted),"
+                            " resetting to  question's DNSServer Address %#a", CRDisplayString(m, cr),
+                            qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID,
+                            &cr->resrec.rDNSServer->addr,
+                            qptr->qDNSServer ? &qptr->qDNSServer->addr : mDNSNULL);
+                    cr->resrec.rDNSServer = qptr->qDNSServer;
+                }
+                PurgeOrReconfirmCacheRecord(m, cr);
             }
         }
-
-        // If a cache record's DNSServer pointer is NULL, but its active question got a DNSServer in this DNS configuration
-        // update, then use its DNSServer. This way, the active question and its duplicates don't miss out on RMV events.
-        if (!cr->resrec.rDNSServer && cr->CRActiveQuestion && cr->CRActiveQuestion->qDNSServer)
+        else if (!cr->resrec.rDNSServer || cr->resrec.rDNSServer->flags & DNSServerFlag_Delete)
         {
-            cr->resrec.rDNSServer = cr->CRActiveQuestion->qDNSServer;
-            LogInfo("uDNS_SetupDNSConfig: Using active question's DNS server %#a for cache record %s", &cr->resrec.rDNSServer->addr, CRDisplayString(m, cr));
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+                "uDNS_SetupDNSConfig: Purging Resourcerecord " PRI_S ", DNS server " PUB_S " " PRI_IP_ADDR " " PUB_S,
+                CRDisplayString(m, cr), !cr->resrec.rDNSServer ? "(to be deleted)" : "",
+                cr->resrec.rDNSServer ? &cr->resrec.rDNSServer->addr : mDNSNULL,
+                cr->resrec.rDNSServer ? DNSScopeToString(cr->resrec.rDNSServer->scopeType) : "" );
+            cr->resrec.rDNSServer = mDNSNULL;
+            cr->resrec.mortality = Mortality_Mortal;
+            mDNS_PurgeCacheResourceRecord(m, cr);
         }
     }
 
+    //  Delete all the DNS servers that are flagged for deletion
     while (*p)
     {
-        if (((*p)->flags & DNSServer_FlagDelete) != 0)
+        if (((*p)->flags & DNSServerFlag_Delete) != 0)
         {
-            // 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;
-            FORALL_CACHERECORDS(slot, cg, cr)
-            {
-                if (cr->resrec.InterfaceID) continue;
-                if (cr->resrec.rDNSServer == ptr)
-                {
-                    // If we don't have an active question for this cache record, neither Purge can
-                    // generate RMV events nor Reconfirm can send queries out. Just set the DNSServer
-                    // pointer on the record NULL so that we don't point to freed memory (We might dereference
-                    // DNSServer pointers from resource record for logging purposes).
-                    //
-                    // If there is an active question, point to its DNSServer as long as it does not point to the
-                    // freed one. We already went through the questions above and made them point at either the
-                    // new server or NULL if there is no server.
-
-                    if (cr->CRActiveQuestion)
-                    {
-                        DNSQuestion *qptr = cr->CRActiveQuestion;
-
-                        if (qptr->qDNSServer == ptr)
-                        {
-                            LogMsg("uDNS_SetupDNSConfig: ERROR!! Cache Record %s  Active question %##s (%s) (scope:%p) pointing to DNSServer Address %#a"
-                                   " to be freed", CRDisplayString(m, cr),  qptr->qname.c, DNSTypeName(qptr->qtype), qptr->InterfaceID, &ptr->addr);
-                            qptr->validDNSServers = zeroOpaque128;
-                            qptr->qDNSServer = mDNSNULL;
-                            cr->resrec.rDNSServer = mDNSNULL;
-                        }
-                        else
-                        {
-                            LogInfo("uDNS_SetupDNSConfig: Cache Record %s,  Active question %##s (%s) (scope:%p), pointing to DNSServer %#a (to be deleted),"
-                                    " resetting to  question's DNSServer Address %#a", CRDisplayString(m, cr),  qptr->qname.c, DNSTypeName(qptr->qtype),
-                                    qptr->InterfaceID, &ptr->addr, (qptr->qDNSServer) ? &qptr->qDNSServer->addr : mDNSNULL);
-                            cr->resrec.rDNSServer = qptr->qDNSServer;
-                        }
-                    }
-                    else
-                    {
-                        LogInfo("uDNS_SetupDNSConfig: Cache Record %##s has no Active question, Record's DNSServer Address %#a, Server to be deleted %#a",
-                                cr->resrec.name, &cr->resrec.rDNSServer->addr, &ptr->addr);
-                        cr->resrec.rDNSServer = mDNSNULL;
-                    }
-
-                    cr->resrec.mortality = Mortality_Mortal;
-                    PurgeOrReconfirmCacheRecord(m, cr, ptr, mDNStrue);
-                }
-            }
             *p = (*p)->next;
-            LogInfo("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s) %d", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c, NumUnicastDNSServers);
+            LogInfo("uDNS_SetupDNSConfig: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
             mDNSPlatformMemFree(ptr);
         }
         else
         {
-            (*p)->flags &= ~DNSServer_FlagNew;
             p = &(*p)->next;
         }
     }
+    LogInfo("uDNS_SetupDNSConfig: CountOfUnicastDNSServers %d", CountOfUnicastDNSServers(m));
 
     // If we now have no DNS servers at all and we used to have some, 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.
@@ -15212,7 +15136,7 @@ mDNSexport mStatus uDNS_SetupDNSConfig(mDNS *const m)
         if (m->FQDN.c[0]) mDNSPlatformDynDNSHostNameStatusChanged(&m->FQDN, 1); // Set status to 1 to indicate temporary failure
     }
 
-    debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", NumUnicastDNSServers);
+    debugf("uDNS_SetupDNSConfig: number of unicast DNS servers %d", CountOfUnicastDNSServers(m));
     return mStatus_NoError;
 }
 
@@ -15263,14 +15187,12 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
 
     mDNSCoreBeSleepProxyServer_internal(m, 0, 0, 0, 0, 0);
 
-#if APPLE_OSX_mDNSResponder
-#if !NO_WCF
-    CHECK_WCF_FUNCTION(WCFConnectionDealloc)
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+    if (WCFConnectionDealloc)
     {
-        if (m->WCF) WCFConnectionDealloc((WCFConnection *)m->WCF);
+        if (m->WCF) WCFConnectionDealloc(m->WCF);
     }
 #endif
-#endif
 
 #ifndef UNICAST_DISABLED
     {
@@ -15293,7 +15215,7 @@ mDNSexport void mDNS_StartExit(mDNS *const m)
     }
 #endif
 
-    DeadvertiseAllInterfaceRecords(m);
+    DeadvertiseAllInterfaceRecords(m, kDeadvertiseFlag_All);
 
     // Shut down all our active NAT Traversals
     while (m->NATTraversals)
index 14b03c9e49ae41dd14e0449ec697bc665b6e79bc..be0a4c1e4268c4551d05df9b7cd9aef9627cc473 100755 (executable)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
 #ifndef __mDNSDebug_h
 #define __mDNSDebug_h
 
+#include "mDNSFeatures.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+#include <os/log.h>
+#endif
+
 // Set MDNS_DEBUGMSGS to 0 to optimize debugf() calls out of the compiled code
 // Set MDNS_DEBUGMSGS to 1 to generate normal debugging messages
 // Set MDNS_DEBUGMSGS to 2 to generate verbose debugging messages
 //    warning: double format, pointer arg (arg 2)       (for %.4a, %.16a, %#a -- IP address formats)
 #define MDNS_CHECK_PRINTF_STYLE_FUNCTIONS 0
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+typedef os_log_t mDNSLogCategory_t;
+
+typedef os_log_type_t mDNSLogLevel_t;
+#define MDNS_LOG_FAULT      OS_LOG_TYPE_FAULT
+#define MDNS_LOG_ERROR      OS_LOG_TYPE_ERROR
+#define MDNS_LOG_WARNING    OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_DEFAULT    OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_INFO       OS_LOG_TYPE_DEFAULT
+#define MDNS_LOG_DEBUG      OS_LOG_TYPE_DEBUG
+#else
+typedef const char * mDNSLogCategory_t;
 typedef enum
 {
-    MDNS_LOG_MSG,
-    MDNS_LOG_OPERATION,
-    MDNS_LOG_SPS,
-    MDNS_LOG_INFO,
-    MDNS_LOG_DEBUG,
+    MDNS_LOG_FAULT   = 1,
+    MDNS_LOG_ERROR   = 2,
+    MDNS_LOG_WARNING = 3,
+    MDNS_LOG_DEFAULT = 4,
+    MDNS_LOG_INFO    = 5,
+    MDNS_LOG_DEBUG   = 6
 } mDNSLogLevel_t;
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+    extern os_log_t mDNSLogCategory_Default;
+    extern os_log_t mDNSLogCategory_mDNS;
+    extern os_log_t mDNSLogCategory_uDNS;
+    extern os_log_t mDNSLogCategory_SPS;
+    extern os_log_t mDNSLogCategory_XPC;
+
+    #define MDNS_LOG_CATEGORY_DEFINITION(NAME)  mDNSLogCategory_ ## NAME
+#else
+    #define MDNS_LOG_CATEGORY_DEFINITION(NAME)  # NAME
+#endif
+
+#define MDNS_LOG_CATEGORY_DEFAULT   MDNS_LOG_CATEGORY_DEFINITION(Default)
+#define MDNS_LOG_CATEGORY_MDNS      MDNS_LOG_CATEGORY_DEFINITION(mDNS)
+#define MDNS_LOG_CATEGORY_UDNS      MDNS_LOG_CATEGORY_DEFINITION(uDNS)
+#define MDNS_LOG_CATEGORY_SPS       MDNS_LOG_CATEGORY_DEFINITION(SPS)
+#define MDNS_LOG_CATEGORY_XPC       MDNS_LOG_CATEGORY_DEFINITION(XPC)
 
-// Set this symbol to 1 to answer remote queries for our Address, reverse mapping PTR, and HINFO records
+// Set this symbol to 1 to answer remote queries for our Address, and reverse mapping PTR
 #define ANSWER_REMOTE_HOSTNAME_QUERIES 0
 
 // Set this symbol to 1 to do extra debug checks on malloc() and free()
 // Set this symbol to 2 to write a log message for every malloc() and free()
-//#define MACOSX_MDNS_MALLOC_DEBUGGING 1
+// #define MDNS_MALLOC_DEBUGGING 1
+
+#if (MDNS_MALLOC_DEBUGGING > 0) && defined(WIN32)
+#error "Malloc debugging does not yet work on Windows"
+#endif
 
 //#define ForceAlerts 1
 //#define LogTimeStamps 1
@@ -94,21 +135,27 @@ extern "C" {
 
 #if (MDNS_HAS_VA_ARG_MACROS)
     #if (MDNS_C99_VA_ARGS)
-        #define debug_noop(... ) ((void)0)
-        #define LogMsg(... )           LogMsgWithLevel(MDNS_LOG_MSG, __VA_ARGS__)
-        #define LogOperation(... )     do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, __VA_ARGS__);} while (0)
-        #define LogSPS(... )           do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS,       __VA_ARGS__);} while (0)
-        #define LogInfo(... )          do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO,      __VA_ARGS__);} while (0)
-        #define LogDebug(... )         do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG,     __VA_ARGS__);} while (0)
+        #define MDNS_LOG_DEFINITION(LEVEL, ...) \
+            do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, LEVEL, __VA_ARGS__); } while (0)
+
+        #define debug_noop(...)   do {} while(0)
+        #define LogMsg(...)       LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, __VA_ARGS__)
+        #define LogOperation(...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO,  __VA_ARGS__)
+        #define LogSPS(...)       MDNS_LOG_DEFINITION(MDNS_LOG_INFO,  __VA_ARGS__)
+        #define LogInfo(...)      MDNS_LOG_DEFINITION(MDNS_LOG_INFO,  __VA_ARGS__)
+        #define LogDebug(...)     MDNS_LOG_DEFINITION(MDNS_LOG_DEBUG, __VA_ARGS__)
     #elif (MDNS_GNU_VA_ARGS)
-        #define debug_noop( ARGS... ) ((void)0)
-        #define LogMsg( ARGS... )       LogMsgWithLevel(MDNS_LOG_MSG, ARGS)
-        #define LogOperation( ARGS... ) do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_OPERATION, ARGS);} while (0)
-        #define LogSPS( ARGS... )       do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_SPS,       ARGS);} while (0)
-        #define LogInfo( ARGS... )      do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_INFO,      ARGS);} while (0)
-        #define LogDebug( ARGS... )     do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_DEBUG,     ARGS);} while (0)
+        #define MDNS_LOG_DEFINITION(LEVEL, ARGS...) \
+            do { if (mDNS_LoggingEnabled) LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, LEVEL, ARGS); } while (0)
+
+        #define debug_noop(ARGS...)   do {} while (0)
+        #define LogMsg(ARGS... )      LogMsgWithLevel(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, ARGS)
+        #define LogOperation(ARGS...) MDNS_LOG_DEFINITION(MDNS_LOG_INFO,  ARGS)
+        #define LogSPS(ARGS...)       MDNS_LOG_DEFINITION(MDNS_LOG_INFO,  ARGS)
+        #define LogInfo(ARGS...)      MDNS_LOG_DEFINITION(MDNS_LOG_INFO,  ARGS)
+        #define LogDebug(ARGS...)     MDNS_LOG_DEFINITION(MDNS_LOG_DEBUG, ARGS)
     #else
-        #error Unknown variadic macros
+        #error "Unknown variadic macros"
     #endif
 #else
 // If your platform does not support variadic macros, you need to define the following variadic functions.
@@ -126,6 +173,7 @@ extern void LogInfo_(const char *format, ...)      IS_A_PRINTF_STYLE_FUNCTION(1,
 extern void LogDebug_(const char *format, ...)     IS_A_PRINTF_STYLE_FUNCTION(1,2);
 #endif
 
+
 #if MDNS_DEBUGMSGS
 #define debugf debugf_
 extern void debugf_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
@@ -147,7 +195,7 @@ extern int mDNS_McastTracingEnabled;
 extern int mDNS_DebugMode;          // If non-zero, LogMsg() writes to stderr instead of syslog
 extern const char ProgramName[];
 
-extern void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(2,3);
+extern void LogMsgWithLevel(mDNSLogCategory_t category, mDNSLogLevel_t level, const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
 // LogMsgNoIdent needs to be fixed so that it logs without the ident prefix like it used to
 // (or completely overhauled to use the new "log to a separate file" facility)
 #define LogMsgNoIdent LogMsg
@@ -158,20 +206,146 @@ extern void LogFatalError(const char *format, ...);
 #define LogFatalError LogMsg
 #endif
 
-#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 uds_validatelists(void);
-extern void udns_validatelists(void *const v);
+#if MDNS_MALLOC_DEBUGGING >= 1
+extern void *mallocL(const char *msg, mDNSu32 size);
+extern void *callocL(const char *msg, mDNSu32 size);
+extern void freeL(const char *msg, void *x);
+#if APPLE_OSX_mDNSResponder
 extern void LogMemCorruption(const char *format, ...);
 #else
-#define mallocL(X,Y) malloc(Y)
-#define callocL(X,Y) calloc(1, Y)
-#define freeL(X,Y) free(Y)
+#define LogMemCorruption LogMsg
+#endif
+#else
+#define mallocL(MSG, SIZE) malloc(SIZE)
+#define callocL(MSG, SIZE) calloc(1, SIZE)
+#define freeL(MSG, PTR) free(PTR)
 #endif
 
 #ifdef __cplusplus
 }
 #endif
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+/** @brief Write a log message to system's log storage(memory or disk).
+ *
+ *  On Apple platform, os_log() will be called to log a message.
+ *
+ *  @param CATEGORY         A custom log object previously created by the os_log_create function, and such an object is
+ *                          used to specify "subsystem" and "category". For mDNSResponder, the subsystem should always
+ *                          be set to "com.apple.mDNSResponder"; and the category is used for categorization and
+ *                          filtering of related log messages within the subsystem’s settings. We have 4 categories that
+ *                          are pre-defined: MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_CATEGORY_MDNS, MDNS_LOG_CATEGORY_UDNS,
+ *                          MDNS_LOG_CATEGORY_SPS. If these categories are not enough, use os_log_create to create more.
+ *
+ *  @param LEVEL            The log level that determines the importance of the message. The levels are, in order of
+ *                          decreasing importance:
+ *                              MDNS_LOG_FAULT      Fault-level messages are intended for capturing system-level errors
+ *                                                  that are critical to the system. They are always saved in the data store.
+ *                              MDNS_LOG_ERROR      Error-level messages are intended for reporting process-level errors
+ *                                                  that are unexpected and incorrect during the normal operation. They
+ *                                                  are always saved in the data store.
+ *                              MDNS_LOG_WARNING    Warning-level messages are intended for capturing unexpected and
+ *                                                  possible incorrect behavior that might be used later to root cause
+ *                                                  an error or fault. They are are initially stored in memory buffers
+ *                                                  and then moved to a data store.
+ *                              MDNS_LOG_DEFAULT    Default-level messages are intended for reporting things that might
+ *                                                  result a failure. They are are initially stored in memory buffers
+ *                                                  and then moved to a data store.
+ *                              MDNS_LOG_INFO       Info-level messages are intended for capturing information that may
+ *                                                  be helpful, but isn’t essential, for troubleshooting errors. They
+ *                                                  are initially stored in memory buffers, but will only be moved into
+ *                                                  data store when faults and, optionally, errors occur.
+ *                              MDNS_LOG_DEBUG      Debug-level messages are intended for information that may be useful
+ *                                                  during development or while troubleshooting a specific problem, Debug
+ *                                                  logging should not be used in shipping software. They are only
+ *                                                  captured in memory when debug logging is enabled through a
+ *                                                  configuration change.
+ *
+ *  @param FORMAT           A constant string or format string that produces a human-readable log message. The format
+ *                          string follows the IEEE printf specification, besides the following customized format specifiers:
+ *                              %{mdnsresponder:domain_name}.*P     the pointer to a DNS lable sequence
+ *                              %{mdnsresponder:ip_addr}.20P        the pointer to a mDNSAddr variable
+ *                              %{network:in_addr}.4P               the pointer to a mDNSv4Addr variable
+ *                              %{network:in6_addr}.16P             the pointer to a mDNSv6Addr variable
+ *                              %{mdnsresponder:mac_addr}.6P        the pointer to a 6-byte-length MAC address
+ *
+ *  @param ...              The parameter list that will be formated by the format string. Note that if the customized
+ *                          format specifiers are used and the data length is not specified in the format string, the
+ *                          size should be listed before the pointer to the data, for example:
+ *                              "%{mdnsresponder:domain_name}.*P", (name ? (int)DomainNameLength((const domainname *)name) : 0), <the pointer to a DNS label sequence>
+ *
+ */
+    #define LogRedact(CATEGORY, LEVEL, FORMAT, ...) os_log_with_type(CATEGORY, LEVEL, FORMAT, ## __VA_ARGS__)
+#else
+    #if (MDNS_HAS_VA_ARG_MACROS)
+        #if (MDNS_C99_VA_ARGS)
+            #define LogRedact(CATEGORY, LEVEL, ...) \
+                do { if (mDNS_LoggingEnabled) LogMsgWithLevel(CATEGORY, LEVEL, __VA_ARGS__); } while (0)
+        #elif (MDNS_GNU_VA_ARGS)
+            #define LogRedact(CATEGORY, LEVEL, ARGS...) \
+                do { if (mDNS_LoggingEnabled) LogMsgWithLevel(CATEGORY, LEVEL, ARGS); } while (0)
+        #else
+            #error "Unknown variadic macros"
+        #endif
+    #else
+        #define LogRedact      (mDNS_LoggingEnabled == 0) ? ((void)0) : LogRedact_
+        extern void LogRedact_(const char *format, ...) IS_A_PRINTF_STYLE_FUNCTION(1,2);
+    #endif
+#endif // MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+
+// The followings are the customized log specifier defined in os_log. For compatibility, we have to define it when it is
+// not on the Apple platform, for example, the Posix platform. The keyword "public" or "private" is used to control whether
+// the content would be redacted when the redaction is turned on: "public" means the content will always be printed;
+// "private" means the content will be printed as <private> if the redaction is turned on, only when the redaction is
+// turned off, the content will be printed as what it should be.
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+    #define PUB_S "%{public}s"
+    #define PRI_S "%{private}s"
+#else
+    #define PUB_S "%s"
+    #define PRI_S PUB_S
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+    #define PUB_DM_NAME "%{public, mdnsresponder:domain_name}.*P"
+    #define PRI_DM_NAME "%{private, mdnsresponder:domain_name}.*P"
+    // When DM_NAME_PARAM is used, the file where the function is defined must include DNSEmbeddedAPI.h
+    #define DM_NAME_PARAM(name) ((name) ? ((int)DomainNameLength((const domainname *)(name))) : 0), (name)
+#else
+    #define PUB_DM_NAME "%##s"
+    #define PRI_DM_NAME PUB_DM_NAME
+    #define DM_NAME_PARAM(name) (name)
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+    #define PUB_IP_ADDR "%{public, mdnsresponder:ip_addr}.20P"
+    #define PRI_IP_ADDR "%{private, mdnsresponder:ip_addr}.20P"
+
+    #define PUB_IPv4_ADDR "%{public, network:in_addr}.4P"
+    #define PRI_IPv4_ADDR "%{private, network:in_addr}.4P"
+
+    #define PUB_IPv6_ADDR "%{public, network:in6_addr}.16P"
+    #define PRI_IPv6_ADDR "%{private, network:in6_addr}.16P"
+#else
+    #define PUB_IP_ADDR "%#a"
+    #define PRI_IP_ADDR PUB_IP_ADDR
+
+    #define PUB_IPv4_ADDR "%.4a"
+    #define PRI_IPv4_ADDR PUB_IPv4_ADDR
+
+    #define PUB_IPv6_ADDR "%.16a"
+    #define PRI_IPv6_ADDR PUB_IPv6_ADDR
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+    #define PUB_MAC_ADDR "%{public, mdnsresponder:mac_addr}.6P"
+    #define PRI_MAC_ADDR "%{private, mdnsresponder:mac_addr}.6P"
+#else
+    #define PUB_MAC_ADDR "%.6a"
+    #define PRI_MAC_ADDR PUB_MAC_ADDR
 #endif
+
+extern void LogToFD(int fd, const char *format, ...);
+
+#endif // __mDNSDebug_h
index d714de490ca06cfb8f3eb54289530a298c890adf..041772a5c0a8e2d0761f7c3ad759b92e8b5a1c5d 100755 (executable)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
 #include <stdarg.h>     // stdarg.h is required for for va_list support for the mDNS_vsnprintf declaration
 #endif
 
-#include "mDNSDebug.h"
 #if APPLE_OSX_mDNSResponder
 #include <uuid/uuid.h>
-#include <TargetConditionals.h>
 #endif
 
-#ifdef __cplusplus
-extern "C" {
-#endif
+#include "mDNSFeatures.h"
 
 // ***************************************************************************
 // Feature removal compile options & limited resource targets
@@ -84,13 +79,16 @@ extern "C" {
 // memory footprint for use in embedded systems with limited resources.
 
 // UNICAST_DISABLED - disables unicast DNS functionality, including Wide Area Bonjour
-// ANONYMOUS_DISABLED - disables anonymous functionality
 // DNSSEC_DISABLED - disables DNSSEC functionality
 // SPC_DISABLED - disables Bonjour Sleep Proxy client
 // IDLESLEEPCONTROL_DISABLED - disables sleep control for Bonjour Sleep Proxy clients
 
 // In order to disable the above features pass the option to your compiler, e.g. -D UNICAST_DISABLED
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
+#endif
+
 // Additionally, the LIMITED_RESOURCES_TARGET compile option will reduce the maximum DNS message sizes.
 
 #ifdef LIMITED_RESOURCES_TARGET
@@ -101,8 +99,8 @@ extern "C" {
 #define MaximumRDSize               264
 #endif
 
-#if !defined(MDNSRESPONDER_BTMM_SUPPORT)
-#define MDNSRESPONDER_BTMM_SUPPORT 0
+#ifdef __cplusplus
+extern "C" {
 #endif
 
 // ***************************************************************************
@@ -150,6 +148,20 @@ extern "C" {
  #endif
 #endif
 
+#ifndef fallthrough
+ #if __clang__
+  #if __has_c_attribute(fallthrough)
+   #define fallthrough() [[fallthrough]]
+  #else
+   #define fallthrough()
+  #endif
+ #elif __GNUC__
+  #define fallthrough() __attribute__((fallthrough))
+ #else
+  #define fallthrough()
+ #endif // __GNUC__
+#endif // fallthrough
+
 // ***************************************************************************
 #if 0
 #pragma mark - DNS Resource Record class and type constants
@@ -266,10 +278,17 @@ typedef   signed int mDNSs32;
 typedef unsigned int mDNSu32;
 #endif
 
+#include "mDNSDebug.h"
+
 // To enforce useful type checking, we make mDNSInterfaceID be a pointer to a dummy struct
 // This way, mDNSInterfaceIDs can be assigned, and compared with each other, but not with other types
 // Declaring the type to be the typical generic "void *" would lack this type checking
-typedef struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
+typedef const struct mDNSInterfaceID_dummystruct { void *dummy; } *mDNSInterfaceID;
+
+// Use when printing interface IDs; the interface ID is actually a pointer, but we're only using
+// the pointer as a unique identifier, and in special cases it's actually a small number.   So there's
+// little point in printing all 64 bits--the upper 32 bits in particular will not add information.
+#define IIDPrintable(x) ((uint32_t)(uintptr_t)(x))
 
 // These types are for opaque two- and four-byte identifiers.
 // The "NotAnInteger" fields of the unions allow the value to be conveniently passed around in a
@@ -373,8 +392,11 @@ enum
     mStatus_NoRouter                  = -65566,
     mStatus_PollingMode               = -65567,
     mStatus_Timeout                   = -65568,
-    mStatus_HostUnreachErr            = -65569,
-    // -65570 to -65786 currently unused; available for allocation
+    mStatus_DefunctConnection         = -65569,
+    // -65570 to -65785 currently unused; available for allocation
+
+    // udp connection status
+    mStatus_HostUnreachErr    = -65786,
 
     // tcp connection status
     mStatus_ConnPending       = -65787,
@@ -436,13 +458,6 @@ typedef struct { mDNSu8 c[256]; } UTF8str255;       // Null-terminated C string
 #define kStandardTTL (3600UL * 100 / 80)
 #define kHostNameTTL 120UL
 
-// Some applications want to register their SRV records with a lower ttl so that in case the server
-// using a dynamic port number restarts, the clients will not have stale information for more than
-// 10 seconds
-
-#define kHostNameSmallTTL 10UL
-
-
 // Multicast DNS uses announcements (gratuitous responses) to update peer caches.
 // This means it is feasible to use relatively larger TTL values than we might otherwise
 // use, because we have a cache coherency protocol to keep the peer caches up to date.
@@ -478,6 +493,7 @@ typedef struct ResourceRecord_struct ResourceRecord;
 
 // Structure to abstract away the differences between TCP/SSL sockets, and one for UDP sockets
 // The actual definition of these structures appear in the appropriate platform support code
+typedef struct TCPListener_struct TCPListener;
 typedef struct TCPSocket_struct TCPSocket;
 typedef struct UDPSocket_struct UDPSocket;
 
@@ -873,23 +889,6 @@ typedef packedstruct
     // hashLength, nxt, bitmap
 } rdataNSEC3;
 
-// In the multicast usage of NSEC3, we know the actual size of RData
-// 4 bytes : HashAlg, Flags,Iterations
-// 5 bytes : Salt Length 1 byte, Salt 4 bytes
-// 21 bytes : HashLength 1 byte, Hash 20 bytes
-// 34 bytes : Window number, Bitmap length, Type bit map to include the first 256 types
-#define MCAST_NSEC3_RDLENGTH (4 + 5 + 21 + 34)
-#define SHA1_HASH_LENGTH 20
-
-// Base32 encoding takes 5 bytes of the input and encodes as 8 bytes of output.
-// For example, SHA-1 hash of 20 bytes will be encoded as 20/5 * 8 = 32 base32
-// bytes. For a max domain name size of 255 bytes of base32 encoding : (255/8)*5
-// is the max hash length possible.
-#define NSEC3_MAX_HASH_LEN  155
-// In NSEC3, the names are hashed and stored in the first label and hence cannot exceed label
-// size.
-#define NSEC3_MAX_B32_LEN   MAX_DOMAIN_LABEL
-
 // We define it here instead of dnssec.h so that these values can be used
 // in files without bringing in all of dnssec.h unnecessarily.
 typedef enum
@@ -1315,15 +1314,6 @@ struct NATTraversalInfo_struct
 #pragma mark - DNSServer & McastResolver structures and constants
 #endif
 
-enum
-{
-    DNSServer_FlagDelete      = 0x1,
-    DNSServer_FlagNew         = 0x2,
-#if APPLE_OSX_mDNSResponder
-    DNSServer_FlagUnreachable = 0x4,
-#endif
-};
-
 enum
 {
     McastResolver_FlagDelete = 1,
@@ -1355,6 +1345,12 @@ typedef enum
                                    // have a matching serviceID
 } ScopeType;
 
+typedef mDNSu32 DNSServerFlags;
+#define DNSServerFlag_Delete        (1U << 0)
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#define DNSServerFlag_Unreachable   (1U << 1)
+#endif
+
 // Note: DNSSECAware is set if we are able to get a valid response to
 // a DNSSEC question. In some cases it is possible that the proxy
 // strips the EDNS0 option and we just get a plain response with no
@@ -1366,37 +1362,33 @@ typedef struct DNSServer
 {
     struct DNSServer *next;
     mDNSInterfaceID interface;  // DNS requests should be sent on this interface
-    mDNSs32 serviceID;
-    mDNSAddr addr;
-    mDNSIPPort port;
-    mDNSu32 flags;              // Set when we're planning to delete this from the list
-    domainname domain;          // name->server matching for "split dns"
+    mDNSs32 serviceID;          // ServiceID from DNS configuration.
+    mDNSAddr addr;              // DNS server's IP address.
+    DNSServerFlags flags;       // Set when we're planning to delete this from the list.
     mDNSs32 penaltyTime;        // amount of time this server is penalized
     ScopeType scopeType;        // See the ScopeType enum above
     mDNSu32 timeout;            // timeout value for questions
     mDNSu32 resGroupID;         // ID of the resolver group that contains this DNSServer
-    mDNSu8 retransDO;           // Total Retransmissions for queries sent with DO option
-    mDNSBool isCell;            // Resolver from Cellular Interface?
-    mDNSBool req_A;             // If set, send v4 query (DNSConfig allows A queries)
-    mDNSBool req_AAAA;          // If set, send v6 query (DNSConfig allows AAAA queries)
+    mDNSIPPort port;            // DNS server's port number.
+    mDNSBool usableA;           // True if A query results are usable over the interface, i.e., interface has IPv4.
+    mDNSBool usableAAAA;        // True if AAAA query results are usable over the interface, i.e., interface has IPv6.
+    mDNSBool isCell;            // True if the interface to this server is cellular.
+    mDNSBool isExpensive;       // True if the interface to this server is expensive.
+    mDNSBool isConstrained;     // True if the interface to this server is constrained.
+    mDNSBool isCLAT46;          // True if the interface to this server supports CLAT46.
     mDNSBool req_DO;            // If set, okay to send DNSSEC queries (EDNS DO bit is supported)
     mDNSBool DNSSECAware;       // Set if we are able to receive a response to a request sent with DO option.
-    mDNSBool isExpensive;       // True if the interface to this server is expensive.
-    mDNSBool isCLAT46;          // True if the interface to this server is CLAT46.
+    mDNSu8 retransDO;           // Total Retransmissions for queries sent with DO option
+    domainname domain;          // name->server matching for "split dns"
 } DNSServer;
 
-typedef struct
-{
-    mDNSu8 *AnonData;
-    int AnonDataLen;
-    mDNSu32 salt;
-    ResourceRecord *nsec3RR;
-    mDNSInterfaceID SendNow;     // The interface ID that this record should be sent on
-} AnonymousInfo;
+#define kNegativeRecordType_Unspecified 0 // Initializer of ResourceRecord didn't specify why the record is negative.
+#define kNegativeRecordType_NoData      1 // The record's name exists, but there are no records of this type.
 
 struct ResourceRecord_struct
 {
     mDNSu8 RecordType;                  // See kDNSRecordTypes enum.
+    mDNSu8 negativeRecordType;          // If RecordType is kDNSRecordTypePacketNegative, specifies type of negative record.
     MortalityState mortality;           // Mortality of this resource record (See MortalityState enum)
     mDNSu16 rrtype;                     // See DNS_TypeValues enum.
     mDNSu16 rrclass;                    // See DNS_ClassValues enum.
@@ -1419,7 +1411,6 @@ struct ResourceRecord_struct
     const domainname *name;
     RData           *rdata;             // Pointer to storage for this rdata
     DNSServer       *rDNSServer;        // Unicast DNS server authoritative for this entry; null for multicast
-    AnonymousInfo   *AnonInfo;          // Anonymous Information
 };
 
 
@@ -1490,9 +1481,12 @@ typedef enum
     AuthRecordAnyIncludeAWDL,   // registered for *Any, including AWDL interface
     AuthRecordAnyIncludeAWDLandP2P, // registered for *Any, including AWDL and P2P interfaces
     AuthRecordLocalOnly,
-    AuthRecordP2P               // discovered over D2D/P2P framework
+    AuthRecordP2P,              // discovered over D2D/P2P framework
 } AuthRecType;
 
+#define AuthRecordIncludesAWDL(AR) \
+    (((AR)->ARType == AuthRecordAnyIncludeAWDL) || ((AR)->ARType == AuthRecordAnyIncludeAWDLandP2P))
+
 typedef enum
 {
     AuthFlagsWakeOnly = 0x1     // WakeOnly service
@@ -1529,6 +1523,8 @@ struct AuthRecord_struct
     mDNSs32 KATimeExpire;               // In platform time units: time to send keepalive packet for the proxy record
 
     // Field Group 3: Transient state for Authoritative Records
+    mDNSs32 ProbingConflictCount;       // Number of conflicting records observed during probing.
+    mDNSs32 LastConflictPktNum;         // Number of the last received packet that caused a probing conflict.
     mDNSu8 Acknowledged;                // Set if we've given the success callback to the client
     mDNSu8 ProbeRestartCount;           // Number of times we have restarted probing
     mDNSu8 ProbeCount;                  // Number of probes remaining before this record is valid (kDNSRecordTypeUnique)
@@ -1610,7 +1606,7 @@ struct AuthRecord_struct
 // Note: Question_uDNS(Q) is used in *only* one place -- on entry to mDNS_StartQuery_internal, to decide whether to set TargetQID.
 // Everywhere else in the code, the determination of whether a question is unicast is made by checking to see if TargetQID is nonzero.
 #define AuthRecord_uDNS(R) ((R)->resrec.InterfaceID == mDNSInterface_Any && !(R)->ForceMCast && !IsLocalDomain((R)->resrec.name))
-#define Question_uDNS(Q)   ((Q)->InterfaceID == mDNSInterface_Unicast || (Q)->ProxyQuestion || \
+#define Question_uDNS(Q)   ((Q)->IsUnicastDotLocal || (Q)->ProxyQuestion || \
                             ((Q)->InterfaceID != mDNSInterface_LocalOnly && (Q)->InterfaceID != mDNSInterface_P2P && (Q)->InterfaceID != mDNSInterface_BLE && !(Q)->ForceMCast && !IsLocalDomain(&(Q)->qname)))
 
 // AuthRecordLocalOnly records are registered using mDNSInterface_LocalOnly and 
@@ -1620,13 +1616,6 @@ struct AuthRecord_struct
 // All other auth records, not including those defined as RRLocalOnly().
 #define RRAny(rr) ((rr)->ARType == AuthRecordAny || (rr)->ARType == AuthRecordAnyIncludeP2P || (rr)->ARType == AuthRecordAnyIncludeAWDL || (rr)->ARType == AuthRecordAnyIncludeAWDLandP2P)
 
-// Question (A or AAAA) that is suppressed currently because IPv4 or IPv6 address
-// is not available locally for A or AAAA question respectively. Also, if the
-// query is disallowed for the "pid" that we are sending on behalf of, suppress it.
-#define QuerySuppressed(Q) (((Q)->SuppressUnusable && (Q)->SuppressQuery) || ((Q)->DisallowPID))
-
-#define PrivateQuery(Q) ((Q)->AuthInfo && (Q)->AuthInfo->AutoTunnel)
-
 // Normally we always lookup the cache and /etc/hosts before sending the query on the wire. For single label
 // queries (A and AAAA) that are unqualified (indicated by AppendSearchDomains), we want to append search
 // domains before we try them as such
@@ -1744,7 +1733,6 @@ struct ServiceRecordSet_struct
     ExtraResourceRecord *Extras;    // Optional list of extra AuthRecords attached to this service registration
     mDNSu32 NumSubTypes;
     AuthRecord          *SubTypes;
-    const mDNSu8        *AnonData;
     mDNSu32             flags;      // saved for subsequent calls to mDNS_RegisterService() if records 
                                     // need to be re-registered.
     AuthRecord RR_ADV;              // e.g. _services._dns-sd._udp.local. PTR _printer._tcp.local.
@@ -1776,10 +1764,21 @@ typedef struct
 
 typedef enum
 {
-    LLQ_InitialRequest    = 1,
-    LLQ_SecondaryRequest  = 2,
-    LLQ_Established       = 3,
-    LLQ_Poll              = 4
+    // This is the initial state.
+    LLQ_Init = 1,
+
+    // All of these states indicate that we are doing DNS Push, and haven't given up yet.
+       LLQ_DNSPush_ServerDiscovery = 100,
+       LLQ_DNSPush_Connecting      = 101,
+       LLQ_DNSPush_Established     = 102,
+
+    // All of these states indicate that we are doing LLQ and haven't given up yet.
+    LLQ_InitialRequest   = 200,
+    LLQ_SecondaryRequest = 201,
+    LLQ_Established      = 202,
+
+    // If we get here, it means DNS Push isn't available, so we're polling.
+    LLQ_Poll                    = 300
 } LLQ_State;
 
 // LLQ constants
@@ -1806,23 +1805,15 @@ enum
 
 enum { NoAnswer_Normal = 0, NoAnswer_Suspended = 1, NoAnswer_Fail = 2 };
 
-// DNS Push Notification
-typedef enum
-{
-    DNSPUSH_NOERROR  = 0,
-    DNSPUSH_FORMERR  = 1,
-    DNSPUSH_SERVFAIL = 2,
-    DNSPUSH_NOTIMP   = 4,
-    DNSPUSH_REFUSED  = 5
-} DNSPUSH_ErrorCode;
-
 typedef enum {
-    DNSPUSH_INIT         = 1,
-    DNSPUSH_NOSERVER     = 2,
-    DNSPUSH_SERVERFOUND  = 3,
-    DNSPUSH_ESTABLISHED  = 4
-} DNSPush_State;
-    
+    DNSPushServerDisconnected,
+       DNSPushServerConnectFailed,
+       DNSPushServerConnectionInProgress,
+       DNSPushServerConnected,
+       DNSPushServerSessionEstablished,
+       DNSPushServerNoDNSPush
+} DNSPushServer_ConnectState;
+
 enum {
     AllowExpired_None = 0,                  // Don't allow expired answers or mark answers immortal (behave normally)
     AllowExpired_MakeAnswersImmortal = 1,   // Any answers to this question get marked as immortal
@@ -1835,26 +1826,11 @@ typedef mDNSu8 AllowExpiredState;
 #define HMAC_OPAD   0x5c
 #define MD5_LEN     16
 
-#define AutoTunnelUnregistered(X) (                                               \
-        (X)->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered && \
-        (X)->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered && \
-        (X)->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered && \
-        (X)->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered && \
-        (X)->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered )
-
 // Internal data structure to maintain authentication information
 typedef struct DomainAuthInfo
 {
     struct DomainAuthInfo *next;
     mDNSs32 deltime;                        // If we're planning to delete this DomainAuthInfo, the time we want it deleted
-    mDNSBool   AutoTunnel;                  // Whether this is 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
-    AuthRecord AutoTunnel6Record;           // AutoTunnel AAAA Record obtained from awacsd
-    mDNSBool AutoTunnelServiceStarted;         // Whether a service has been registered in this domain
-    mDNSv6Addr AutoTunnelInnerAddress;
     domainname domain;
     domainname keyname;
     domainname hostname;
@@ -1871,6 +1847,7 @@ typedef struct DomainAuthInfo
 // addition to not entering in the cache, it also forces the negative response through.
 typedef enum { QC_rmv = 0, QC_add, QC_addnocache, QC_forceresponse, QC_dnssec , QC_nodnssec, QC_suppressed } QC_result;
 typedef void mDNSQuestionCallback (mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord);
+typedef void (*mDNSQuestionResetHandler)(DNSQuestion *question);
 typedef void AsyncDispatchFunc(mDNS *const m, void *context);
 typedef void DNSSECAuthInfoFreeCallback(mDNS *const m, void *context);
 extern void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDispatchFunc func);
@@ -1912,21 +1889,30 @@ typedef enum { DNSSECValNotRequired = 0, DNSSECValRequired, DNSSECValInProgress,
 // RFC 4122 defines it to be 16 bytes 
 #define UUID_SIZE       16
 
-#define AWD_METRICS (USE_AWD && TARGET_OS_IOS)
-
-#if AWD_METRICS
-    
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
 enum
 {
     ExpiredAnswer_None = 0,                  // No expired answers used
     ExpiredAnswer_Allowed = 1,               // An expired answer is allowed by this request
-    ExpiredAnswer_AnsweredWithExpired = 2,   // Question was answered with an expired answer
-    ExpiredAnswer_ExpiredAnswerChanged = 3,  // Expired answer changed on refresh
+    ExpiredAnswer_AnsweredWithCache = 2,     // Question was answered with a cached answer
+    ExpiredAnswer_AnsweredWithExpired = 3,   // Question was answered with an expired answer
+    ExpiredAnswer_ExpiredAnswerChanged = 4,  // Expired answer changed on refresh
     
     ExpiredAnswer_EnumCount
 };
 typedef mDNSu8 ExpiredAnswerMetric;
 
+enum
+{
+    DNSOverTCP_None = 0,                     // DNS Over TCP not used
+    DNSOverTCP_Truncated = 1,                // DNS Over TCP used because UDP reply was truncated
+    DNSOverTCP_Suspicious = 2,               // DNS Over TCP used because we received a suspicious reply
+    DNSOverTCP_SuspiciousDefense = 3,        // DNS Over TCP used because we were within the timeframe of a previous suspicious response
+
+    DNSOverTCP_EnumCount
+};
+typedef mDNSu8 DNSOverTCPMetric;
+
 typedef struct
 {
     domainname *        originalQName;          // Name of original A/AAAA record if this question is for a CNAME record.
@@ -1934,21 +1920,22 @@ typedef struct
     mDNSs32             firstQueryTime;         // The time when the first query was sent to a DNS server.
     mDNSBool            answered;               // Has this question been answered?
     ExpiredAnswerMetric expiredAnswerState;     // Expired answer state (see ExpiredAnswerMetric above)
-    
+    DNSOverTCPMetric    dnsOverTCPState;        // DNS Over TCP state (see DNSOverTCPMetric above)
+
 }   uDNSMetrics;
 #endif
 
-// DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
-#define USE_DNS64 (HAVE_DNS64 && TARGET_OS_IOS)
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
+extern mDNSu32 max_num_regservices;  // tracks the max number of simultaneous services registered by the device
+#endif
 
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
 #include "DNS64State.h"
 #endif
 
-#if TARGET_OS_EMBEDDED
-extern mDNSu32 curr_num_regservices; // tracks the current number of services registered
-extern mDNSu32 max_num_regservices;  // tracks the max number of simultaneous services registered by the device
-#endif
+typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer;
+typedef struct mDNS_DNSPushNotificationZone   DNSPushNotificationZone;
 
 struct DNSQuestion_struct
 {
@@ -1974,7 +1961,6 @@ struct DNSQuestion_struct
     DomainAuthInfo       *AuthInfo;         // Non-NULL if query is currently being done using Private DNS
     DNSQuestion          *DuplicateOf;
     DNSQuestion          *NextInDQList;
-    AnonymousInfo        *AnonInfo;         // Anonymous Information
     DupSuppressInfo DupSuppress[DupSuppressInfoSize];
     mDNSInterfaceID SendQNow;               // The interface this query is being sent on right now
     mDNSBool SendOnAll;                     // Set if we're sending this question on all active interfaces
@@ -1983,10 +1969,11 @@ struct DNSQuestion_struct
     mDNSu32 RequestUnicast;                 // Non-zero if we want to send query with kDNSQClass_UnicastResponse bit set
     mDNSs32 LastQTxTime;                    // Last time this Q was sent on one (but not necessarily all) interfaces
     mDNSu32 CNAMEReferrals;                 // Count of how many CNAME redirections we've done
-    mDNSBool SuppressQuery;                 // This query should be suppressed and not sent on the wire
+    mDNSBool Suppressed;                    // This query should be suppressed, i.e., not sent on the wire.
     mDNSu8 LOAddressAnswers;                // Number of answers from the local only auth records that are
                                             // answering A, AAAA, CNAME, or PTR (/etc/hosts)
     mDNSu8 WakeOnResolveCount;              // Number of wakes that should be sent on resolve
+    mDNSBool InitialCacheMiss;              // True after the question cannot be answered from the cache
     mDNSs32 StopTime;                       // Time this question should be stopped by giving them a negative answer
 
     // DNSSEC fields
@@ -2004,7 +1991,7 @@ struct DNSQuestion_struct
     DNSServer            *qDNSServer;       // Caching server for this query (in the absence of an SRV saying otherwise)
     mDNSOpaque128 validDNSServers;          // Valid DNSServers for this question
     mDNSu16 noServerResponse;               // At least one server did not respond.
-    mDNSu16 triedAllServersOnce;            // Tried all DNS servers once
+    mDNSBool triedAllServersOnce;           // True if all DNS servers have been tried once.
     mDNSu8 unansweredQueries;               // The number of unanswered queries to this server
     AllowExpiredState allowExpired;         // Allow expired answers state (see enum AllowExpired_None, etc. above)
 
@@ -2015,7 +2002,7 @@ struct DNSQuestion_struct
     mDNSIPPort tcpSrcPort;                  // Local Port TCP packet received on;need this as tcp struct is disposed
                                             // by tcpCallback before calling into mDNSCoreReceive
     mDNSu8 NoAnswer;                        // Set if we want to suppress answers until tunnel setup has completed
-    mDNSu8 Restart;                         // This question should be restarted soon
+    mDNSBool Restart;                       // This question should be restarted soon.
 
     // LLQ-specific fields. These fields are only meaningful when LongLived flag is set
     LLQ_State state;
@@ -2027,24 +2014,20 @@ struct DNSQuestion_struct
                                             //          the number of packets sent for this TCP/TLS connection
 
     // DNS Push Notification fields. These fields are only meaningful when LongLived flag is set
-    DNSPush_State dnsPushState;             // The state of the DNS push notification negotiation
-    mDNSAddr      dnsPushServerAddr;        // Address of the system acting as the DNS Push Server
-    mDNSIPPort    dnsPushServerPort;        // Port on which the DNS Push Server is being advertised.
+    DNSPushNotificationServer *dnsPushServer;
     
     mDNSOpaque64 id;
 
     // DNS Proxy fields
     mDNSOpaque16 responseFlags;             // Temporary place holder for the error we get back from the DNS server
                                             // till we populate in the cache
-    mDNSBool     DisallowPID;               // Is the query allowed for the "PID" that we are sending on behalf of ?
+    mDNSBool     BlockedByPolicy;           // True if the question is blocked by policy rule evaluation.
     mDNSs32      ServiceID;                 // Service identifier to match against the DNS server
 
     // 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
     mDNSu32  flags;                         // flags from original DNSService*() API request.
-    mDNSAddr Target;                        // Non-zero if you want to direct queries to a specific unicast target address
-    mDNSIPPort TargetPort;                  // Must be set if Target is set
-    mDNSOpaque16 TargetQID;                 // Must be set if Target is set
+    mDNSOpaque16 TargetQID;                 // DNS or mDNS message ID.
     domainname qname;
     domainname firstExpiredQname;           // first expired qname in request chain
     mDNSu16 qtype;
@@ -2054,26 +2037,25 @@ struct DNSQuestion_struct
     mDNSBool ForceMCast;                    // Set by client to force mDNS query, even for apparently uDNS names
     mDNSBool ReturnIntermed;                // Set by client to request callbacks for intermediate CNAME/NXDOMAIN results
     mDNSBool SuppressUnusable;              // Set by client to suppress unusable queries to be sent on the wire
-    mDNSu8 RetryWithSearchDomains;          // Retry with search domains if there is no entry in the cache or AuthRecords
-    mDNSu8 TimeoutQuestion;                 // Timeout this question if there is no reply in configured time
-    mDNSu8 WakeOnResolve;                   // Send wakeup on resolve
-    mDNSu8 UseBackgroundTrafficClass;       // Set by client to use background traffic class for request
-    mDNSs8 SearchListIndex;                 // Index into SearchList; Used by the client layer but not touched by core
-    mDNSs8 AppendSearchDomains;             // Search domains can be appended for this query
-    mDNSs8 AppendLocalSearchDomains;        // Search domains ending in .local can be appended for this query
+    mDNSBool TimeoutQuestion;               // Timeout this question if there is no reply in configured time
+    mDNSBool IsUnicastDotLocal;             // True if this is a dot-local query that should be answered via unicast DNS.
+    mDNSBool WakeOnResolve;                 // Send wakeup on resolve
+    mDNSBool UseBackgroundTraffic;          // Set by client to use background traffic class for request
+    mDNSBool AppendSearchDomains;           // Search domains can be appended for this query
     mDNSu8 ValidationRequired;              // Requires DNSSEC validation.
     mDNSu8 ProxyQuestion;                   // Proxy Question
     mDNSu8 ProxyDNSSECOK;                   // Proxy Question with EDNS0 DNSSEC OK bit set
     mDNSs32 pid;                            // Process ID of the client that is requesting the question
     mDNSu8  uuid[UUID_SIZE];                // Unique ID of the client that is requesting the question (valid only if pid is zero)
     mDNSu32 euid;                           // Effective User Id of the client that is requesting the question
-    domainname           *qnameOrig;        // Copy of the original question name if it is not fully qualified
+    mDNSu32 request_id;                     // The ID of request that generates the current question
     mDNSQuestionCallback *QuestionCallback;
+    mDNSQuestionResetHandler ResetHandler;
     void                 *QuestionContext;
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     uDNSMetrics metrics;                    // Data used for collecting unicast DNS query metrics.
 #endif
-#if USE_DNS64
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
     DNS64 dns64;                            // DNS64 state for performing IPv6 address synthesis on networks with NAT64.
 #endif
 };
@@ -2169,7 +2151,9 @@ struct NetworkInterfaceInfo_struct
     // Standard AuthRecords that every Responder host should have (one per active IP address)
     AuthRecord RR_A;                    // 'A' or 'AAAA' (address) record for our ".local" name
     AuthRecord RR_PTR;                  // PTR (reverse lookup) record
-    AuthRecord RR_HINFO;
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    AuthRecord RR_AddrRand;             // For non-AWDL interfaces, this is the A or AAAA record of the randomized hostname.
+#endif
 
     // Client API fields: The client must set up these fields *before* calling mDNS_RegisterInterface()
     mDNSInterfaceID InterfaceID;        // Identifies physical interface; MUST NOT be 0, -1, or -2
@@ -2302,27 +2286,7 @@ typedef struct
     mDNSu32 WakeOnResolves;                 // Number of times we did a wake on resolve
 } mDNSStatistics;
 
-extern void LogMDNSStatistics(mDNS *const m);
-
-typedef struct mDNS_DNSPushNotificationServer DNSPushNotificationServer;
-typedef struct mDNS_DNSPushNotificationZone   DNSPushNotificationZone;
-
-struct mDNS_DNSPushNotificationServer
-{
-    mDNSAddr   serverAddr;        // Server Address
-    tcpInfo_t *connection;        // TCP Connection pointer
-    mDNSu32    numberOfQuestions; // Number of questions for this server
-    DNSPushNotificationServer *next;
-} ;
-
-struct mDNS_DNSPushNotificationZone
-{
-    domainname zoneName;
-    DNSPushNotificationServer *servers; // DNS Push Notification Servers for this zone
-    mDNSu32 numberOfQuestions;          // Number of questions for this zone
-    DNSPushNotificationZone *next;
-} ;
-
+extern void LogMDNSStatisticsToFD(int fd, mDNS *const m);
 
 // Time constant (~= 260 hours ~= 10 days and 21 hours) used to set
 // various time values to a point well into the future.
@@ -2372,11 +2336,13 @@ struct mDNS_struct
     mDNSs32 NextScheduledNATOp;         // Next time to send NAT-traversal packets
     mDNSs32 NextScheduledSPS;           // Next time to purge expiring Sleep Proxy records
     mDNSs32 NextScheduledKA;            // Next time to send Keepalive packets (SPS)
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     mDNSs32 NextBonjourDisableTime;     // Next time to leave multicast group if Bonjour on Demand is enabled
     mDNSu8 BonjourEnabled;              // Non zero if Bonjour is currently enabled by the Bonjour on Demand logic
-#endif // BONJOUR_ON_DEMAND
-    mDNSs32 DelayConflictProcessing;    // To prevent spurious confilcts due to stale packets on the wire/air.
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+    mDNSs32 NextSuspiciousTimeout;      // Time until suspicious reply defense will timeout
+#endif
     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
@@ -2427,6 +2393,14 @@ struct mDNS_struct
     domainlabel nicelabel;              // Rich text label encoded using canonically precomposed UTF-8
     domainlabel hostlabel;              // Conforms to RFC 1034 "letter-digit-hyphen" ARPANET host name rules
     domainname MulticastHostname;       // Fully Qualified "dot-local" Host Name, e.g. "Foo.local."
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    domainname RandomizedHostname;      // Randomized hostname to use for services involving AWDL interfaces. This is to
+                                        // avoid using a hostname derived from the device's name, which may contain the
+                                        // owner's real name, (e.g., "Steve's iPhone" -> "Steves-iPhone.local"), which is a
+                                        // privacy concern.
+    mDNSu32 AutoTargetAWDLIncludedCount;// Number of registered AWDL-included auto-target records.
+    mDNSu32 AutoTargetAWDLOnlyCount;    // Number of registered AWDL-only auto-target records.
+#endif
     UTF8str255 HIHardware;
     UTF8str255 HISoftware;
     AuthRecord DeviceInfo;
@@ -2459,8 +2433,6 @@ struct mDNS_struct
     domainname StaticHostname;              // Current answer to reverse-map query
     domainname FQDN;
     HostnameInfo     *Hostnames;            // List of registered hostnames + hostname metadata
-    NATTraversalInfo AutoTunnelNAT;         // Shared between all AutoTunnel DomainAuthInfo structs
-    mDNSv6Addr AutoTunnelRelayAddr;
 
     mDNSu32 WABBrowseQueriesCount;          // Number of WAB Browse domain enumeration queries (b, db) callers
     mDNSu32 WABLBrowseQueriesCount;         // Number of legacy WAB Browse domain enumeration queries (lb) callers
@@ -2518,9 +2490,8 @@ struct mDNS_struct
     int ProxyRecords;                           // Total number of records we're holding as proxy
     #define           MAX_PROXY_RECORDS 10000   /* DOS protection: 400 machines at 25 records each */
 
-#if APPLE_OSX_mDNSResponder
-    ClientTunnel     *TunnelClients;
-    void            *WCF;
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+    WCFConnection    *WCF;
 #endif
     // DNS Proxy fields
     mDNSu32 dp_ipintf[MaxIp];                   // input interface index list from the DNS Proxy Client
@@ -2531,11 +2502,11 @@ struct mDNS_struct
     int             uds_listener_skt;           // Listening socket for incoming UDS clients. This should not be here -- it's private to uds_daemon.c and nothing to do with mDNSCore -- SC
     mDNSu32         AutoTargetServices;         // # of services that have AutoTarget set
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
     // Counters used in Bonjour on Demand logic.
     mDNSu32         NumAllInterfaceRecords;     // Right now we count *all* multicast records here. Later we may want to change to count interface-specific records separately. (This count includes records on the DuplicateRecords list too.)
     mDNSu32         NumAllInterfaceQuestions;   // Right now we count *all* multicast questions here. Later we may want to change to count interface-specific questions separately.
-#endif // BONJOUR_ON_DEMAND
+#endif
 
     DNSSECStatistics DNSSECStats;
     mDNSStatistics   mDNSStats;
@@ -2545,6 +2516,8 @@ struct mDNS_struct
     union { DNSMessage m; void *p; } imsg;  // Incoming message received from wire
     DNSMessage omsg;                        // Outgoing message we're building
     LargeCacheRecord rec;                   // Resource Record extracted from received message
+
+    mDNSu32 next_request_id;
 };
 
 #define FORALL_CACHERECORDS(SLOT,CG,CR)                           \
@@ -2560,7 +2533,6 @@ struct mDNS_struct
 
 extern const mDNSInterfaceID mDNSInterface_Any;             // Zero
 extern const mDNSInterfaceID mDNSInterface_LocalOnly;       // Special value
-extern const mDNSInterfaceID mDNSInterface_Unicast;         // Special value
 extern const mDNSInterfaceID mDNSInterfaceMark;             // Special value
 extern const mDNSInterfaceID mDNSInterface_P2P;             // Special value
 extern const mDNSInterfaceID uDNSInterfaceMark;             // Special value
@@ -2615,10 +2587,6 @@ extern const mDNSOpaque64 zeroOpaque64;
 extern const mDNSOpaque128 zeroOpaque128;
     
 extern mDNSBool StrictUnicastOrdering;
-extern int NumUnicastDNSServers;
-#if APPLE_OSX_mDNSResponder
-extern mDNSu8 NumUnreachableDNSServers;
-#endif
 
 #define localdomain           (*(const domainname *)"\x5" "local")
 #define DeviceInfoName        (*(const domainname *)"\xC" "_device-info" "\x4" "_tcp")
@@ -2639,6 +2607,7 @@ extern mDNSu8 NumUnreachableDNSServers;
 
 // If we're not doing inline functions, then this header needs to have the extern declarations
 #if !defined(mDNSinline)
+extern int          CountOfUnicastDNSServers(mDNS *const m);
 extern mDNSs32      NonZeroTime(mDNSs32 t);
 extern mDNSu16      mDNSVal16(mDNSOpaque16 x);
 extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
@@ -2652,6 +2621,14 @@ extern mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v);
 
 #ifdef mDNSinline
 
+mDNSinline int CountOfUnicastDNSServers(mDNS *const m)
+{
+    int count = 0;
+    DNSServer *ptr = m->DNSServers;
+    while(ptr) { if(!(ptr->flags & DNSServerFlag_Delete)) count++; ptr = ptr->next; }
+    return (count);
+}
+
 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])); }
@@ -2665,6 +2642,10 @@ mDNSinline mDNSOpaque16 mDNSOpaque16fromIntVal(mDNSu16 v)
 }
 
 #endif
+    
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+#define SUSPICIOUS_REPLY_DEFENSE_SECS   10
+#endif
 
 // ***************************************************************************
 #if 0
@@ -2806,7 +2787,6 @@ typedef enum { mDNS_Dereg_normal, mDNS_Dereg_rapid, mDNS_Dereg_conflict, mDNS_De
 extern void    mDNS_SetupResourceRecord(AuthRecord *rr, RData *RDataStorage, mDNSInterfaceID InterfaceID,
                                         mDNSu16 rrtype, mDNSu32 ttl, mDNSu8 RecordType, AuthRecType artype, mDNSRecordCallback Callback, void *Context);
 
-extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType);
 extern 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, RData *txtrdata, const mDNSu8 txtinfo[], mDNSu16 txtlen,
@@ -2828,7 +2808,7 @@ extern void mDNS_SetupQuestion(DNSQuestion *const q, const mDNSInterfaceID Inter
                                const mDNSu16 qtype, mDNSQuestionCallback *const callback, void *const context);
 
 extern mStatus mDNS_StartBrowse(mDNS *const m, DNSQuestion *const question,
-                                const domainname *const srv, const domainname *const domain, const mDNSu8 *anondata,
+                                const domainname *const srv, const domainname *const domain,
                                 const mDNSInterfaceID InterfaceID, mDNSu32 flags,
                                 mDNSBool ForceMCast, mDNSBool useBackgroundTrafficClass,
                                 mDNSQuestionCallback *Callback, void *Context);
@@ -2877,6 +2857,10 @@ extern mDNSu32 SetValidDNSServers(mDNS *m, DNSQuestion *question);
 // This macro uses mDNSPlatformMemCopy() to make sure it only touches the actual bytes that are valid.
 #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)
+#define AssignConstStringDomainName(DST, SRC) do { \
+    mDNSu16 len__ = DomainNameLengthLimit((domainname *)(SRC), (mDNSu8 *)(SRC) + sizeof (SRC)); \
+    if (len__ <= MAX_DOMAIN_NAME) \
+        mDNSPlatformMemCopy((DST)->c, (SRC), 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]))
@@ -2964,6 +2948,7 @@ extern mDNSBool DeconstructServiceName(const domainname *const fqdn, domainlabel
 // not the number of characters that *would* have been printed were buflen unlimited.
 extern mDNSu32 mDNS_vsnprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, va_list arg) IS_A_PRINTF_STYLE_FUNCTION(3,0);
 extern mDNSu32 mDNS_snprintf(char *sbuffer, mDNSu32 buflen, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
+extern void mDNS_snprintf_add(char **dst, const char *lim, const char *fmt, ...) IS_A_PRINTF_STYLE_FUNCTION(3,4);
 extern mDNSu32 NumCacheRecordsForInterfaceID(const mDNS *const m, mDNSInterfaceID id);
 extern char *DNSTypeName(mDNSu16 rrtype);
 extern char *GetRRDisplayString_rdb(const ResourceRecord *const rr, const RDataBody *const rd1, char *const buffer);
@@ -2975,6 +2960,7 @@ extern mDNSBool mDNSSameAddress(const mDNSAddr *ip1, const mDNSAddr *ip2);
 extern void IncrementLabelSuffix(domainlabel *name, mDNSBool RichText);
 extern mDNSBool mDNSv4AddrIsRFC1918(const mDNSv4Addr * const addr);  // returns true for RFC1918 private addresses
 #define mDNSAddrIsRFC1918(X) ((X)->type == mDNSAddrType_IPv4 && mDNSv4AddrIsRFC1918(&(X)->ip.v4))
+extern const char *DNSScopeToString(mDNSu32 scope);
 
 // For PCP
 extern void mDNSAddrMapIPv4toIPv6(mDNSv4Addr* in, mDNSv6Addr* out);
@@ -3046,7 +3032,7 @@ extern mDNSBool mDNSAddrIPv4FromMappedIPv6(mDNSv6Addr *in, mDNSv4Addr *out);
 // and the value is prepended to the IPSec identifier (used for key lookup)
 
 extern mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
-                                       const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel);
+                                       const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port);
 
 extern void RecreateNATMappings(mDNS *const m, const mDNSu32 waitTicks);
 
@@ -3071,7 +3057,7 @@ extern void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCa
 extern void mDNS_RemoveDynDNSHostName(mDNS *m, const domainname *fqdn);
 extern void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAddr *v6addr, const mDNSAddr *router);
 extern DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, mDNSs32 serviceID, const mDNSAddr *addr,
-                                    const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46,
+                                    const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46,
                                     mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO);
 extern void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 responseFlags);
 extern void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID);
@@ -3100,9 +3086,6 @@ extern void DNSDigest_SignMessage(DNSMessage *msg, mDNSu8 **end, DomainAuthInfo
     (M)->h.numAdditionals = (mDNSu16)((mDNSu8 *)&(M)->h.numAdditionals)[0] << 8 | ((mDNSu8 *)&(M)->h.numAdditionals)[1]; \
 } while (0)
 
-#define DNSDigest_SignMessageHostByteOrder(M,E,INFO) \
-    do { SwapDNSHeaderBytes(M); DNSDigest_SignMessage((M), (E), (INFO), 0); SwapDNSHeaderBytes(M); } while (0)
-
 // 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
@@ -3144,6 +3127,17 @@ extern mDNSBool DNSDigest_VerifyMessage(DNSMessage *msg, mDNSu8 *end, LargeCache
 //
 // mDNSPlatformUTC returns the time, in seconds, since Jan 1st 1970 UTC and is required for generating TSIG records
 
+#ifdef MDNS_MALLOC_DEBUGGING
+typedef void mDNSListValidationFunction(void *);
+typedef struct listValidator mDNSListValidator;
+struct listValidator {
+    struct listValidator *next;
+    const char *validationFunctionName;
+    mDNSListValidationFunction *validator;
+    void *context;
+};
+#endif // MDNS_MALLOC_DEBUGGING
+
 extern mStatus  mDNSPlatformInit        (mDNS *const m);
 extern void     mDNSPlatformClose       (mDNS *const m);
 extern mStatus  mDNSPlatformSendUDP(const mDNS *const m, const void *const msg, const mDNSu8 *const end,
@@ -3153,7 +3147,6 @@ extern mStatus  mDNSPlatformSendUDP(const mDNS *const m, const void *const msg,
 extern void     mDNSPlatformLock        (const mDNS *const m);
 extern void     mDNSPlatformUnlock      (const mDNS *const m);
 
-extern void     mDNSPlatformStrCopy     (      void *dst, const void *src);
 extern mDNSu32  mDNSPlatformStrLCopy    (      void *dst, const void *src, mDNSu32 len);
 extern mDNSu32  mDNSPlatformStrLen      (                 const void *src);
 extern void     mDNSPlatformMemCopy     (      void *dst, const void *src, mDNSu32 len);
@@ -3161,13 +3154,18 @@ extern mDNSBool mDNSPlatformMemSame     (const void *dst, const void *src, mDNSu
 extern int      mDNSPlatformMemCmp      (const void *dst, const void *src, mDNSu32 len);
 extern void     mDNSPlatformMemZero     (      void *dst,                  mDNSu32 len);
 extern void mDNSPlatformQsort       (void *base, int nel, int width, int (*compar)(const void *, const void *));
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-#define         mDNSPlatformMemAllocate(X) mallocL(# X, X)
+#if MDNS_MALLOC_DEBUGGING
+#define         mDNSPlatformMemAllocate(X)      mallocL(# X, X)
+#define         mDNSPlatformMemAllocateClear(X)        callocL(# X, X)
+#define         mDNSPlatformMemFree(X)          freeL(# X, X)
+extern void     mDNSPlatformValidateLists (void);
+extern void     mDNSPlatformAddListValidator(mDNSListValidator *validator,
+                                             mDNSListValidationFunction *vf, const char *vfName, void *context);
 #else
-extern void *   mDNSPlatformMemAllocate (mDNSu32 len);
+extern void *   mDNSPlatformMemAllocate(mDNSu32 len);
 extern void *   mDNSPlatformMemAllocateClear(mDNSu32 len);
-#endif
-extern void     mDNSPlatformMemFree     (void *mem);
+extern void     mDNSPlatformMemFree(void *mem);
+#endif // MDNS_MALLOC_DEBUGGING
 
 // If the platform doesn't have a strong PRNG, we define a naive multiply-and-add based on a seed
 // from the platform layer.  Long-term, we should embed an arc4 implementation, but the strength
@@ -3221,10 +3219,17 @@ typedef enum
 } TCPSocketFlags;
 
 typedef void (*TCPConnectionCallback)(TCPSocket *sock, void *context, mDNSBool ConnectionEstablished, mStatus err);
-extern TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
+typedef void (*TCPAcceptedCallback)(TCPSocket *sock, mDNSAddr *addr, mDNSIPPort *port,
+                                                                       const char *remoteName, void *context);
+extern TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrtype, mDNSIPPort *port, domainname *hostname, mDNSBool useBackgroundTrafficClass); // creates a TCP socket
+extern TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+                                                                                 TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+                                                                                 TCPAcceptedCallback callback, void *context); // Listen on a port
+extern mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context);
 extern TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd);
 extern int        mDNSPlatformTCPGetFD(TCPSocket *sock);
-extern mStatus    mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname,
+extern mDNSBool   mDNSPlatformTCPWritable(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);
@@ -3253,7 +3258,7 @@ extern void       mDNSPlatformTLSTearDownCerts(void);
 // in browse/registration calls must implement these routines to get the "default" browse/registration list.
 
 extern mDNSBool   mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **RegDomains,
-                        DNameListElem **BrowseDomains, mDNSBool ackConfig);
+                                           DNameListElem **BrowseDomains, mDNSBool ackConfig);
 extern mStatus    mDNSPlatformGetPrimaryInterface(mDNSAddr *v4, mDNSAddr *v6, mDNSAddr *router);
 extern void       mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status);
 
@@ -3262,13 +3267,17 @@ extern void       mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason);
 extern void       mDNSPlatformSendWakeupPacket(mDNSInterfaceID InterfaceID, char *EthAddr, char *IPAddr, int iteration);
 
 extern mDNSBool   mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID);
-extern mDNSBool   mDNSPlatformInterfaceIsAWDL(const NetworkInterfaceInfo *intf);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+extern mDNSBool   mDNSPlatformInterfaceIsAWDL(mDNSInterfaceID interfaceID);
+#endif
 extern mDNSBool   mDNSPlatformValidRecordForQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
 extern mDNSBool   mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID);
 extern mDNSBool   mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf);
 
 extern void mDNSPlatformFormatTime(unsigned long t, mDNSu8 *buf, int bufsize);
 
+// Platform event API
+
 #ifdef _LEGACY_NAT_TRAVERSAL_
 // Support for legacy NAT traversal protocols, implemented by the platform layer and callable by the core.
 extern void     LNT_SendDiscoveryMsg(mDNS *m);
@@ -3332,6 +3341,9 @@ extern void     mDNSCoreInitComplete(mDNS *const m, mStatus result);
 extern void     mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const end,
                                 const mDNSAddr *const srcaddr, const mDNSIPPort srcport,
                                 const mDNSAddr *dstaddr, const mDNSIPPort dstport, const mDNSInterfaceID InterfaceID);
+extern CacheRecord *mDNSCheckCacheFlushRecords(mDNS *m, CacheRecord *CacheFlushRecords, mDNSBool id_is_zero, int numAnswers,
+                                                                                          DNSQuestion *unicastQuestion, CacheRecord *NSECCachePtr, CacheRecord *NSECRecords,
+                                                                                          mDNSu8 rcode);
 extern void     mDNSCoreRestartQueries(mDNS *const m);
 extern void     mDNSCoreRestartQuestion(mDNS *const m, DNSQuestion *q);
 extern void     mDNSCoreRestartRegistration(mDNS *const m, AuthRecord  *rr, int announceCount);
@@ -3377,26 +3389,12 @@ extern AuthGroup *AuthGroupForName(AuthHash *r, const mDNSu32 namehash, const do
 extern AuthGroup *AuthGroupForRecord(AuthHash *r, const ResourceRecord *const rr);
 extern AuthGroup *InsertAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
 extern AuthGroup *RemoveAuthRecord(mDNS *const m, AuthHash *r, AuthRecord *rr);
-extern mDNSBool mDNS_CheckForCacheRecord(mDNS *const m, DNSQuestion *q, mDNSu16 qtype);
 
-// 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(DNSQuestion *const q);
-extern void StartServerTunnel(DomainAuthInfo *const info);
-extern void UpdateAutoTunnelDomainStatuses(const mDNS *const m);
-extern void RemoveAutoTunnel6Record(mDNS *const m);
-extern mDNSBool RecordReadyForSleep(AuthRecord *rr);
 // For now this LocalSleepProxy 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
 extern mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool offloadKeepAlivesOnly, mDNSBool *keepaliveOnly);
-extern void mDNSPlatformUpdateDNSStatus(DNSQuestion *q);
-extern void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q);
-extern void mDNSPlatformLogToFile(int log_level, const char *buffer);
 extern mDNSBool SupportsInNICProxy(NetworkInterfaceInfo *const intf);
-extern mStatus SymptomReporterDNSServerReachable(mDNS *const m, const mDNSAddr *addr);
-extern mStatus SymptomReporterDNSServerUnreachable(DNSServer *s);
 #endif
 
 typedef void ProxyCallback (void *socket, DNSMessage *const msg, const mDNSu8 *const end, const mDNSAddr *const srcaddr,
@@ -3413,6 +3411,10 @@ extern void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mD
 extern mDNSs32 mDNSPlatformGetPID(void);
 extern mDNSBool mDNSValidKeepAliveRecord(AuthRecord *rr);
 extern mDNSBool CacheRecordRmvEventsForQuestion(mDNS *const m, DNSQuestion *q);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+extern void GetRandomUUIDLabel(domainlabel *label);
+extern void GetRandomUUIDLocalHostname(domainname *hostname);
+#endif
 
 // ***************************************************************************
 #if 0
@@ -3574,7 +3576,7 @@ typedef struct MD5state_st
     mDNSu32 A,B,C,D;
     mDNSu32 Nl,Nh;
     mDNSu32 data[MD5_BLOCK_LONG];
-    int num;
+    mDNSu32 num;
 } MD5_CTX;
 
 extern int MD5_Init(MD5_CTX *c);
@@ -3631,38 +3633,32 @@ struct CompileTimeAssertionChecks_mDNS
     // cause structure sizes (and therefore memory usage) to balloon unreasonably.
     char sizecheck_RDataBody           [(sizeof(RDataBody)            ==   264) ? 1 : -1];
     char sizecheck_ResourceRecord      [(sizeof(ResourceRecord)       <=    72) ? 1 : -1];
-    char sizecheck_AuthRecord          [(sizeof(AuthRecord)           <=  1208) ? 1 : -1];
+    char sizecheck_AuthRecord          [(sizeof(AuthRecord)           <=  1168) ? 1 : -1];
     char sizecheck_CacheRecord         [(sizeof(CacheRecord)          <=   232) ? 1 : -1];
     char sizecheck_CacheGroup          [(sizeof(CacheGroup)           <=   232) ? 1 : -1];
-    char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=  1168) ? 1 : -1];
+    char sizecheck_DNSQuestion         [(sizeof(DNSQuestion)          <=  1128) ? 1 : -1];
 
     char sizecheck_ZoneData            [(sizeof(ZoneData)             <=  2000) ? 1 : -1];
     char sizecheck_NATTraversalInfo    [(sizeof(NATTraversalInfo)     <=   200) ? 1 : -1];
     char sizecheck_HostnameInfo        [(sizeof(HostnameInfo)         <=  3050) ? 1 : -1];
-    char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   330) ? 1 : -1];
-    char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  8400) ? 1 : -1];
-    char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  5540) ? 1 : -1];
-    char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=  7888) ? 1 : -1];
+    char sizecheck_DNSServer           [(sizeof(DNSServer)            <=   328) ? 1 : -1];
+    char sizecheck_NetworkInterfaceInfo[(sizeof(NetworkInterfaceInfo) <=  8240) ? 1 : -1];
+    char sizecheck_ServiceRecordSet    [(sizeof(ServiceRecordSet)     <=  4728) ? 1 : -1];
+    char sizecheck_DomainAuthInfo      [(sizeof(DomainAuthInfo)       <=   944) ? 1 : -1];
 #if APPLE_OSX_mDNSResponder
     char sizecheck_ClientTunnel        [(sizeof(ClientTunnel)         <=  1512) ? 1 : -1];
 #endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+    // structure size is assumed by LogRedact routine.
+    char sizecheck_mDNSAddr            [(sizeof(mDNSAddr)             ==    20) ? 1 : -1];
+    char sizecheck_mDNSv4Addr          [(sizeof(mDNSv4Addr)           ==     4) ? 1 : -1];
+    char sizecheck_mDNSv6Addr          [(sizeof(mDNSv6Addr)           ==    16) ? 1 : -1];
+#endif
 };
 
 // Routine to initialize device-info TXT record contents
 mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr);
 
-#if APPLE_OSX_mDNSResponder
-extern void D2D_start_advertising_interface(NetworkInterfaceInfo *interface);
-extern void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface);
-extern void D2D_start_advertising_record(AuthRecord *ar);
-extern void D2D_stop_advertising_record(AuthRecord *ar);
-#else
-#define D2D_start_advertising_interface(X)
-#define D2D_stop_advertising_interface(X)
-#define D2D_start_advertising_record(X)
-#define D2D_stop_advertising_record(X)
-#endif
-
 // ***************************************************************************
 
 #ifdef __cplusplus
index 31cf1e959fda2debb94f2712b762833a246d42bf..8c782b550ca44a19655b2edb92bc2ea59d77130c 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2019 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.
@@ -66,7 +66,7 @@ mDNSlocal CacheRecord *NSECParentForQuestion(mDNS *const m, DNSQuestion *q)
         return mDNSNULL;
     }
     for (cr = cg->members; cr; cr = cr->next)
-        if (SameNameRecordAnswersQuestion(&cr->resrec, q))
+        if (SameNameCacheRecordAnswersQuestion(cr, q))
             return cr;
     return mDNSNULL;
 }
index 43cd37a8c102bed2c108f91960f80f58fd5fac09..4bacd5298ff5a3056b058cb43b6b98b594a116f1 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-2018 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.
 #include "nsec3.h"
 #include "nsec.h"
 
+// Base32 encoding takes 5 bytes of the input and encodes as 8 bytes of output.
+// For example, SHA-1 hash of 20 bytes will be encoded as 20/5 * 8 = 32 base32
+// bytes. For a max domain name size of 255 bytes of base32 encoding : (255/8)*5
+// is the max hash length possible.
+#define NSEC3_MAX_HASH_LEN  155
+// In NSEC3, the names are hashed and stored in the first label and hence cannot exceed label
+// size.
+#define NSEC3_MAX_B32_LEN   MAX_DOMAIN_LABEL
+
 // Define DNSSEC_DISABLED to remove all the DNSSEC functionality
 // and use the stub functions implemented later in this file.
 
@@ -160,6 +169,54 @@ mDNSlocal mDNSBool NSEC3CoversName(mDNS *const m, CacheRecord *ncr, const mDNSu8
     return mDNSfalse;
 }
 
+mDNSlocal const mDNSu8 *NSEC3HashName(const domainname *name, rdataNSEC3 *nsec3, const mDNSu8 hash[NSEC3_MAX_HASH_LEN], int *dlen)
+{
+    AlgContext *ctx;
+    unsigned int i;
+    unsigned int iterations;
+    domainname lname;
+    mDNSu8 *p = (mDNSu8 *)&nsec3->salt;
+    const mDNSu8 *digest;
+    int digestlen;
+    mDNSBool first = mDNStrue;
+
+    if (DNSNameToLowerCase((domainname *)name, &lname) != mStatus_NoError)
+    {
+        LogMsg("NSEC3HashName: ERROR!! DNSNameToLowerCase failed");
+        return mDNSNULL;
+    }
+
+    digest = lname.c;
+    digestlen = DomainNameLength(&lname);
+
+    // Note that it is "i <=". The first iteration is for digesting the name and salt.
+    // The iteration count does not include that.
+    iterations = swap16(nsec3->iterations);
+    for (i = 0; i <= iterations; i++)
+    {
+        ctx = AlgCreate(DIGEST_ALG, nsec3->alg);
+        if (!ctx)
+        {
+            LogMsg("NSEC3HashName: ERROR!! Cannot allocate context");
+            return mDNSNULL;
+        }
+
+        AlgAdd(ctx, digest, digestlen);
+        if (nsec3->saltLength)
+            AlgAdd(ctx, p, nsec3->saltLength);
+        if (first)
+        {
+            first = mDNSfalse;
+            digest = hash;
+            digestlen = AlgLength(ctx);
+        }
+        AlgFinal(ctx, (void *)digest, digestlen);
+        AlgDestroy(ctx);
+    }
+    *dlen = digestlen;
+    return digest;
+}
+
 // This function can be called with NSEC3ClosestEncloser, NSEC3Covers and NSEC3CEProof
 //
 // Passing in NSEC3ClosestEncloser means "find an exact match for the origName".
@@ -236,7 +293,7 @@ mDNSlocal mDNSBool NSEC3Find(mDNS *const m, NSEC3FindValues val, CacheRecord *nc
         int b32len;
 
         name = SkipLeadingLabels(origName, i);
-        if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
+        if (!NSEC3HashName(name, nsec3, hashName, &hlen))
         {
             LogMsg("NSEC3Find: NSEC3HashName failed for %##s", name->c);
             continue;
@@ -705,7 +762,7 @@ mDNSexport CacheRecord *NSEC3RecordIsDelegation(mDNS *const m, domainname *name,
 
             nsec3 = (rdataNSEC3 *)rdb->data;
 
-            if (!NSEC3HashName(name, nsec3, mDNSNULL, 0, hashName, &hlen))
+            if (!NSEC3HashName(name, nsec3, hashName, &hlen))
             {
                 LogMsg("NSEC3RecordIsDelegation: NSEC3HashName failed for %##s", name->c);
                 return mDNSNULL;
index 6214c262e4ef487fdd7b4418fc4e149fd7a1d5c0..7a4d9e6c170c2327106c4469f6c5e300a55bd31f 100755 (executable)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2017 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
  * Any dynamic run-time requirements should be handled by the platform layer below or client layer above
  */
 
-#if APPLE_OSX_mDNSResponder
-#include <TargetConditionals.h>
-#endif
 #include "uDNS.h"
 
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
 #include "Metrics.h"
 #endif
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+#include "SymptomReporter.h"
+#endif
+
 #if (defined(_MSC_VER))
 // Disable "assignment within conditional expression".
 // Other compilers understand the convention that if you place the assignment expression within an extra pair
@@ -48,16 +48,14 @@ mDNSexport SearchListElem *SearchList = mDNSNULL;
 // The value can be set to true by the Platform code e.g., MacOSX uses the plist mechanism
 mDNSBool StrictUnicastOrdering = mDNSfalse;
 
+extern mDNS mDNSStorage;
+
 // We keep track of the number of unicast DNS servers and log a message when we exceed 64.
 // Currently the unicast queries maintain a 128 bit map to track the valid DNS servers for that
 // question. Bit position is the index into the DNS server list. This is done so to try all
 // the servers exactly once before giving up. If we could allocate memory in the core, then
 // arbitrary limitation of 128 DNSServers can be removed.
-int NumUnicastDNSServers = 0;
 #define MAX_UNICAST_DNS_SERVERS 128
-#if APPLE_OSX_mDNSResponder
-mDNSu8 NumUnreachableDNSServers = 0;
-#endif
 
 #define SetNextuDNSEvent(m, rr) { \
         if ((m)->NextuDNSEvent - ((rr)->LastAPTime + (rr)->ThisAPInterval) >= 0)                                                                              \
@@ -115,115 +113,117 @@ mDNSlocal void SetRecordRetry(mDNS *const m, AuthRecord *rr, mDNSu32 random)
 #pragma mark - Name Server List Management
 #endif
 
-#define TrueFalseStr(X) ((X) ? "true" : "false")
-
-mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
-                                        const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isCLAT46,
-                                        mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *domain, const mDNSInterfaceID interface,
+    const mDNSs32 serviceID, const mDNSAddr *addr, const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout,
+    mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46, mDNSu32 resGroupID,
+    mDNSBool usableA, mDNSBool usableAAAA, mDNSBool reqDO)
 {
     DNSServer **p;
     DNSServer *server;
-
-    if ((NumUnicastDNSServers + 1) > MAX_UNICAST_DNS_SERVERS)
+    int       dnsCount = CountOfUnicastDNSServers(m);
+    if (dnsCount >= MAX_UNICAST_DNS_SERVERS)
     {
-        LogMsg("mDNS_AddDNSServer: DNS server limit of %d reached, not adding this server", MAX_UNICAST_DNS_SERVERS);
+        LogMsg("mDNS_AddDNSServer: DNS server count of %d reached, not adding this server", dnsCount);
         return mDNSNULL;
     }
 
-    if (!d)
-        d = (const domainname *)"";
+    if (!domain) domain = (const domainname *)"";
 
-    LogInfo("mDNS_AddDNSServer(%d): Adding %#a for %##s, InterfaceID %p, serviceID %u, scopeType %d, resGroupID %d req_A %s, req_AAAA %s, cell %s, expensive %s, CLAT46 %s, req_DO %s",
-        NumUnicastDNSServers, addr, d->c, interface, serviceID, (int)scopeType, resGroupID,
-        TrueFalseStr(reqA), TrueFalseStr(reqAAAA), TrueFalseStr(isCell), TrueFalseStr(isExpensive), TrueFalseStr(isCLAT46), TrueFalseStr(reqDO));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+        "mDNS_AddDNSServer(%d): Adding " PRI_IP_ADDR " for " PRI_DM_NAME " interface " PUB_S " (%p), serviceID %u, "
+        "scopeType %d, resGroupID %u" PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S,
+        dnsCount + 1, addr, DM_NAME_PARAM(domain), InterfaceNameForID(&mDNSStorage, interface), interface, serviceID,
+        (int)scopeType, resGroupID,
+        usableA       ? ", usableA"     : "",
+        usableAAAA    ? ", usableAAAA"  : "",
+        isCell        ? ", cell"        : "",
+        isExpensive   ? ", expensive"   : "",
+        isConstrained ? ", constrained" : "",
+        isCLAT46      ? ", CLAT46"      : "",
+        reqDO         ? ", reqDO"       : "");
 
     mDNS_CheckLock(m);
 
+    // Scan our existing list to see if we already have a matching record for this DNS resolver
     for (p = &m->DNSServers; (server = *p) != mDNSNULL; p = &server->next)
     {
-        if ((server->scopeType     == scopeType)     &&
-            (server->interface     == interface)     &&
-            (server->serviceID     == serviceID)     &&
-            mDNSSameAddress(&server->addr, addr)     &&
-            mDNSSameIPPort(server->port, port)       &&
-            (server->timeout       == timeout)       &&
-            (!!server->isCell      == !!isCell)      &&
-            (!!server->isExpensive == !!isExpensive) &&
-            (!!server->isCLAT46    == !!isCLAT46)    &&
-            (!!server->req_A       == !!reqA)        &&
-            (!!server->req_AAAA    == !!reqAAAA)     &&
-            (!!server->req_DO      == !!reqDO)       &&
-            SameDomainName(&server->domain, d))
-        {
-            if (!(server->flags & DNSServer_FlagDelete))
-                debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once", addr, mDNSVal16(port), d->c, interface);
-            *p = server->next;
-            server->next = mDNSNULL;
-            break;
-        }
+        if (server->interface       != interface)       continue;
+        if (server->serviceID       != serviceID)       continue;
+        if (!mDNSSameAddress(&server->addr, addr))      continue;
+        if (!mDNSSameIPPort(server->port, port))        continue;
+        if (!SameDomainName(&server->domain, domain))   continue;
+        if (server->scopeType       != scopeType)       continue;
+        if (server->timeout         != timeout)         continue;
+        if (!server->usableA        != !usableA)        continue;
+        if (!server->usableAAAA     != !usableAAAA)     continue;
+        if (!server->isCell         != !isCell)         continue;
+        if (!server->req_DO         != !reqDO)          continue;
+        if (!(server->flags & DNSServerFlag_Delete))
+        {
+            debugf("Note: DNS Server %#a:%d for domain %##s (%p) registered more than once",
+                addr, mDNSVal16(port), domain->c, interface);
+        }
+        // If we found a matching record, cut it from the list
+        // (and if we’re *not* resurrecting a record that was marked for deletion, it’s a duplicate,
+        // and the debugf message signifies that we’re collapsing duplicate entries into one)
+        *p = server->next;
+        server->next = mDNSNULL;
+        break;
     }
+
+    // If we broke out because we found an existing matching record, advance our pointer to the end of the list
     while (*p)
     {
         p = &(*p)->next;
     }
 
-    // NumUnicastDNSServers is the count of active DNS servers i.e., ones that are not marked
-    // with DNSServer_FlagDelete. We should increment it:
-    //
-    // 1) When we add a new DNS server
-    // 2) When we resurrect a old DNS server that is marked with DNSServer_FlagDelete
-    //
-    // Don't increment when we resurrect a DNS server that is not marked with DNSServer_FlagDelete.
-    // We have already accounted for it when it was added for the first time. This case happens when
-    // we add DNS servers with the same address multiple times (mis-configuration).
-
-    if (!server || (server->flags & DNSServer_FlagDelete))
-        NumUnicastDNSServers++;
-
     if (server)
     {
-        if (server->flags & DNSServer_FlagDelete)
+        if (server->flags & DNSServerFlag_Delete)
         {
-#if APPLE_OSX_mDNSResponder
-            server->flags &= ~DNSServer_FlagUnreachable;
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
+            server->flags &= ~DNSServerFlag_Unreachable;
 #endif
-            server->flags &= ~DNSServer_FlagDelete;
+            server->flags &= ~DNSServerFlag_Delete;
         }
-        *p = server; // move to end of list, to ensure ordering from platform layer
+        server->isExpensive   = isExpensive;
+        server->isConstrained = isConstrained;
+        server->isCLAT46      = isCLAT46;
+        *p = server;    // Append resurrected record at end of list
     }
     else
     {
-        // allocate, add to list
-        server = (DNSServer *)mDNSPlatformMemAllocateClear(sizeof(*server));
+        server = (DNSServer *) mDNSPlatformMemAllocateClear(sizeof(*server));
         if (!server)
         {
             LogMsg("Error: mDNS_AddDNSServer - malloc");
         }
         else
         {
-            server->scopeType   = scopeType;
-            server->interface   = interface;
-            server->serviceID   = serviceID;
-            server->addr        = *addr;
-            server->port        = port;
-            server->flags       = DNSServer_FlagNew;
-            server->timeout     = timeout;
-            server->isCell      = isCell;
-            server->isExpensive = isExpensive;
-            server->isCLAT46    = isCLAT46;
-            server->req_A       = reqA;
-            server->req_AAAA    = reqAAAA;
-            server->req_DO      = reqDO;
+            server->interface     = interface;
+            server->serviceID     = serviceID;
+            server->addr          = *addr;
+            server->port          = port;
+            server->scopeType     = scopeType;
+            server->timeout       = timeout;
+            server->usableA       = usableA;
+            server->usableAAAA    = usableAAAA;
+            server->isCell        = isCell;
+            server->isExpensive   = isExpensive;
+            server->isConstrained = isConstrained;
+            server->isCLAT46      = isCLAT46;
+            server->req_DO        = reqDO;
             // We start off assuming that the DNS server is not DNSSEC aware and
             // when we receive the first response to a DNSSEC question, we set
             // it to true.
             server->DNSSECAware = mDNSfalse;
             server->retransDO = 0;
-            AssignDomainName(&server->domain, d);
-            *p = server;
+            AssignDomainName(&server->domain, domain);
+            *p = server; // Append new record at end of list
         }
     }
-    if (server) {
+    if (server)
+    {
         server->penaltyTime = 0;
         // We always update the ID (not just when we allocate a new instance) because we want
         // all the resGroupIDs for a particular domain to match.
@@ -243,8 +243,9 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
 
     mDNS_CheckLock(m);
 
-    LogInfo("PenalizeDNSServer: Penalizing DNS server %#a question for question %p %##s (%s) SuppressUnusable %d",
-            (q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL), q, q->qname.c, DNSTypeName(q->qtype), q->SuppressUnusable);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+              "PenalizeDNSServer: Penalizing DNS server " PRI_IP_ADDR " question for question %p " PRI_DM_NAME " (" PUB_S ") SuppressUnusable %d",
+              (q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), q->SuppressUnusable);
 
     // If we get error from any DNS server, remember the error. If all of the servers,
     // return the error, then return the first error. 
@@ -267,27 +268,28 @@ mDNSexport void PenalizeDNSServer(mDNS *const m, DNSQuestion *q, mDNSOpaque16 re
 
     if (!StrictUnicastOrdering)
     {
-        LogInfo("PenalizeDNSServer: Strict Unicast Ordering is FALSE");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Strict Unicast Ordering is FALSE");
         // We penalize the server so that new queries don't pick this server for DNSSERVER_PENALTY_TIME
         // XXX Include other logic here to see if this server should really be penalized
         //
         if (q->qtype == kDNSType_PTR)
         {
-            LogInfo("PenalizeDNSServer: Not Penalizing PTR question");
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Not Penalizing PTR question");
         }
         else if ((rcode == kDNSFlag1_RC_FormErr) || (rcode == kDNSFlag1_RC_ServFail) || (rcode == kDNSFlag1_RC_NotImpl) || (rcode == kDNSFlag1_RC_Refused))
         {
-            LogInfo("PenalizeDNSServer: Not Penalizing DNS Server since it at least responded with rcode %d", rcode);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                      "PenalizeDNSServer: Not Penalizing DNS Server since it at least responded with rcode %d", rcode);
         }
         else
         {
-            LogInfo("PenalizeDNSServer: Penalizing question type %d", q->qtype);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: Penalizing question type %d", q->qtype);
             q->qDNSServer->penaltyTime = NonZeroTime(m->timenow + DNSSERVER_PENALTY_TIME);
         }
     }
     else
     {
-        LogInfo("PenalizeDNSServer: Strict Unicast Ordering is TRUE");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "PenalizeDNSServer: Strict Unicast Ordering is TRUE");
     }
 
 end:
@@ -297,8 +299,9 @@ end:
     {
         if (new)
         {
-            LogMsg("PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server %#a:%d", &new->addr,
-                   mDNSVal16(new->port));
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                      "PenalizeDNSServer: ERROR!! GetServerForQuestion returned the same server " PRI_IP_ADDR ":%d",
+                      &new->addr, mDNSVal16(new->port));
             q->ThisQInterval = 0;   // Inactivate this question so that we dont bombard the network
         }
         else
@@ -308,7 +311,7 @@ end:
             // is slow in responding and we have sent three queries. When we repeatedly call, it is
             // okay to receive the same NULL DNS server. Next time we try to send the query, we will
             // realize and re-initialize the DNS servers.
-            LogInfo("PenalizeDNSServer: GetServerForQuestion returned the same server NULL");
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "PenalizeDNSServer: GetServerForQuestion returned the same server NULL");
         }
     }
     else
@@ -318,8 +321,9 @@ end:
 
         if (new)
         {
-            LogInfo("PenalizeDNSServer: Server for %##s (%s) changed to %#a:%d (%##s)",
-                    q->qname.c, DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qDNSServer->domain.c);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                      "PenalizeDNSServer: Server for " PRI_DM_NAME " (" PUB_S ") changed to " PRI_IP_ADDR ":%d (" PRI_DM_NAME ")",
+                      DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), DM_NAME_PARAM(q->qDNSServer->domain.c));
             // We want to try the next server immediately. As the question may already have backed off, reset
             // the interval. We do this only the first time when we try all the DNS servers. Once we reached the end of
             // list and retrying all the servers again e.g., at least one server failed to respond in the previous try, we
@@ -347,7 +351,9 @@ end:
             // the next query will not happen until cache expiry. If it is a long lived question,
             // AnswerCurrentQuestionWithResourceRecord will not set it to MaxQuestionInterval. In that case,
             // we want the normal backoff to work.
-            LogInfo("PenalizeDNSServer: Server for %p, %##s (%s) changed to NULL, Interval %d", q, q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                      "PenalizeDNSServer: Server for %p, " PRI_DM_NAME " (" PUB_S ") changed to NULL, Interval %d",
+                      q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), q->ThisQInterval);
         }
         q->unansweredQueries = 0;
 
@@ -387,7 +393,7 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName_internal(mDNS *m, const domainname
     // First purge any dead keys from the list
     while (*p)
     {
-        if ((*p)->deltime && m->timenow - (*p)->deltime >= 0 && AutoTunnelUnregistered(*p))
+        if ((*p)->deltime && m->timenow - (*p)->deltime >= 0)
         {
             DNSQuestion *q;
             DomainAuthInfo *info = *p;
@@ -425,15 +431,14 @@ mDNSexport DomainAuthInfo *GetAuthInfoForName(mDNS *m, const domainname *const n
 
 // MUST be called with the lock held
 mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
-                                           const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
+                                           const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
 {
     DNSQuestion *q;
     DomainAuthInfo **p = &m->AuthInfoList;
     if (!info || !b64keydata) { LogMsg("mDNS_SetSecretForDomain: ERROR: info %p b64keydata %p", info, b64keydata); return(mStatus_BadParamErr); }
 
-    LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s%s", domain->c, keyname->c, autoTunnel ? " AutoTunnel" : "");
+    LogInfo("mDNS_SetSecretForDomain: domain %##s key %##s", domain->c, keyname->c);
 
-    info->AutoTunnel = autoTunnel;
     AssignDomainName(&info->domain,  domain);
     AssignDomainName(&info->keyname, keyname);
     if (hostname)
@@ -458,16 +463,6 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info,
     while (*p && (*p) != info) p=&(*p)->next;
     if (*p) {LogInfo("mDNS_SetSecretForDomain: Domain %##s Already in list", (*p)->domain.c); return(mStatus_AlreadyRegistered);}
 
-    // Caution: Only zero AutoTunnelHostRecord.namestorage AFTER we've determined that this is a NEW DomainAuthInfo
-    // being added to the list. Otherwise we risk smashing our AutoTunnel host records 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->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeUnregistered;
-    info->AutoTunnelServiceStarted = mDNSfalse;
-    info->AutoTunnelInnerAddress = zerov6Addr;
     info->next = mDNSNULL;
     *p = info;
 
@@ -1013,9 +1008,6 @@ mDNSlocal void StartLLQPolling(mDNS *const m, DNSQuestion *q)
     // we risk causing spurious "SendQueries didn't send all its queries" log messages
     q->LastQTime     = m->timenow - q->ThisQInterval + 1;
     SetNextQueryTime(m, q);
-#if APPLE_OSX_mDNSResponder
-    UpdateAutoTunnelDomainStatuses(m);
-#endif
 }
 
 mDNSlocal mDNSu8 *putLLQ(DNSMessage *const msg, mDNSu8 *ptr, const DNSQuestion *const question, const LLQOptData *const data)
@@ -1071,8 +1063,6 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
 
     if (q->tcp) { LogMsg("sendChallengeResponse: ERROR!!: question %##s (%s) tcp non-NULL", q->qname.c, DNSTypeName(q->qtype)); return; }
 
-    if (PrivateQuery(q)) { LogMsg("sendChallengeResponse: ERROR!!: Private Query %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-
     if (q->ntries++ == kLLQ_MAX_TRIES)
     {
         LogMsg("sendChallengeResponse: %d failed attempts for LLQ %##s", kLLQ_MAX_TRIES, q->qname.c);
@@ -1101,7 +1091,7 @@ mDNSlocal void sendChallengeResponse(mDNS *const m, DNSQuestion *const q, const
     responsePtr = putLLQ(&m->omsg, responsePtr, q, llq);
     if (responsePtr)
     {
-        mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL, mDNSfalse);
+        mStatus err = mDNSSendDNSMessage(m, &m->omsg, responsePtr, mDNSInterface_Any, mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSfalse);
         if (err) { LogMsg("sendChallengeResponse: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err); }
     }
     else StartLLQPolling(m,q);
@@ -1150,27 +1140,12 @@ mDNSlocal void recvSetupResponse(mDNS *const m, mDNSu8 rcode, DNSQuestion *const
     }
     else if (q->state == LLQ_SecondaryRequest)
     {
-        //LogInfo("Got LLQ_SecondaryRequest");
-
-        // Fix this immediately if not sooner.  Copy the id from the LLQOptData into our DNSQuestion struct.  This is only
-        // an issue for private LLQs, because we skip parts 2 and 3 of the handshake.  This is related to a bigger
-        // 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 (PrivateQuery(q))
-        {
-            LogInfo("Private LLQ_SecondaryRequest; copying id %08X%08X", llq->id.l[0], llq->id.l[1]);
-            q->id = llq->id;
-        }
-
         if (llq->err) { LogMsg("ERROR: recvSetupResponse %##s (%s) code %d from server", q->qname.c, DNSTypeName(q->qtype), llq->err); StartLLQPolling(m,q); return; }
         if (!mDNSSameOpaque64(&q->id, &llq->id))
         { LogMsg("recvSetupResponse - ID changed.  discarding"); return; }     // this can happen rarely (on packet loss + reordering)
         q->state         = LLQ_Established;
         q->ntries        = 0;
         SetLLQTimer(m, q, llq);
-#if APPLE_OSX_mDNSResponder
-        UpdateAutoTunnelDomainStatuses(m);
-#endif
     }
 }
 
@@ -1226,7 +1201,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
                     //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, q, &opt->u.llq);
-                    if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSNULL, mDNSfalse);
+                    if (ackEnd) mDNSSendDNSMessage(m, &m->omsg, ackEnd, mDNSInterface_Any, mDNSNULL, q->LocalSocket, srcaddr, srcport, mDNSNULL, mDNSfalse);
                     m->rec.r.resrec.RecordType = 0;     // Clear RecordType to show we're not still using it
                     debugf("uDNS_LLQ_Events: q->state == LLQ_Established msg->h.id %d q->TargetQID %d", mDNSVal16(msg->h.id), mDNSVal16(q->TargetQID));
                     *matchQuestion = q;
@@ -1276,7 +1251,7 @@ mDNSexport uDNS_LLQType uDNS_recvLLQResponse(mDNS *const m, const DNSMessage *co
 }
 
 // Stub definition of TCPSocket_struct so we can access flags field. (Rest of TCPSocket_struct is platform-dependent.)
-struct TCPSocket_struct { TCPSocketFlags flags; /* ... */ };
+struct TCPSocket_struct { mDNSIPPort port; TCPSocketFlags flags; /* ... */ };
 
 // 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
@@ -1350,9 +1325,9 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
             AuthInfo = q->AuthInfo;     // Need to add TSIG to this message
         }
 
-        err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, sock, AuthInfo, mDNSfalse);
+        err = mDNSSendDNSMessage(m, &tcpInfo->request, end, mDNSInterface_Any, sock, mDNSNULL, &tcpInfo->Addr, tcpInfo->Port, AuthInfo, mDNSfalse);
         if (err) { debugf("ERROR: tcpCallback: mDNSSendDNSMessage - %d", err); err = mStatus_UnknownErr; goto exit; }
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
         if (mDNSSameIPPort(tcpInfo->Port, UnicastDNSPort))
         {
             MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&tcpInfo->request));
@@ -1414,7 +1389,7 @@ mDNSlocal void tcpCallback(TCPSocket *sock, void *context, mDNSBool ConnectionEs
             if (tcpInfo->replylen < sizeof(DNSMessageHeader))
             { LogMsg("ERROR: tcpCallback - length too short (%d bytes)", tcpInfo->replylen); err = mStatus_UnknownErr; goto exit; }
 
-            tcpInfo->reply = mDNSPlatformMemAllocate(tcpInfo->replylen);
+            tcpInfo->reply = (DNSMessage *) mDNSPlatformMemAllocate(tcpInfo->replylen);
             if (!tcpInfo->reply) { LogMsg("ERROR: tcpCallback - malloc failed"); err = mStatus_NoMemoryErr; goto exit; }
         }
 
@@ -1574,17 +1549,16 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
     tcpInfo_t *info;
     mDNSBool useBackgroundTrafficClass;
 
-    useBackgroundTrafficClass = question ? question->UseBackgroundTrafficClass : mDNSfalse;
+    useBackgroundTrafficClass = question ? question->UseBackgroundTraffic : mDNSfalse;
 
     if ((flags & kTCPSocketFlags_UseTLS) && (!hostname || !hostname->c[0]))
     { LogMsg("MakeTCPConn: TLS connection being setup with NULL hostname"); return mDNSNULL; }
 
-    info = (tcpInfo_t *)mDNSPlatformMemAllocate(sizeof(tcpInfo_t));
+    info = (tcpInfo_t *) mDNSPlatformMemAllocateClear(sizeof(*info));
     if (!info) { LogMsg("ERROR: MakeTCP - memallocate failed"); return(mDNSNULL); }
-    mDNSPlatformMemZero(info, sizeof(tcpInfo_t));
 
     info->m          = m;
-    info->sock       = mDNSPlatformTCPSocket(flags, &srcport, useBackgroundTrafficClass);
+    info->sock       = mDNSPlatformTCPSocket(flags, Addr->type, &srcport, hostname, useBackgroundTrafficClass);
     info->requestLen = 0;
     info->question   = question;
     info->rr         = rr;
@@ -1604,7 +1578,7 @@ mDNSlocal tcpInfo_t *MakeTCPConn(mDNS *const m, const DNSMessage *const msg, con
 
     if (!info->sock) { LogMsg("MakeTCPConn: unable to create TCP socket"); mDNSPlatformMemFree(info); return(mDNSNULL); }
     mDNSPlatformSetSocktOpt(info->sock, mDNSTransport_TCP, Addr->type, question);
-    err = mDNSPlatformTCPConnect(info->sock, Addr, Port, hostname, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
+    err = mDNSPlatformTCPConnect(info->sock, Addr, Port, (question ? question->InterfaceID : mDNSNULL), tcpCallback, info);
 
     // Probably suboptimal here.
     // Instead of returning mDNSNULL here on failure, we should probably invoke the callback with an error code.
@@ -1628,6 +1602,16 @@ mDNSexport void DisposeTCPConn(struct tcpInfo_t *tcp)
 // Lock must be held
 mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
 {
+    // States prior to LLQ_InitialRequest should not react to NAT Mapping changes.
+    // startLLQHandshake is never called with q->state < LLQ_InitialRequest except
+    // from LLQNATCallback.   When we are actually trying to do LLQ, then q->state will
+    // be equal to or greater than LLQ_InitialRequest when LLQNATCallback calls
+    // startLLQHandshake.
+    if (q->state < LLQ_InitialRequest)
+    {
+        return;
+    }
+
     if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
     {
         LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
@@ -1660,77 +1644,40 @@ mDNSexport void startLLQHandshake(mDNS *m, DNSQuestion *q)
         return;
     }
 
-    if (PrivateQuery(q))
+    debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
+           &m->AdvertisedV4,                     mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
+           &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr)             ? " (RFC 1918)" : "",
+           q->qname.c, DNSTypeName(q->qtype));
+
+    if (q->ntries++ >= kLLQ_MAX_TRIES)
     {
-        if (q->tcp) LogInfo("startLLQHandshake: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
-        if (!q->nta)
-        {
-            // Normally we lookup the zone data and then call this function. And we never free the zone data
-            // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
-            // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
-            // When we poll, we free the zone information as we send the query to the server (See
-            // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
-            // are still behind Double NAT, we would have returned early in this function. But we could
-            // have switched to a network with no NATs and we should get the zone data again.
-            LogInfo("startLLQHandshake: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-            q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
-            return;
-        }
-        else if (!q->nta->Host.c[0])
-        {
-            // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
-            LogMsg("startLLQHandshake: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
-        }
-        q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
-        if (!q->tcp)
-            q->ThisQInterval = mDNSPlatformOneSecond * 5;   // If TCP failed (transient networking glitch) try again in five seconds
-        else
-        {
-            q->state         = LLQ_SecondaryRequest;        // Right now, for private DNS, we skip the four-way LLQ handshake
-            q->ReqLease      = kLLQ_DefLease;
-            q->ThisQInterval = 0;
-        }
-        q->LastQTime     = m->timenow;
-        SetNextQueryTime(m, q);
+        LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
+        StartLLQPolling(m, q);
     }
     else
     {
-        debugf("startLLQHandshake: m->AdvertisedV4 %#a%s Server %#a:%d%s %##s (%s)",
-               &m->AdvertisedV4,                     mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) ? " (RFC 1918)" : "",
-               &q->servAddr, mDNSVal16(q->servPort), mDNSAddrIsRFC1918(&q->servAddr)             ? " (RFC 1918)" : "",
-               q->qname.c, DNSTypeName(q->qtype));
-
-        if (q->ntries++ >= kLLQ_MAX_TRIES)
-        {
-            LogMsg("startLLQHandshake: %d failed attempts for LLQ %##s Polling.", kLLQ_MAX_TRIES, q->qname.c);
-            StartLLQPolling(m, q);
-        }
-        else
-        {
-            mDNSu8 *end;
-            LLQOptData llqData;
+        mDNSu8 *end;
+        LLQOptData llqData;
 
-            // set llq rdata
-            llqData.vers  = kLLQ_Vers;
-            llqData.llqOp = kLLQOp_Setup;
-            llqData.err   = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
-            llqData.id    = zeroOpaque64;
-            llqData.llqlease = kLLQ_DefLease;
+        // set llq rdata
+        llqData.vers  = kLLQ_Vers;
+        llqData.llqOp = kLLQOp_Setup;
+        llqData.err   = LLQErr_NoError; // Don't need to tell server UDP notification port when sending over UDP
+        llqData.id    = zeroOpaque64;
+        llqData.llqlease = kLLQ_DefLease;
 
-            InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
-            end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
-            if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
+        InitializeDNSMessage(&m->omsg.h, q->TargetQID, uQueryFlags);
+        end = putLLQ(&m->omsg, m->omsg.data, q, &llqData);
+        if (!end) { LogMsg("ERROR: startLLQHandshake - putLLQ"); StartLLQPolling(m,q); return; }
 
-            mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSNULL, mDNSfalse);
+        mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort , mDNSNULL, mDNSfalse);
 
-            // update question state
-            q->state         = LLQ_InitialRequest;
-            q->ReqLease      = kLLQ_DefLease;
-            q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
-            q->LastQTime     = m->timenow;
-            SetNextQueryTime(m, q);
-        }
+        // update question state
+        q->state         = LLQ_InitialRequest;
+        q->ReqLease      = kLLQ_DefLease;
+        q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
+        q->LastQTime     = m->timenow;
+        SetNextQueryTime(m, q);
     }
 }
 
@@ -1746,17 +1693,6 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
         return(&rr->resrec.rdata->u.srv.target);
     else
     {
-#if APPLE_OSX_mDNSResponder
-        DomainAuthInfo *AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
-        if (AuthInfo && AuthInfo->AutoTunnel)
-        {
-            StartServerTunnel(AuthInfo);
-            if (AuthInfo->AutoTunnelHostRecord.namestorage.c[0] == 0) return(mDNSNULL);
-            debugf("GetServiceTarget: Returning %##s", AuthInfo->AutoTunnelHostRecord.namestorage.c);
-            return(&AuthInfo->AutoTunnelHostRecord.namestorage);
-        }
-        else
-#endif // APPLE_OSX_mDNSResponder
         {
             const int srvcount = CountLabels(rr->resrec.name);
             HostnameInfo *besthi = mDNSNULL, *hi;
@@ -1780,13 +1716,13 @@ mDNSexport const domainname *GetServiceTarget(mDNS *m, AuthRecord *const rr)
     }
 }
 
-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 *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";
-mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0C_dns-push-tls"    "\x04_tcp";
+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";
+mDNSlocal const domainname *DNS_PUSH_NOTIFICATION_SERVICE_TYPE = (const domainname*)"\x0D_dns-push-tls"   "\x04_tcp";
 
 #define ZoneDataSRV(X) ( \
         (X)->ZoneService == ZoneServiceUpdate  ? ((X)->ZonePrivate ? PRIVATE_UPDATE_SERVICE_TYPE : PUBLIC_UPDATE_SERVICE_TYPE) : \
@@ -1819,25 +1755,13 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
         {
             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])
         {
-            DomainAuthInfo *AuthInfo = GetAuthInfoForName(m, zd->CurrentSOA);
-            if (AuthInfo && AuthInfo->AutoTunnel)
-            {
-                // To keep the load on the server down, we don't chop down on
-                // SOA lookups for AutoTunnels
-                LogInfo("GetZoneData_QuestionCallback: not chopping labels for %##s", zd->CurrentSOA->c);
-                zd->ZoneDataCallback(m, mStatus_NoSuchNameErr, zd);
-            }
-            else
-            {
-                zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
-                AssignDomainName(&zd->question.qname, zd->CurrentSOA);
-                GetZoneData_StartQuery(m, zd, kDNSType_SOA);
-            }
+            zd->CurrentSOA = (domainname *)(zd->CurrentSOA->c + zd->CurrentSOA->c[0]+1);
+            AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+            GetZoneData_StartQuery(m, zd, kDNSType_SOA);
         }
         else
         {
@@ -1867,8 +1791,37 @@ mDNSlocal void GetZoneData_QuestionCallback(mDNS *const m, DNSQuestion *question
             {
                 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);
+                // The MakeTCPConn path, which is used by everything but DNS Push, won't work at all for
+                // IPv6.  This should be fixed for all cases we care about, but for now we make an exception
+                // for Push notifications: we do not look up the a record here, but rather rely on the DSO
+                // infrastructure to do a GetAddrInfo call on the name and try each IP address in sequence
+                // until one connects.  We can't do this for the other use cases because this is in the DSO
+                // code, not in MakeTCPConn.  Ultimately the fix for this is to use Network Framework to do
+                // the connection establishment for all of these use cases.
+                //
+                // One implication of this is that if two different zones have DNS push server SRV records
+                // pointing to the same server using a different domain name, we will not see these as being
+                // the same server, and will not share the connection.   This isn't something we can easily
+                // fix, and so the advice if someone runs into this and considers it a problem should be to
+                // use the same name.
+                //
+                // Another issue with this code is that at present, we do not wait for more than one SRV
+                // record--we cancel the query as soon as the first one comes in.   This isn't ideal: it
+                // would be better to wait until we've gotten all our answers and then pick the one with
+                // the highest priority.   Of course, this is unlikely to cause an operational problem in
+                // practice, and as with the previous point, the fix is easy: figure out which server you
+                // want people to use and don't list any other servers.   Fully switching to Network
+                // Framework for this would (I think!) address this problem, or at least make it someone
+                // else's problem.
+                if (zd->ZoneService != ZoneServiceDNSPush)
+                {
+                    AssignDomainName(&zd->question.qname, &zd->Host);
+                    GetZoneData_StartQuery(m, zd, kDNSType_A);
+                }
+                else
+                {
+                    zd->ZoneDataCallback(m, mStatus_NoError, zd);
+                }                    
             }
             else
             {
@@ -1919,7 +1872,6 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
     zd->question.ThisQInterval       = -1;
     zd->question.InterfaceID         = mDNSInterface_Any;
     zd->question.flags               = 0;
-    zd->question.Target              = zeroAddr;
     //zd->question.qname.c[0]        = 0;           // Already set
     zd->question.qtype               = qtype;
     zd->question.qclass              = kDNSClass_IN;
@@ -1928,17 +1880,13 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
     zd->question.ForceMCast          = mDNSfalse;
     zd->question.ReturnIntermed      = mDNStrue;
     zd->question.SuppressUnusable    = mDNSfalse;
-    zd->question.SearchListIndex     = 0;
     zd->question.AppendSearchDomains = 0;
-    zd->question.RetryWithSearchDomains = mDNSfalse;
     zd->question.TimeoutQuestion     = 0;
     zd->question.WakeOnResolve       = 0;
-    zd->question.UseBackgroundTrafficClass = mDNSfalse;
+    zd->question.UseBackgroundTraffic = mDNSfalse;
     zd->question.ValidationRequired = 0;
     zd->question.ValidatingResponse = 0;
     zd->question.ProxyQuestion      = 0;
-    zd->question.qnameOrig           = mDNSNULL;
-    zd->question.AnonInfo            = mDNSNULL;
     zd->question.pid                 = mDNSPlatformGetPID();
     zd->question.euid                = 0;
     zd->question.QuestionCallback    = GetZoneData_QuestionCallback;
@@ -1951,51 +1899,25 @@ mDNSlocal mStatus GetZoneData_StartQuery(mDNS *const m, ZoneData *zd, mDNSu16 qt
 // 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)
 {
-    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));
+    ZoneData *zd = (ZoneData*) mDNSPlatformMemAllocateClear(sizeof(*zd));
+    if (!zd) { LogMsg("ERROR: StartGetZoneData - mDNSPlatformMemAllocateClear failed"); return mDNSNULL; }
     AssignDomainName(&zd->ChildName, name);
     zd->ZoneService      = target;
-    zd->CurrentSOA       = (domainname *)(&zd->ChildName.c[initialskip]);
+    zd->CurrentSOA       = &zd->ChildName;
     zd->ZoneName.c[0]    = 0;
     zd->ZoneClass        = 0;
     zd->Host.c[0]        = 0;
     zd->Port             = zeroIPPort;
     zd->Addr             = zeroAddr;
-    zd->ZonePrivate      = AuthInfo && AuthInfo->AutoTunnel ? mDNStrue : mDNSfalse;
+    zd->ZonePrivate      = mDNSfalse;
     zd->ZoneDataCallback = callback;
     zd->ZoneDataContext  = ZoneDataContext;
 
     zd->question.QuestionContext = zd;
 
     mDNS_DropLockBeforeCallback();      // GetZoneData_StartQuery expects to be called from a normal callback, so we emulate that here
-    if (AuthInfo && AuthInfo->AutoTunnel && !mDNSIPPortIsZero(AuthInfo->port))
-    {
-        LogInfo("StartGetZoneData: Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
-        // We bypass SOA and SRV queries if we know the hostname and port already from the configuration.
-        // Today this is only true for AutoTunnel. As we bypass, we need to infer a few things:
-        //
-        // 1. Zone name is the same as the AuthInfo domain
-        // 2. ZoneClass is kDNSClass_IN which should be a safe assumption
-        //
-        // If we want to make this bypass mechanism work for non-AutoTunnels also, (1) has to hold
-        // good. Otherwise, it has to be configured also.
-
-        AssignDomainName(&zd->ZoneName, &AuthInfo->domain);
-        zd->ZoneClass = kDNSClass_IN;
-        AssignDomainName(&zd->Host, &AuthInfo->hostname);
-        zd->Port = AuthInfo->port;
-        AssignDomainName(&zd->question.qname, &zd->Host);
-        GetZoneData_StartQuery(m, zd, kDNSType_A);
-    }
-    else
-    {
-        if (AuthInfo && AuthInfo->AutoTunnel) LogInfo("StartGetZoneData: Not Bypassing SOA, SRV query for %##s", AuthInfo->domain.c);
-        AssignDomainName(&zd->question.qname, zd->CurrentSOA);
-        GetZoneData_StartQuery(m, zd, kDNSType_SOA);
-    }
+    AssignDomainName(&zd->question.qname, zd->CurrentSOA);
+    GetZoneData_StartQuery(m, zd, kDNSType_SOA);
     mDNS_ReclaimLockAfterCallback();
 
     return zd;
@@ -2338,6 +2260,7 @@ mDNSlocal void UpdateOneSRVRecord(mDNS *m, AuthRecord *rr)
 
     case regState_NATError:
         if (!NATChanged) return;
+        fallthrough();
     // if nat changed, register if we have a target (below)
 
     case regState_NoTarget:
@@ -2608,7 +2531,6 @@ mDNSlocal void GetStaticHostname(mDNS *m)
 
     q->InterfaceID      = mDNSInterface_Any;
     q->flags            = 0;
-    q->Target           = zeroAddr;
     q->qtype            = kDNSType_PTR;
     q->qclass           = kDNSClass_IN;
     q->LongLived        = mDNSfalse;
@@ -2616,17 +2538,13 @@ mDNSlocal void GetStaticHostname(mDNS *m)
     q->ForceMCast       = mDNSfalse;
     q->ReturnIntermed   = mDNStrue;
     q->SuppressUnusable = mDNSfalse;
-    q->SearchListIndex  = 0;
     q->AppendSearchDomains = 0;
-    q->RetryWithSearchDomains = mDNSfalse;
     q->TimeoutQuestion  = 0;
     q->WakeOnResolve    = 0;
-    q->UseBackgroundTrafficClass = mDNSfalse;
+    q->UseBackgroundTraffic = mDNSfalse;
     q->ValidationRequired = 0;
     q->ValidatingResponse = 0;
     q->ProxyQuestion      = 0;
-    q->qnameOrig        = mDNSNULL;
-    q->AnonInfo         = mDNSNULL;
     q->pid              = mDNSPlatformGetPID();
     q->euid             = 0;
     q->QuestionCallback = FoundStaticHostname;
@@ -2647,10 +2565,9 @@ mDNSexport void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSReco
     if (*ptr) { LogMsg("DynDNSHostName %##s already in list", fqdn->c); return; }
 
     // allocate and format new address record
-    *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
+    *ptr = (HostnameInfo *) mDNSPlatformMemAllocateClear(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;
@@ -2787,10 +2704,6 @@ mDNSexport void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr, co
         m->StaticHostname.c[0] = 0;
 
         m->NextSRVUpdate = NonZeroTime(m->timenow);
-
-#if APPLE_OSX_mDNSResponder
-        UpdateAutoTunnelDomainStatuses(m);
-#endif
     }
 
     mDNS_Unlock(m);
@@ -2897,23 +2810,14 @@ mDNSlocal mStatus checkUpdateResult(mDNS *const m, const domainname *const displ
     }
 }
 
-// We add three Additional Records for unicast resource record registrations
-// which is a function of AuthInfo and AutoTunnel properties
-mDNSlocal mDNSu32 RRAdditionalSize(mDNS *const m, DomainAuthInfo *AuthInfo)
+mDNSlocal mDNSu32 RRAdditionalSize(DomainAuthInfo *AuthInfo)
 {
-    mDNSu32 leaseSize, hinfoSize, tsigSize;
+    mDNSu32 leaseSize, tsigSize;
     mDNSu32 rr_base_size = 10; // type (2) class (2) TTL (4) rdlength (2)
 
     // OPT RR : Emptyname(.) + base size + rdataOPT
     leaseSize = 1 + rr_base_size + sizeof(rdataOPT);
 
-    // HINFO: Resource Record Name + base size + RDATA
-    // HINFO is added only for autotunnels
-    hinfoSize = 0;
-    if (AuthInfo && AuthInfo->AutoTunnel)
-        hinfoSize = (m->hostlabel.c[0] + 1) + DomainNameLength(&AuthInfo->domain) +
-                    rr_base_size + (2 + m->HIHardware.c[0] + m->HISoftware.c[0]);
-
     //TSIG: Resource Record Name + base size + RDATA
     // RDATA:
     //  Algorithm name: hmac-md5.sig-alg.reg.int (8+7+3+3 + 5 bytes for length = 26 bytes)
@@ -2928,7 +2832,7 @@ mDNSlocal mDNSu32 RRAdditionalSize(mDNS *const m, DomainAuthInfo *AuthInfo)
     tsigSize = 0;
     if (AuthInfo) tsigSize = DomainNameLength(&AuthInfo->keyname) + rr_base_size + 58;
 
-    return (leaseSize + hinfoSize + tsigSize);
+    return (leaseSize + tsigSize);
 }
 
 //Note: Make sure that RREstimatedSize is updated accordingly if anything that is done here
@@ -3010,7 +2914,7 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
     limit = ptr + AbsoluteMaxDNSMessageData;
 
     AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
-    limit -= RRAdditionalSize(m, AuthInfo);
+    limit -= RRAdditionalSize(AuthInfo);
 
     mDNS_CheckLock(m);
 
@@ -3047,7 +2951,7 @@ mDNSlocal void SendRecordRegistration(mDNS *const m, AuthRecord *rr)
     {
         LogInfo("SendRecordRegistration UDP %s", ARDisplayString(m, rr));
         if (!rr->nta) { LogMsg("SendRecordRegistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
-        err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
+        err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &rr->nta->Addr, rr->nta->Port, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
         if (err) debugf("ERROR: SendRecordRegistration - mDNSSendDNSMessage - %d", err);
     }
 
@@ -3140,8 +3044,7 @@ mDNSlocal void SendGroupRRMessage(mDNS *const m, AuthRecord *anchorRR, mDNSu8 *p
     mDNSu8 *limit;
     if (!anchorRR) {debugf("SendGroupRRMessage: Could not merge records"); return;}
 
-    if (info && info->AutoTunnel) limit = m->omsg.data + AbsoluteMaxDNSMessageData;
-    else limit = m->omsg.data + NormalMaxDNSMessageData;
+    limit = m->omsg.data + NormalMaxDNSMessageData;
 
     // This has to go in the additional section and hence need to be done last
     ptr = putUpdateLeaseWithLimit(&m->omsg, ptr, DEFAULT_UPDATE_LEASE, limit);
@@ -3163,7 +3066,7 @@ mDNSlocal void SendGroupRRMessage(mDNS *const m, AuthRecord *anchorRR, mDNSu8 *p
     }
     else
     {
-        mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, mDNSNULL, info, mDNSfalse);
+        mStatus err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &anchorRR->nta->Addr, anchorRR->nta->Port, info, mDNSfalse);
         if (err) LogInfo("SendGroupRRMessage: Cannot send UDP message for %s", ARDisplayString(m, anchorRR));
         else LogInfo("SendGroupRRMessage: Sent a group UDP update ID: %d start %p, end %p, limit %p", mDNSVal16(m->omsg.h.id), m->omsg.data, ptr, limit);
     }
@@ -3319,11 +3222,10 @@ mDNSlocal mDNSBool SendGroupUpdates(mDNS *const m)
                 // Though we allow single record registrations for UDP to be AbsoluteMaxDNSMessageData (See
                 // SendRecordRegistration) to handle large TXT records, to avoid fragmentation we limit UDP
                 // message to NormalMaxDNSMessageData
-                if (AuthInfo && AuthInfo->AutoTunnel) spaceleft = AbsoluteMaxDNSMessageData;
-                else spaceleft = NormalMaxDNSMessageData;
+                spaceleft = NormalMaxDNSMessageData;
 
                 next = m->omsg.data;
-                spaceleft -= RRAdditionalSize(m, AuthInfo);
+                spaceleft -= RRAdditionalSize(AuthInfo);
                 if (spaceleft <= 0)
                 {
                     LogMsg("SendGroupUpdates: ERROR!!: spaceleft is zero at the beginning");
@@ -3526,9 +3428,6 @@ mDNSlocal void hndlRecordUpdateReply(mDNS *m, AuthRecord *rr, mStatus err, mDNSu
     LogInfo("hndlRecordUpdateReply: err %d ID %d state %d %s(%p)", err, mDNSVal16(rr->updateid), rr->state, ARDisplayString(m, rr), rr);
 
     rr->updateError = err;
-#if APPLE_OSX_mDNSResponder
-    if (err == mStatus_BadSig || err == mStatus_BadKey || err == mStatus_BadTime) UpdateAutoTunnelDomainStatuses(m);
-#endif
 
     SetRecordRetry(m, rr, random);
 
@@ -3921,7 +3820,7 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
            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", end - msg->data);
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
     if (NumUnreachableDNSServers > 0)
         SymptomReporterDNSServerReachable(m, srcaddr);
 #endif
@@ -3933,7 +3832,13 @@ mDNSexport void uDNS_ReceiveMsg(mDNS *const m, DNSMessage *const msg, const mDNS
             if (msg->h.flags.b[0] & kDNSFlag0_TC && mDNSSameOpaque16(qptr->TargetQID, msg->h.id) && m->timenow - qptr->LastQTime < RESPONSE_WINDOW)
             {
                 if (!srcaddr) LogMsg("uDNS_ReceiveMsg: TCP DNS response had TC bit set: ignoring");
-                else          uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport);
+                else
+                {
+                    uDNS_RestartQuestionAsTCP(m, qptr, srcaddr, srcport);
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+                    qptr->metrics.dnsOverTCPState = DNSOverTCP_Truncated;
+#endif
+                }
             }
     }
 
@@ -3983,7 +3888,6 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
 {
     mDNSu8 *end;
     LLQOptData llq;
-    mDNSu8 *limit = m->omsg.data + AbsoluteMaxDNSMessageData;
 
     if (q->ReqLease)
         if ((q->state == LLQ_Established && q->ntries >= kLLQ_MAX_TRIES) || q->expire - m->timenow < 0)
@@ -4003,45 +3907,12 @@ mDNSexport void sendLLQRefresh(mDNS *m, DNSQuestion *q)
     end = putLLQ(&m->omsg, m->omsg.data, q, &llq);
     if (!end) { LogMsg("sendLLQRefresh: putLLQ failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
 
-    // Note that we (conditionally) add HINFO and TSIG here, since the question might be going away,
-    // so we may not be able to reference it (most importantly it's AuthInfo) when we actually send the message
-    end = putHINFO(m, &m->omsg, end, q->AuthInfo, limit);
-    if (!end) { LogMsg("sendLLQRefresh: putHINFO failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-
-    if (PrivateQuery(q))
-    {
-        DNSDigest_SignMessageHostByteOrder(&m->omsg, &end, q->AuthInfo);
-        if (!end) { LogMsg("sendLLQRefresh: DNSDigest_SignMessage failed %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-    }
-
-    if (PrivateQuery(q) && !q->tcp)
-    {
-        LogInfo("sendLLQRefresh setting up new TLS session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        if (!q->nta)
-        {
-            // Note: If a question is in LLQ_Established state, we never free the zone data for the
-            // question (PrivateQuery). If we free, we reset the state to something other than LLQ_Established.
-            // This function is called only if the query is in LLQ_Established state and hence nta should
-            // never be NULL. In spite of that, we have seen q->nta being NULL in the field. Just refetch the
-            // zone data in that case.
-            q->nta = StartGetZoneData(m, &q->qname, ZoneServiceLLQ, LLQGotZoneData, q);
-            return;
-            // ThisQInterval is not adjusted when we return from here which means that we will get called back
-            // again immediately. As q->servAddr and q->servPort are still valid and the nta->Host is initialized
-            // without any additional discovery for PrivateQuery, things work. 
-        }
-        q->tcp = MakeTCPConn(m, &m->omsg, end, kTCPSocketFlags_UseTLS, &q->servAddr, q->servPort, &q->nta->Host, q, mDNSNULL);
-    }
-    else
     {
         mStatus err;
 
-        // if AuthInfo and AuthInfo->AutoTunnel is set, we use the TCP socket but don't need to pass the AuthInfo as
-        // we already protected the message above.
-        LogInfo("sendLLQRefresh: using existing %s session %##s (%s)", PrivateQuery(q) ? "TLS" : "UDP",
-                q->qname.c, DNSTypeName(q->qtype));
+        LogInfo("sendLLQRefresh: using existing UDP session %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
 
-        err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->servAddr, q->servPort, q->tcp ? q->tcp->sock : mDNSNULL, mDNSNULL, mDNSfalse);
+        err = mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->tcp ? q->tcp->sock : mDNSNULL, q->LocalSocket, &q->servAddr, q->servPort, mDNSNULL, mDNSfalse);
         if (err)
         {
             LogMsg("sendLLQRefresh: mDNSSendDNSMessage%s failed: %d", q->tcp ? " (TCP)" : "", err);
@@ -4073,16 +3944,13 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
     {
         q->servAddr = zoneInfo->Addr;
         q->servPort = zoneInfo->Port;
-        if (!PrivateQuery(q))
+        // We don't need the zone data as we use it only for the Host information which we
+        // don't need if we are not going to use TLS connections.
+        if (q->nta)
         {
-            // We don't need the zone data as we use it only for the Host information which we
-            // don't need if we are not going to use TLS connections.
-            if (q->nta)
-            {
-                if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p)  %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
-                CancelGetZoneData(m, q->nta);
-                q->nta = mDNSNULL;
-            }
+            if (q->nta != zoneInfo) LogMsg("LLQGotZoneData: nta (%p) != zoneInfo (%p)  %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
+            CancelGetZoneData(m, q->nta);
+            q->nta = mDNSNULL;
         }
         q->ntries = 0;
         debugf("LLQGotZoneData %#a:%d", &q->servAddr, mDNSVal16(q->servPort));
@@ -4108,90 +3976,36 @@ mDNSexport void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneI
     mDNS_Unlock(m);
 }
 
-#ifdef DNS_PUSH_ENABLED
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
 mDNSexport void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
 {
     DNSQuestion *q = (DNSQuestion *)zoneInfo->ZoneDataContext;
     mDNS_Lock(m);
 
     // If we get here it means that the GetZoneData operation has completed.
-    // We hold on to the zone data if it is AutoTunnel as we use the hostname
-    // in zoneInfo during the TLS connection setup.
     q->servAddr = zeroAddr;
     q->servPort = zeroIPPort;
-    if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && !mDNSAddressIsZero(&zoneInfo->Addr) && zoneInfo->Host.c[0])
-    {
-        q->dnsPushState      = DNSPUSH_SERVERFOUND;
-        q->dnsPushServerAddr = zoneInfo->Addr;
-        q->dnsPushServerPort = zoneInfo->Port;
-        q->ntries            = 0;
-        LogInfo("DNSPushNotificationGotZoneData %#a:%d", &q->dnsPushServerAddr, mDNSVal16(q->dnsPushServerPort));
-        SubscribeToDNSPushNotificationServer(m,q);
-    }
-    else
+    if (!err && zoneInfo && !mDNSIPPortIsZero(zoneInfo->Port) && zoneInfo->Host.c[0])
     {
-        q->dnsPushState = DNSPUSH_NOSERVER;
-        StartLLQPolling(m,q);
-        if (err == mStatus_NoSuchNameErr)
+        q->state = LLQ_DNSPush_Connecting;
+        LogInfo("DNSPushNotificationGotZoneData %##s%%%d", &zoneInfo->Host, ntohs(zoneInfo->Port.NotAnInteger));
+        q->dnsPushServer = SubscribeToDNSPushNotificationServer(m, q);
+        if (q->dnsPushServer == mDNSNULL || (q->dnsPushServer->connectState != DNSPushServerConnectionInProgress &&
+                                             q->dnsPushServer->connectState != DNSPushServerConnected &&
+                                             q->dnsPushServer->connectState != DNSPushServerSessionEstablished))
         {
-            // this actually failed, so mark it by setting address to all ones
-            q->servAddr.type  = mDNSAddrType_IPv4;
-            q->servAddr.ip.v4 = onesIPv4Addr;
+            goto noServer;
         }
     }
-    mDNS_Unlock(m);
-}
-#endif // DNS_PUSH_ENABLED
-
-// Called in normal callback context (i.e. mDNS_busy and mDNS_reentrancy are both 1)
-mDNSlocal void PrivateQueryGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo)
-{
-    DNSQuestion *q = (DNSQuestion *) zoneInfo->ZoneDataContext;
-
-    LogInfo("PrivateQueryGotZoneData %##s (%s) err %d Zone %##s Private %d", q->qname.c, DNSTypeName(q->qtype), err, zoneInfo->ZoneName.c, zoneInfo->ZonePrivate);
-
-    if (q->nta != zoneInfo) LogMsg("PrivateQueryGotZoneData:ERROR!!: nta (%p) != zoneInfo (%p)  %##s (%s)", q->nta, zoneInfo, q->qname.c, DNSTypeName(q->qtype));
-
-    if (err || !zoneInfo || mDNSAddressIsZero(&zoneInfo->Addr) || mDNSIPPortIsZero(zoneInfo->Port) || !zoneInfo->Host.c[0])
-    {
-        LogInfo("PrivateQueryGotZoneData: ERROR!! %##s (%s) invoked with error code %d %p %#a:%d",
-                q->qname.c, DNSTypeName(q->qtype), err, zoneInfo,
-                zoneInfo ? &zoneInfo->Addr : mDNSNULL,
-                zoneInfo ? mDNSVal16(zoneInfo->Port) : 0);
-        CancelGetZoneData(m, q->nta);
-        q->nta = mDNSNULL;
-        return;
-    }
-
-    if (!zoneInfo->ZonePrivate)
-    {
-        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;
-        CancelGetZoneData(m, q->nta);
-        q->nta = mDNSNULL;
-        mDNS_Lock(m);
-        SetNextQueryTime(m, q);
-        mDNS_Unlock(m);
-        return;
-        // Next call to uDNS_CheckCurrentQuestion() will do this as a non-private query
-    }
-
-    if (!PrivateQuery(q))
+    else
     {
-        LogMsg("PrivateQueryGotZoneData: ERROR!! Not a private query %##s (%s) AuthInfo %p", q->qname.c, DNSTypeName(q->qtype), q->AuthInfo);
-        CancelGetZoneData(m, q->nta);
-        q->nta = mDNSNULL;
-        return;
+    noServer:
+        q->state = LLQ_InitialRequest;
+        startLLQHandshake(m,q);
     }
-
-    q->TargetQID = mDNS_NewMessageID(m);
-    if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
-    if (!q->nta) { LogMsg("PrivateQueryGotZoneData:ERROR!! nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype)); return; }
-    q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &zoneInfo->Addr, zoneInfo->Port, &q->nta->Host, q, mDNSNULL);
-    if (q->nta) { CancelGetZoneData(m, q->nta); q->nta = mDNSNULL; }
+    mDNS_Unlock(m);
 }
+#endif
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -4321,19 +4135,6 @@ mDNSexport void RecordRegistrationGotZoneData(mDNS *const m, mStatus err, const
         mDNSv4AddrIsRFC1918(&m->AdvertisedV4.ip.v4) && newRR->nta && !mDNSAddrIsRFC1918(&newRR->nta->Addr) &&
         newRR->AutoTarget == Target_AutoHostAndNATMAP)
     {
-        DomainAuthInfo *AuthInfo;
-        AuthInfo = GetAuthInfoForName(m, newRR->resrec.name);
-        if (AuthInfo && AuthInfo->AutoTunnel)
-        {
-            domainname *t = GetRRDomainNameTarget(&newRR->resrec);
-            LogMsg("RecordRegistrationGotZoneData: ERROR!! AutoTunnel has Target_AutoHostAndNATMAP for %s", ARDisplayString(m, newRR));
-            if (t) t->c[0] = 0;
-            newRR->resrec.rdlength = newRR->resrec.rdestimate = 0;
-            newRR->state = regState_NoTarget;
-            CancelGetZoneData(m, newRR->nta);
-            newRR->nta = mDNSNULL;
-            return;
-        }
         // During network transitions, we are called multiple times in different states. Setup NAT
         // state just once for this record.
         if (!newRR->NATinfo.clientContext)
@@ -4382,7 +4183,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
 
     limit = ptr + AbsoluteMaxDNSMessageData;
     AuthInfo = GetAuthInfoForName_internal(m, rr->resrec.name);
-    limit -= RRAdditionalSize(m, AuthInfo);
+    limit -= RRAdditionalSize(AuthInfo);
 
     rr->updateid = mDNS_NewMessageID(m);
     InitializeDNSMessage(&m->omsg.h, rr->updateid, UpdateReqFlags);
@@ -4408,7 +4209,7 @@ mDNSlocal void SendRecordDeregistration(mDNS *m, AuthRecord *rr)
         mStatus err;
         LogInfo("SendRecordDeregistration UDP %s", ARDisplayString(m, rr));
         if (!rr->nta) { LogMsg("SendRecordDeregistration:ERROR!! nta is NULL for %s", ARDisplayString(m, rr)); return; }
-        err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, &rr->nta->Addr, rr->nta->Port, mDNSNULL, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
+        err = mDNSSendDNSMessage(m, &m->omsg, ptr, mDNSInterface_Any, mDNSNULL, mDNSNULL, &rr->nta->Addr, rr->nta->Port, GetAuthInfoForName_internal(m, rr->resrec.name), mDNSfalse);
         if (err) debugf("ERROR: SendRecordDeregistration - mDNSSendDNSMessage - %d", err);
         //if (rr->state == regState_DeregPending) CompleteDeregistration(m, rr);        // Don't touch rr after this
     }
@@ -4646,22 +4447,69 @@ mDNSlocal void handle_unanswered_query(mDNS *const m)
 
 mDNSlocal void uDNS_HandleLLQState(mDNS *const m, DNSQuestion *q)
 {
-#ifdef DNS_PUSH_ENABLED
-    // First attempt to use DNS Push Notification.
-    if (q->dnsPushState == DNSPUSH_INIT)
-        DiscoverDNSPushNotificationServer(m, q);
-#endif // DNS_PUSH_ENABLED
-    switch (q->state)
+    LogMsg("->uDNS_HandleLLQState: %##s %d", &q->qname, q->state);
+    switch(q->state)
     {
+    case LLQ_Init:
+        // If DNS Push isn't supported, LLQ_Init falls through to LLQ_InitialRequest.
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+        // First attempt to use DNS Push Notification.
+        DiscoverDNSPushNotificationServer(m, q);
+        break;
+
+    case LLQ_DNSPush_ServerDiscovery:
+    case LLQ_DNSPush_Connecting:
+    case LLQ_DNSPush_Established:
+        // Sanity check the server state to see if it matches.   If we find that we aren't connected, when
+        // we think we should be, change our state.
+        if (q->dnsPushServer == NULL)
+        {
+            q->state = LLQ_Init;
+            q->ThisQInterval = 0;
+            q->LastQTime = m->timenow;
+            SetNextQueryTime(m, q);
+        }
+        else
+        {
+            switch(q->dnsPushServer->connectState)
+            {
+            case DNSPushServerDisconnected:
+            case DNSPushServerConnectFailed:
+            case DNSPushServerNoDNSPush:
+                LogMsg("uDNS_HandleLLQState: %##s, server state %d doesn't match question state %d",
+                       &q->dnsPushServer->serverName, q->state, q->dnsPushServer->connectState);
+                q->state = LLQ_Poll;
+                q->ThisQInterval = (mDNSPlatformOneSecond * 5);
+                q->LastQTime     = m->timenow;
+                SetNextQueryTime(m, q);
+                break;
+            case DNSPushServerSessionEstablished:
+                LogMsg("uDNS_HandleLLQState: %##s, server connection established but question state is %d",
+                       &q->dnsPushServer->serverName, q->state);
+                q->state = LLQ_DNSPush_Established;
+                q->ThisQInterval = 0;
+                q->LastQTime     = m->timenow;
+                SetNextQueryTime(m, q);
+                break;
+                
+            case DNSPushServerConnectionInProgress:
+            case DNSPushServerConnected:
+                break;
+            }
+        }
+        break;
+#else
+            // Silence warnings; these are never reached without DNS Push
+        case LLQ_DNSPush_ServerDiscovery:
+        case LLQ_DNSPush_Connecting:
+        case LLQ_DNSPush_Established:
+#endif // MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
         case LLQ_InitialRequest:   startLLQHandshake(m, q); break;
-        case LLQ_SecondaryRequest:
-            // For PrivateQueries, we need to start the handshake again as we don't do the Challenge/Response step
-            if (PrivateQuery(q))   startLLQHandshake(m, q);
-            else                   sendChallengeResponse(m, q, mDNSNULL);
-            break;
+        case LLQ_SecondaryRequest: sendChallengeResponse(m, q, mDNSNULL); break;
         case LLQ_Established:      sendLLQRefresh(m, q); break;
         case LLQ_Poll:             break;       // Do nothing (handled below)
     }
+    LogMsg("<-uDNS_HandleLLQState: %##s %d %d", &q->qname, q->state);
 }
 
 // The question to be checked is not passed in as an explicit parameter;
@@ -4684,10 +4532,13 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
         {
             DNSServer *orig = q->qDNSServer;
             if (orig)
-                LogInfo("uDNS_CheckCurrentQuestion: Sent %d unanswered queries for %##s (%s) to %#a:%d (%##s)",
-                        q->unansweredQueries, q->qname.c, DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), orig->domain.c);
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[R%u->Q%u] uDNS_CheckCurrentQuestion: Sent %d unanswered queries for " PRI_DM_NAME " (" PUB_S ") to " PRI_IP_ADDR ":%d (" PRI_DM_NAME ")",
+                          q->request_id, mDNSVal16(q->TargetQID), q->unansweredQueries, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), &orig->addr, mDNSVal16(orig->port), DM_NAME_PARAM(orig->domain.c));
+            }
 
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, SYMPTOMS)
             SymptomReporterDNSServerUnreachable(orig);
 #endif
             PenalizeDNSServer(m, q, zeroID);
@@ -4710,15 +4561,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
         {
             DNSServer *new;
             DNSQuestion *qptr;
-            q->triedAllServersOnce = 1;
+            q->triedAllServersOnce = mDNStrue;
             // Re-initialize all DNS servers for this question. If we have a DNSServer, DNSServerChangeForQuestion will
             // handle all the work including setting the new DNS server.
             SetValidDNSServers(m, q);
             new = GetServerForQuestion(m, q);
             if (new)
             {
-                LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%d ThisQInterval %d",
-                        q, q->qname.c, DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval);
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[R%u->Q%u] uDNS_checkCurrentQuestion: Retrying question %p " PRI_DM_NAME " (" PUB_S ") DNS Server " PRI_IP_ADDR ":%d ThisQInterval %d",
+                          q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype), new ? &new->addr : mDNSNULL, mDNSVal16(new ? new->port : zeroIPPort), q->ThisQInterval);
                 DNSServerChangeForQuestion(m, q, new);
             }
             for (qptr = q->next ; qptr; qptr = qptr->next)
@@ -4728,7 +4580,6 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
         {
             mDNSu8 *end;
             mStatus err = mStatus_NoError;
-            mDNSBool private = mDNSfalse;
 
             InitializeDNSMessage(&m->omsg.h, q->TargetQID, (DNSSECQuestion(q) ? DNSSecQFlags : uQueryFlags));
 
@@ -4740,71 +4591,77 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                 else
                     end = putDNSSECOption(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData);
             }
-            private = PrivateQuery(q);
 
             if (end > m->omsg.data)
             {
-                //LogMsg("uDNS_CheckCurrentQuestion %p %d %p %##s (%s)", q, NextQSendTime(q) - m->timenow, private, q->qname.c, DNSTypeName(q->qtype));
-                if (private)
+                debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
+                       q, q->qname.c, DNSTypeName(q->qtype),
+                       q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
+#if APPLE_OSX_mDNSResponder
+                // When a DNS proxy network extension initiates the close of a UDP flow (this usually happens when a DNS
+                // proxy gets disabled or crashes), mDNSResponder's corresponding UDP socket will be marked with the
+                // SS_CANTRCVMORE state flag. Reading from such a socket is no longer possible, so close the current
+                // socket pair so that we can create a new pair.
+                if (q->LocalSocket && mDNSPlatformUDPSocketEncounteredEOF(q->LocalSocket))
                 {
-                    if (q->nta) CancelGetZoneData(m, q->nta);
-                    q->nta = StartGetZoneData(m, &q->qname, q->LongLived ? ZoneServiceLLQ : ZoneServiceQuery, PrivateQueryGotZoneData, q);
-                    if (q->state == LLQ_Poll) q->ThisQInterval = (LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10)) / QuestionIntervalStep;
+                    mDNSPlatformUDPClose(q->LocalSocket);
+                    q->LocalSocket = mDNSNULL;
+                }
+#endif
+                if (!q->LocalSocket)
+                {
+                    q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
+                    if (q->LocalSocket)
+                    {
+                        mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv4, q);
+                        mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv6, q);
+                    }
                 }
+                if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
                 else
                 {
-                    debugf("uDNS_CheckCurrentQuestion sending %p %##s (%s) %#a:%d UnansweredQueries %d",
-                           q, q->qname.c, DNSTypeName(q->qtype),
-                           q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->unansweredQueries);
-#if APPLE_OSX_mDNSResponder
-                    // When a DNS proxy network extension initiates the close of a UDP flow (this usually happens when a DNS
-                    // proxy gets disabled or crashes), mDNSResponder's corresponding UDP socket will be marked with the
-                    // SS_CANTRCVMORE state flag. Reading from such a socket is no longer possible, so close the current
-                    // socket pair so that we can create a new pair.
-                    if (q->LocalSocket && mDNSPlatformUDPSocketEncounteredEOF(q->LocalSocket))
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+                    // If we are in suspicious mode, restart question as TCP
+                    mDNSs32  suspiciousTimeout = m->NextSuspiciousTimeout ? m->NextSuspiciousTimeout - m->timenow : 0;
+                    if (suspiciousTimeout > 0 && suspiciousTimeout <= SUSPICIOUS_REPLY_DEFENSE_SECS * mDNSPlatformOneSecond)
                     {
-                        mDNSPlatformUDPClose(q->LocalSocket);
-                        q->LocalSocket = mDNSNULL;
+                        uDNS_RestartQuestionAsTCP(m, q, &q->qDNSServer->addr, q->qDNSServer->port);
+                        err = mStatus_NoError;
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+                        q->metrics.dnsOverTCPState = DNSOverTCP_SuspiciousDefense;
+#endif
                     }
+                    else
 #endif
-                    if (!q->LocalSocket)
                     {
-                        q->LocalSocket = mDNSPlatformUDPSocket(zeroIPPort);
-                        if (q->LocalSocket)
-                        {
-                            mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv4, q);
-                            mDNSPlatformSetSocktOpt(q->LocalSocket, mDNSTransport_UDP, mDNSAddrType_IPv6, q);
-                        }
+                        err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, mDNSNULL, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, q->UseBackgroundTraffic);
                     }
-                    if (!q->LocalSocket) err = mStatus_NoMemoryErr; // If failed to make socket (should be very rare), we'll try again next time
-                    else
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+                    if (!err)
                     {
-                        err = mDNSSendDNSMessage(m, &m->omsg, end, q->qDNSServer->interface, q->LocalSocket, &q->qDNSServer->addr, q->qDNSServer->port, mDNSNULL, mDNSNULL, q->UseBackgroundTrafficClass);
-#if AWD_METRICS
-                        if (!err)
+                        MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg));
+                        if (q->metrics.answered)
                         {
-                            MetricsUpdateDNSQuerySize((mDNSu32)(end - (mDNSu8 *)&m->omsg));
-                            if (q->metrics.answered)
-                            {
-                                q->metrics.querySendCount = 0;
-                                q->metrics.answered       = mDNSfalse;
-                            }
-                            if (q->metrics.querySendCount++ == 0)
-                            {
-                                q->metrics.firstQueryTime = m->timenow;
-                            }
+                            q->metrics.querySendCount = 0;
+                            q->metrics.answered       = mDNSfalse;
+                        }
+                        if (q->metrics.querySendCount++ == 0)
+                        {
+                            q->metrics.firstQueryTime = m->timenow;
                         }
-#endif
                     }
-                }
+#endif
+                               }
             }
 
             if (err == mStatus_HostUnreachErr)
             {
                 DNSServer *newServer;
 
-                LogInfo("uDNS_CheckCurrentQuestion: host unreachable error for DNS server %#a for question [%p] %##s (%s)",
-                    &q->qDNSServer->addr, q, q->qname.c, DNSTypeName(q->qtype));
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[R%u->Q%u] uDNS_CheckCurrentQuestion: host unreachable error for DNS server " PRI_IP_ADDR " for question [%p] " PRI_DM_NAME " (" PUB_S ")",
+                          q->request_id, mDNSVal16(q->TargetQID), &q->qDNSServer->addr, q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
 
                 if (!StrictUnicastOrdering)
                 {
@@ -4814,14 +4671,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                 newServer = GetServerForQuestion(m, q);
                 if (!newServer)
                 {
-                    q->triedAllServersOnce = 1;
+                    q->triedAllServersOnce = mDNStrue;
                     SetValidDNSServers(m, q);
                     newServer = GetServerForQuestion(m, q);
                 }
                 if (newServer)
                 {
-                    LogInfo("uDNS_checkCurrentQuestion: Retrying question %p %##s (%s) DNS Server %#a:%u ThisQInterval %d",
-                        q, q->qname.c, DNSTypeName(q->qtype), newServer ? &newServer->addr : mDNSNULL, mDNSVal16(newServer ? newServer->port : zeroIPPort), q->ThisQInterval);
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                              "[R%u->Q%u] uDNS_checkCurrentQuestion: Retrying question %p " PRI_DM_NAME " (" PUB_S ") DNS Server " PRI_IP_ADDR ":%u ThisQInterval %d",
+                              q->request_id, mDNSVal16(q->TargetQID), q, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+                              newServer ? &newServer->addr : mDNSNULL, mDNSVal16(newServer ? newServer->port : zeroIPPort), q->ThisQInterval);
                     DNSServerChangeForQuestion(m, q, newServer);
                 }
                 if (q->triedAllServersOnce)
@@ -4849,16 +4708,6 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                     q->unansweredQueries++;
                     if (q->ThisQInterval > MAX_UCAST_POLL_INTERVAL)
                         q->ThisQInterval = MAX_UCAST_POLL_INTERVAL;
-                    if (private && q->state != LLQ_Poll)
-                    {
-                        // We don't want to retransmit too soon. Hence, we always schedule our first
-                        // retransmisson at 3 seconds rather than one second
-                        if (q->ThisQInterval < (3 * mDNSPlatformOneSecond))
-                            q->ThisQInterval = q->ThisQInterval * QuestionIntervalStep;
-                        if (q->ThisQInterval > LLQ_POLL_INTERVAL)
-                            q->ThisQInterval = LLQ_POLL_INTERVAL;
-                        LogInfo("uDNS_CheckCurrentQuestion: private non polling question for %##s (%s) will be retried in %d ms", q->qname.c, DNSTypeName(q->qtype), q->ThisQInterval);
-                    }
                     if (q->qDNSServer->isCell)
                     {
                         // We don't want to retransmit too soon. Schedule our first retransmisson at
@@ -4882,15 +4731,16 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
             // (When we have a group of identical questions, only the active representative of the group gets
             // passed to uDNS_CheckCurrentQuestion -- we only want one set of query packets hitting the wire --
             // but we want *all* of the questions to get answer callbacks.)
-            CacheRecord *rr;
+            CacheRecord *cr;
             const mDNSu32 slot = HashSlotFromNameHash(q->qnamehash);
             CacheGroup *const cg = CacheGroupForName(m, q->qnamehash, &q->qname);
 
             if (!q->qDNSServer)
             {
                 if (!mDNSOpaque128IsZero(&q->validDNSServers))
-                    LogMsg("uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x 0x%x 0x%x for question %##s (%s)",
-                           q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0], q->qname.c, DNSTypeName(q->qtype));
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[R%u->Q%u] uDNS_CheckCurrentQuestion: ERROR!!: valid DNSServer bits not zero 0x%x, 0x%x 0x%x 0x%x for question " PRI_DM_NAME " (" PUB_S ")",
+                              q->request_id, mDNSVal16(q->TargetQID), q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0], DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
                 // If we reached the end of list while picking DNS servers, then we don't want to deactivate the
                 // question. Try after 60 seconds. We find this by looking for valid DNSServers for this question,
                 // if we find any, then we must have tried them before we came here. This avoids maintaining
@@ -4898,7 +4748,9 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                 SetValidDNSServers(m, q);
                 if (mDNSOpaque128IsZero(&q->validDNSServers))
                 {
-                    LogInfo("uDNS_CheckCurrentQuestion: no DNS server for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                              "[R%u->Q%u] uDNS_CheckCurrentQuestion: no DNS server for " PRI_DM_NAME " (" PUB_S ")",
+                              q->request_id, mDNSVal16(q->TargetQID), DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype));
                     q->ThisQInterval = 0;
                 }
                 else
@@ -4915,25 +4767,30 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
                     q->qDNSServer = GetServerForQuestion(m, q);
                     for (qptr = q->next ; qptr; qptr = qptr->next)
                         if (qptr->DuplicateOf == q) { qptr->validDNSServers = q->validDNSServers; qptr->qDNSServer = q->qDNSServer; }
-                    LogInfo("uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d %##s (%s) with DNS Server %#a:%d after 60 seconds, ThisQInterval %d",
-                            q, q->SuppressUnusable, q->qname.c, DNSTypeName(q->qtype),
-                            q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval);
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                              "[R%u->Q%u] uDNS_checkCurrentQuestion: Tried all DNS servers, retry question %p SuppressUnusable %d " PRI_DM_NAME " (" PUB_S ") with DNS Server " PRI_IP_ADDR ":%d after 60 seconds, ThisQInterval %d",
+                              q->request_id, mDNSVal16(q->TargetQID), q, q->SuppressUnusable, DM_NAME_PARAM(q->qname.c), DNSTypeName(q->qtype),
+                              q->qDNSServer ? &q->qDNSServer->addr : mDNSNULL, mDNSVal16(q->qDNSServer ? q->qDNSServer->port : zeroIPPort), q->ThisQInterval);
                 }
             }
             else
             {
                 q->ThisQInterval = 0;
-                LogMsg("uDNS_CheckCurrentQuestion DNS server %#a:%d for %##s is disabled", &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), q->qname.c);
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[R%u->Q%u] uDNS_CheckCurrentQuestion DNS server " PRI_IP_ADDR ":%d for " PRI_DM_NAME " is disabled",
+                          q->request_id, mDNSVal16(q->TargetQID), &q->qDNSServer->addr, mDNSVal16(q->qDNSServer->port), DM_NAME_PARAM(q->qname.c));
             }
 
             if (cg)
             {
-                for (rr = cg->members; rr; rr=rr->next)
+                for (cr = cg->members; cr; cr=cr->next)
                 {
-                    if (SameNameRecordAnswersQuestion(&rr->resrec, q))
+                    if (SameNameCacheRecordAnswersQuestion(cr, q))
                     {
-                        LogInfo("uDNS_CheckCurrentQuestion: Purged resourcerecord %s", CRDisplayString(m, rr));
-                        mDNS_PurgeCacheResourceRecord(m, rr);
+                        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                                  "[R%u->Q%u] uDNS_CheckCurrentQuestion: Purged resourcerecord " PRI_S,
+                                  q->request_id, mDNSVal16(q->TargetQID), CRDisplayString(m, cr));
+                        mDNS_PurgeCacheResourceRecord(m, cr);
                     }
                 }
             }
@@ -4945,7 +4802,7 @@ mDNSexport void uDNS_CheckCurrentQuestion(mDNS *const m)
             if (!mDNSOpaque16IsZero(q->responseFlags))
                 m->rec.r.responseFlags = q->responseFlags;
             // We're already using the m->CurrentQuestion pointer, so CacheRecordAdd can't use it to walk the question list.
-            // To solve this problem we set rr->DelayDelivery to a nonzero value (which happens to be 'now') so that we
+            // To solve this problem we set cr->DelayDelivery to a nonzero value (which happens to be 'now') so that we
             // momentarily defer generating answer callbacks until mDNS_Execute time.
             CreateNewCacheEntry(m, slot, cg, NonZeroTime(m->timenow), mDNStrue, mDNSNULL);
             ScheduleNextCacheCheckTime(m, slot, NonZeroTime(m->timenow));
@@ -5149,6 +5006,9 @@ mDNSexport void uDNS_Tasks(mDNS *const m)
     mDNSs32 nexte;
     DNSServer *d;
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+    if (m->NextSuspiciousTimeout && m->NextSuspiciousTimeout <= m->timenow) m->NextSuspiciousTimeout = 0;
+#endif
     m->NextuDNSEvent = m->timenow + FutureTime;
 
     nexte = CheckRecordUpdates(m);
@@ -5160,7 +5020,8 @@ mDNSexport void uDNS_Tasks(mDNS *const m)
         {
             if (m->timenow - d->penaltyTime >= 0)
             {
-                LogInfo("DNS server %#a:%d out of penalty box", &d->addr, mDNSVal16(d->port));
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "DNS server " PRI_IP_ADDR ":%d out of penalty box", &d->addr, mDNSVal16(d->port));
                 d->penaltyTime = 0;
             }
             else
@@ -5169,7 +5030,11 @@ mDNSexport void uDNS_Tasks(mDNS *const m)
         }
 
     if (m->CurrentQuestion)
-        LogMsg("uDNS_Tasks ERROR m->CurrentQuestion already set: %##s (%s)", m->CurrentQuestion->qname.c, DNSTypeName(m->CurrentQuestion->qtype));
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "uDNS_Tasks ERROR m->CurrentQuestion already set: " PRI_DM_NAME " (" PRI_S ")",
+                  DM_NAME_PARAM(m->CurrentQuestion->qname.c), DNSTypeName(m->CurrentQuestion->qtype));
+    }
     m->CurrentQuestion = m->Questions;
     while (m->CurrentQuestion && m->CurrentQuestion != m->NewQuestions)
     {
@@ -5261,9 +5126,8 @@ mDNSexport void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfa
     else
     {
         // if domain not in list, add to list, mark as add (1)
-        *p = mDNSPlatformMemAllocate(sizeof(SearchListElem));
+        *p = (SearchListElem *) mDNSPlatformMemAllocateClear(sizeof(**p));
         if (!*p) { LogMsg("ERROR: mDNS_AddSearchDomain - malloc"); return; }
-        mDNSPlatformMemZero(*p, sizeof(SearchListElem));
         AssignDomainName(&(*p)->domain, domain);
         (*p)->next = mDNSNULL;
         (*p)->InterfaceID = InterfaceID;
@@ -5298,7 +5162,7 @@ mDNSlocal void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceR
 
     if (AddRecord)
     {
-        ARListElem *arElem = mDNSPlatformMemAllocate(sizeof(ARListElem));
+        ARListElem *arElem = (ARListElem *) mDNSPlatformMemAllocateClear(sizeof(*arElem));
         if (!arElem) { LogMsg("ERROR: FoundDomain out of memory"); return; }
         mDNS_SetupResourceRecord(&arElem->ar, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, 7200, kDNSRecordTypeShared, AuthRecordLocalOnly, FreeARElemCallback, arElem);
         MakeDomainNameFromDNSNameString(&arElem->ar.namestorage, name);
@@ -5692,7 +5556,7 @@ mDNSexport void uDNS_StopWABQueries(mDNS *const m, int queryType)
     uDNS_SetupWABQueries(m);
 }
 
-mDNSexport domainname  *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal)
+mDNSexport domainname  *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, int *searchIndex, mDNSBool ignoreDotLocal)
 {
     SearchListElem *p = SearchList;
     int count = *searchIndex;
@@ -5732,10 +5596,7 @@ mDNSexport domainname  *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mD
         }
         // Point to the next one in the list which we will look at next time.
         (*searchIndex)++;
-        // When we are appending search domains in a ActiveDirectory domain, the question's InterfaceID
-        // set to mDNSInterface_Unicast. Match the unscoped entries in that case.
-        if (((InterfaceID == mDNSInterface_Unicast) && (p->InterfaceID == mDNSInterface_Any)) ||
-            p->InterfaceID == InterfaceID)
+        if (p->InterfaceID == InterfaceID)
         {
             LogInfo("uDNS_GetNextSearchDomain returning domain %##s, InterfaceID %p", p->domain.c, p->InterfaceID);
             return &p->domain;
@@ -5753,6 +5614,11 @@ mDNSexport void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const m
     // new DNS server. So, always try to establish a new connection.
     if (q->tcp) { DisposeTCPConn(q->tcp); q->tcp = mDNSNULL; }
     q->tcp = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_Zero, srcaddr, srcport, mDNSNULL, q, mDNSNULL);
+#if MDNSRESPONDER_SUPPORTS(APPLE, SUSPICIOUS_REPLY_DEFENSE)
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+        "uDNS_RestartQuestionAsTCP: suspicious timeout %d ticks",
+        m->NextSuspiciousTimeout ? m->NextSuspiciousTimeout - m->timenow : 0);
+#endif
 }
 
 mDNSlocal void FlushAddressCacheRecords(mDNS *const m)
@@ -5827,233 +5693,652 @@ struct CompileTimeAssertionChecks_uDNS
 #pragma mark - DNS Push Notification functions
 #endif
 
-#ifdef DNS_PUSH_ENABLED
-mDNSlocal tcpInfo_t * GetTCPConnectionToPushServer(mDNS *m, DNSQuestion *q)
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+mDNSlocal void DNSPushProcessResponse(mDNS *const m, const DNSMessage *const msg,
+                                      DNSPushNotificationServer *server, ResourceRecord *mrr)
 {
-    DNSPushNotificationZone   *zone;
-    DNSPushNotificationServer *server;
-    DNSPushNotificationZone   *newZone;
-    DNSPushNotificationServer *newServer;
+    // "(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
+    // set non-zero, and that tells GetCacheEntity() that they're not, at this moment, eligible for recycling.
+    CacheRecord *CacheFlushRecords = (CacheRecord*)1;
+    CacheRecord **cfp = &CacheFlushRecords;
+    enum { removeName, removeClass, removeRRset, removeRR, addRR } action;
 
-    // If we already have a question for this zone and if the server is the same, reuse it
-    for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+    // Ignore records we don't want to cache.
+
+    // Don't want to cache OPT or TSIG pseudo-RRs
+    if (mrr->rrtype == kDNSType_TSIG)
     {
-        if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
+        return;
+    }
+    if (mrr->rrtype == kDNSType_OPT)
+    {
+        return;
+    }
+
+    if ((mrr->rrtype == kDNSType_CNAME) && SameDomainName(mrr->name, &mrr->rdata->u.name))
+    {
+        LogInfo("DNSPushProcessResponse: CNAME loop domain name %##s", mrr->name->c);
+        return;
+    }
+
+    // TTL == -1: delete individual record
+    // TTL == -2: wildcard delete
+    //   CLASS != ANY, TYPE != ANY: delete all records of specified type and class
+    //   CLASS != ANY, TYPE == ANY: delete all RRs of specified class
+    //   CLASS == ANY: delete all RRs on the name, regardless of type or class (TYPE is ignored).
+    // If TTL is zero, this is a delete, not an add.
+    if ((mDNSs32)mrr->rroriginalttl == -1)
+    {
+        LogMsg("DNSPushProcessResponse: Got remove on %##s with type %s",
+               mrr->name, DNSTypeName(mrr->rrtype));
+        action = removeRR;
+    }
+    else if ((mDNSs32)mrr->rroriginalttl == -2)
+    {
+        if (mrr->rrclass == kDNSQClass_ANY)
         {
-            DNSPushNotificationServer *zoneServer = mDNSNULL;
-            for (zoneServer = zone->servers; zoneServer != mDNSNULL; zoneServer = zoneServer->next)
+            LogMsg("DNSPushProcessResponse: Got Remove Name on %##s", mrr->name);
+            action = removeName;
+        }
+        else if (mrr->rrtype == kDNSQType_ANY)
+        {
+            LogMsg("DNSPushProcessResponse: Got Remove Name on %##s", mrr->name);
+            action = removeClass;
+        }
+        else
+        {
+            LogMsg("DNSPushProcessResponse: Got Remove RRset on %##s, type %s, rdlength %d",
+                   mrr->name, DNSTypeName(mrr->rrtype), mrr->rdlength);
+            action = removeRRset;
+        }
+    }
+    else
+    {
+        action = addRR;
+    }
+
+    if (action != addRR)
+    {
+        if (m->rrcache_size)
+        {
+            CacheRecord *rr;
+            // Remember the unicast question that we found, which we use to make caching
+            // decisions later on in this function
+            CacheGroup *cg = CacheGroupForName(m, mrr->namehash, mrr->name);
+            for (rr = cg ? cg->members : mDNSNULL; rr; rr=rr->next)
             {
-                if (mDNSSameAddress(&q->dnsPushServerAddr, &zoneServer->serverAddr))
+                if ( action == removeName  ||
+                    (action == removeClass && rr->resrec.rrclass == mrr->rrclass) ||
+                    (rr->resrec.rrclass == mrr->rrclass &&
+                     ((action == removeRRset && rr->resrec.rrtype == mrr->rrtype) ||
+                      (action == removeRR    && rr->resrec.rrtype == mrr->rrtype  &&
+                       SameRDataBody(mrr, &rr->resrec.rdata->u, SameDomainName)))))
                 {
-                    zone->numberOfQuestions++;
-                    zoneServer->numberOfQuestions++;
-                    return zoneServer->connection;
+                    LogInfo("DNSPushProcessResponse purging %##s (%s) %s",
+                            rr->resrec.name, DNSTypeName(mrr->rrtype), CRDisplayString(m, rr));
+                    // We've found a cache entry to delete.   Now what?
+                    mDNS_PurgeCacheResourceRecord(m, rr);
                 }
             }
         }
     }
-
-    // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
-    for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
+    else
     {
-        if (mDNSSameAddress(&q->dnsPushServerAddr, &server->serverAddr))
-        {
-            newZone = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
-            newZone->numberOfQuestions = 1;
-            newZone->zoneName = q->nta->ChildName;
-            newZone->servers = server;
-
-            // Add the new zone to the begining of the list
-            newZone->next = m->DNSPushZones;
-            m->DNSPushZones = newZone;
-
-            server->numberOfQuestions++;
-            return server->connection;
+        // It's an add.
+        LogMsg("DNSPushProcessResponse: Got add RR on %##s, type %s, length %d",
+               mrr->name, DNSTypeName(mrr->rrtype), mrr->rdlength);
+
+        // When we receive DNS Push responses, we assume a long cache lifetime --
+        // This path is only reached for DNS Push responses; as long as the connection to the server is
+        // live, the RR should stay ypdated.
+        mrr->rroriginalttl = kLLQ_DefLease /* XXX */;
+
+        // Use the DNS Server we remember from the question that created this DNS Push server structure.
+        mrr->rDNSServer = server->qDNSServer;
+        
+        // 2. See if we want to add this packet resource record to our cache
+        // We only try to cache answers if we have a cache to put them in
+        if (m->rrcache_size)
+        {
+            const mDNSu32 slot = HashSlotFromNameHash(mrr->namehash);
+            CacheGroup *cg = CacheGroupForName(m, mrr->namehash, mrr->name);
+            CacheRecord *rr = mDNSNULL;
+            CacheRecord *NSECCachePtr = (CacheRecord *)1;
+
+            // 2a. Check if this packet resource record is already in our cache.
+            rr = mDNSCoreReceiveCacheCheck(m, msg, uDNS_LLQ_Events, slot, cg, mDNSNULL, &cfp, &NSECCachePtr, mDNSNULL);
+
+            // If packet resource record not in our cache, add it now
+            // (unless it is just a deletion of a record we never had, in which case we don't care)
+            if (!rr && mrr->rroriginalttl > 0)
+            {
+                rr = CreateNewCacheEntry(m, slot, cg, 0,
+                                         mDNStrue, &server->connection->transport->remote_addr);
+                if (rr)
+                {
+                    // Not clear that this is ever used, but for verisimilitude, set this to look like
+                    // an authoritative response to a regular query.
+                    rr->responseFlags.b[0] = kDNSFlag0_QR_Response | kDNSFlag0_OP_StdQuery | kDNSFlag0_AA;
+                    rr->responseFlags.b[1] = kDNSFlag1_RC_NoErr | kDNSFlag0_AA;
+                }
+            }
         }
     }
+}
 
-    // If we do not have any existing connections, create a new connection
-    newServer = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationServer));
-    newZone   = mDNSPlatformMemAllocate(sizeof(DNSPushNotificationZone));
-
-    newServer->numberOfQuestions = 1;
-    newServer->serverAddr = q->dnsPushServerAddr;
-    newServer->connection = MakeTCPConn(m, mDNSNULL, mDNSNULL, kTCPSocketFlags_UseTLS, &q->dnsPushServerAddr, q->dnsPushServerPort, &q->nta->Host, q, mDNSNULL);
-
-    newZone->numberOfQuestions = 1;
-    newZone->zoneName = q->nta->ChildName;
-    newZone->servers  = newServer;
-
-    // Add the new zone to the begining of the list
-    newZone->next   = m->DNSPushZones;
-    m->DNSPushZones = newZone;
-
-    newServer->next   = m->DNSPushServers;
-    m->DNSPushServers = newServer;
-    return newServer->connection;
+mDNSlocal void DNSPushProcessResponses(mDNS *const m, const DNSMessage *const msg, const mDNSu8 *firstAnswer,
+                                           const mDNSu8 *const end, DNSPushNotificationServer *server)
+{
+    DNSQuestion *q;
+    const mDNSu8 *ptr = firstAnswer;
+    mDNSIPPort port;
+    port.NotAnInteger = 0;
+    ResourceRecord *mrr = &m->rec.r.resrec;
+
+    // Validate the contents of the message
+    // XXX Right now this code will happily parse all the valid data and then hit invalid data
+    // and give up.  I don't think there's a risk here, but we should discuss it.
+    // XXX what about source validation?   Like, if we have a VPN, are we safe?   I think yes, but let's think about it.
+    while ((ptr = GetLargeResourceRecord(m, msg, ptr, end, mDNSNULL, kDNSRecordTypePacketAns, &m->rec)))
+    {
+        int gotOne = 0;
+        for (q = m->Questions; q; q = q->next)
+        {
+            if (q->LongLived &&
+                (q->qtype == mrr->rrtype || q->qtype == kDNSServiceType_ANY)
+                && q->qnamehash == mrr->namehash && SameDomainName(&q->qname, mrr->name))
+            {
+                LogMsg("DNSPushProcessResponses found %##s (%s) %d %s %s",
+                       q->qname.c, DNSTypeName(q->qtype), q->state,
+                       q->dnsPushServer ? (q->dnsPushServer->connection
+                                           ? q->dnsPushServer->connection->remote_name
+                                           : "<no push server>") : "<no push server>",
+                       server->connection->remote_name);
+                if (q->dnsPushServer == server)
+                {
+                    gotOne++;
+                    DNSPushProcessResponse(m, msg, server, mrr);
+                    break; // question list may have changed
+                }
+            }
+        }
+        if (!gotOne) {
+            LogMsg("DNSPushProcessResponses: no match for %##s %d %d", mrr->name, mrr->rrtype, mrr->rrclass);
+        }
+        mrr->RecordType = 0;     // Clear RecordType to show we're not still using it
+    }
+}
+                                           
+static void
+DNSPushStartConnecting(DNSPushNotificationServer *server)
+{
+    if (dso_connect(server->connectInfo))
+    {
+        server->connectState = DNSPushServerConnectionInProgress;
+    }
+    else
+    {
+        server->connectState = DNSPushServerConnectFailed;
+    }
 }
 
-mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+mDNSexport  void DNSPushReconcileConnection(mDNS *m, DNSQuestion *q)
 {
-    /* Use the same  NAT setup as in the LLQ case */
-    if (m->LLQNAT.clientContext != mDNSNULL) // LLQNAT just started, give it some time
+    DNSPushNotificationZone   *zone;
+    DNSPushNotificationZone   *nextZone;
+
+    if (q->dnsPushServer == mDNSNULL)
     {
-        LogInfo("startLLQHandshake: waiting for NAT status for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);    // Retry in approx 15 minutes
-        q->LastQTime = m->timenow;
-        SetNextQueryTime(m, q);
         return;
     }
+    
+    // Update the counts
+    for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
+    {
+        if (zone->server == q->dnsPushServer)
+        {
+            zone->numberOfQuestions--;
+        }
+    }
+    q->dnsPushServer->numberOfQuestions--;
 
-    // Either we don't have {PCP, NAT-PMP, UPnP/IGD} support (ExternalPort is zero) or behind a Double NAT that may or
-    // may not have {PCP, NAT-PMP, UPnP/IGD} support (NATResult is non-zero)
-    if (mDNSIPPortIsZero(m->LLQNAT.ExternalPort) || m->LLQNAT.Result)
+    nextZone = mDNSNULL;
+    for (zone = m->DNSPushZones; zone != mDNSNULL; zone = nextZone)
     {
-        LogInfo("startLLQHandshake: Cannot receive inbound packets; will poll for %##s (%s) External Port %d, NAT Result %d",
-                q->qname.c, DNSTypeName(q->qtype), mDNSVal16(m->LLQNAT.ExternalPort), m->LLQNAT.Result);
-        StartLLQPolling(m, q); // Actually sets up the NAT Auto Tunnel
+        nextZone = zone->next;
+        if (zone->numberOfQuestions == 0)
+        {
+            if (zone == m->DNSPushZones)
+                m->DNSPushZones = nextZone;
+            LogInfo("DNSPushReconcileConnection: zone %##s is being freed", &zone->zoneName);
+            mDNSPlatformMemFree(zone);
+         }
+     }
+
+    q->dnsPushServer = mDNSNULL;
+}
+
+static const char kDNSPushActivity_Subscription[] = "dns-push-subscription";
+
+static void DNSPushSendKeepalive(DNSPushNotificationServer *server, mDNSu32 inactivity_timeout, mDNSu32 keepalive_interval)
+{
+    dso_message_t state;
+    dso_transport_t *transport = server->connection->transport;
+    if (transport == NULL || transport->outbuf == NULL) {
+        // Should be impossible, don't crash.
+        LogInfo("DNSPushNotificationSendSubscribe: no transport!");
         return;
     }
+    dso_make_message(&state, transport->outbuf, transport->outbuf_size, server->connection, false, 0);
+    dso_start_tlv(&state, kDSOType_Keepalive);
+    dso_add_tlv_u32(&state, inactivity_timeout);
+    dso_add_tlv_u32(&state, keepalive_interval);
+    dso_finish_tlv(&state);
+    dso_message_write(server->connection, &state, mDNSfalse);
+}
 
-    if (mDNSIPPortIsZero(q->dnsPushServerPort) && q->dnsPushState == DNSPUSH_INIT)
-    {
-        LogInfo("SubscribeToDNSPushNotificationServer: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);    // Retry in approx 15 minutes
-        q->LastQTime     = m->timenow;
-        SetNextQueryTime(m, q);
-        q->dnsPushServerAddr = zeroAddr;
-        // We know q->dnsPushServerPort is zero because of check above
-        if (q->nta) CancelGetZoneData(m, q->nta);
-        q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+static void DNSPushNotificationSendSubscriptionChange(mDNSBool subscribe, dso_state_t *dso, DNSQuestion *q)
+{
+    dso_message_t state;
+    dso_transport_t *transport = dso->transport;
+    mDNSu16 len;
+    if (transport == NULL || transport->outbuf == NULL) {
+        // Should be impossible, don't crash.
+        LogInfo("DNSPushNotificationSendSubscribe: no transport!");
         return;
     }
+    dso_make_message(&state, transport->outbuf, transport->outbuf_size, dso, subscribe ? false : true, q);
+    dso_start_tlv(&state, subscribe ? kDSOType_DNSPushSubscribe : kDSOType_DNSPushUnsubscribe);
+    len = DomainNameLengthLimit(&q->qname, q->qname.c + (sizeof q->qname));
+    dso_add_tlv_bytes(&state, q->qname.c, len);
+    dso_add_tlv_u16(&state, q->qtype);
+    dso_add_tlv_u16(&state, q->qclass);
+    dso_finish_tlv(&state);
+    dso_message_write(dso, &state, mDNSfalse);
+}
 
-    if (q->tcp)
+static void DNSPushStop(mDNS *m, DNSPushNotificationServer *server)
+{
+    mDNSBool found = mDNStrue;
+    DNSQuestion *q;
+    while (found)
     {
-        LogInfo("SubscribeToDNSPushNotificationServer: Disposing existing TCP connection for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        DisposeTCPConn(q->tcp);
-        q->tcp = mDNSNULL;
+        found = mDNSfalse;
+        server->connectState = DNSPushServerNoDNSPush;
+        
+        for (q = m->Questions; q; q = q->next)
+        {
+            if (q->dnsPushServer == server)
+            {
+                DNSPushReconcileConnection(m, q);
+                q->dnsPushServer = NULL;
+                q->state = LLQ_Poll;
+                q->ThisQInterval = 0;
+                q->LastQTime     = m->timenow;
+                SetNextQueryTime(m, q);
+                break;
+            }
+        }
     }
+}
 
-    if (!q->nta)
+mDNSexport void DNSPushServerDrop(DNSPushNotificationServer *server)
+{
+    if (server->connection)
     {
-        // Normally we lookup the zone data and then call this function. And we never free the zone data
-        // for "PrivateQuery". But sometimes this can happen due to some race conditions. When we
-        // switch networks, we might end up "Polling" the network e.g., we are behind a Double NAT.
-        // When we poll, we free the zone information as we send the query to the server (See
-        // PrivateQueryGotZoneData). The NAT callback (LLQNATCallback) may happen soon after that. If we
-        // are still behind Double NAT, we would have returned early in this function. But we could
-        // have switched to a network with no NATs and we should get the zone data again.
-        LogInfo("SubscribeToDNSPushNotificationServer: nta is NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
-        return;
+        dso_drop(server->connection);
+        server->connection = NULL;
     }
-    else if (!q->nta->Host.c[0])
+    if (server->connectInfo)
     {
-        // This should not happen. If it happens, we print a log and MakeTCPConn will fail if it can't find a hostname
-        LogMsg("SubscribeToDNSPushNotificationServer: ERROR!!: nta non NULL for %##s (%s) but HostName %d NULL, LongLived %d", q->qname.c, DNSTypeName(q->qtype), q->nta->Host.c[0], q->LongLived);
+        dso_connect_state_drop(server->connectInfo);
     }
-    q->tcp = GetTCPConnectionToPushServer(m,q);
-    // If TCP failed (transient networking glitch) try again in five seconds
-    q->ThisQInterval = (q->tcp != mDNSNULL) ? q->ThisQInterval = 0 : (mDNSPlatformOneSecond * 5);
-    q->LastQTime     = m->timenow;
-    SetNextQueryTime(m, q);
 }
 
-
-mDNSexport void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+static void DNSPushServerFree(mDNS *m, DNSPushNotificationServer *server)
 {
-    mDNSu8     *end = mDNSNULL;
-    InitializeDNSMessage(&m->omsg.h, zeroID, SubscribeFlags);
-    end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
-    if (!end)
+    DNSPushNotificationServer **sp;
+    DNSPushServerDrop(server);
+
+    sp = &m->DNSPushServers;
+    while (*sp)
     {
-        LogMsg("ERROR: SubscribeToDNSPushNotificationServer putQuestion failed");
-        return;
+        if (*sp == server)
+        {
+            *sp = server->next;
+            break;
+        }
+        else
+        {
+               sp = &server->next;
+        }
     }
+    mDNSPlatformMemFree(server);
+}
 
-    mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+static void DNSPushDSOCallback(void *context, const void *event_context,
+                               dso_state_t *dso, dso_event_type_t eventType)
+{
+    const DNSMessage *message;
+    DNSPushNotificationServer *server = context;
+    dso_activity_t *activity;
+    const dso_query_receive_context_t *receive_context;
+    const dso_disconnect_context_t *disconnect_context;
+    const dso_keepalive_context_t *keepalive_context;
+    DNSQuestion *q;
+    uint16_t rcode;
+    mDNSs32 reconnect_when = 0;
+    mDNS *m = server->m;
 
-    // update question state
-    q->dnsPushState  = DNSPUSH_ESTABLISHED;
-    q->ThisQInterval = (kLLQ_INIT_RESEND * mDNSPlatformOneSecond);
-    q->LastQTime     = m->timenow;
-    SetNextQueryTime(m, q);
+    mDNS_CheckLock(m);
+    
+       switch(eventType)
+    {
+       case kDSOEventType_DNSMessage:
+        // We shouldn't get here because we won't use this connection for DNS messages.
+        message = event_context;
+        LogMsg("DNSPushDSOCallback: DNS Message (opcode=%d) received from %##s",
+               (message->h.flags.b[0] & kDNSFlag0_OP_Mask) >> 3, &server->serverName);
+               break;
+
+       case kDSOEventType_DNSResponse:
+        // We shouldn't get here because we already handled any DNS messages
+        message = event_context;
+        LogMsg("DNSPushDSOCallback: DNS Response (opcode=%d) received from %##s",
+               (message->h.flags.b[0] & kDNSFlag0_OP_Mask) >> 3, &server->serverName);
+               break;
+
+       case kDSOEventType_DSOMessage:
+        message = event_context;
+        if (dso->primary.opcode == kDSOType_DNSPushUpdate) {
+            DNSPushProcessResponses(server->m, message, dso->primary.payload,
+                                    dso->primary.payload + dso->primary.length, server);
+        } else {
+            dso_send_not_implemented(dso, &message->h);
+            LogMsg("DNSPushDSOCallback: Unknown DSO Message (Primary TLV=%d) received from %##s",
+                   dso->primary.opcode, &server->serverName);
+        }
+               break;
+
+       case kDSOEventType_DSOResponse:
+        receive_context = event_context;
+        q = receive_context->query_context;
+        rcode = receive_context->rcode;
+        if (q) {
+            // If we got an error on a subscribe, we need to evaluate what went wrong
+            if (rcode == kDNSFlag1_RC_NoErr) {
+                LogMsg("DNSPushDSOCallback: Subscription for %##s/%d/%d succeeded.", q->qname.c, q->qtype, q->qclass);
+                q->state = LLQ_DNSPush_Established;
+                server->connectState = DNSPushServerSessionEstablished;
+            } else {
+                // Don't use this server.
+                q->dnsPushServer->connectState = DNSPushServerNoDNSPush;
+                q->state = LLQ_Poll;
+                q->ThisQInterval = 0;
+                q->LastQTime     = m->timenow;
+                SetNextQueryTime(m, q);
+                LogMsg("DNSPushDSOCallback: Subscription for %##s/%d/%d failed.", q->qname.c, q->qtype, q->qclass);
+            }
+        } else {
+            LogMsg("DNSPushDSOCallback: DSO Response (Primary TLV=%d) (RCODE=%d) (no query) received from %##s",
+                   dso->primary.opcode, receive_context->rcode, &server->serverName);
+            server->connectState = DNSPushServerSessionEstablished;
+        }
+               break;
+
+       case kDSOEventType_Finalize:
+               LogMsg("DNSPushDSOCallback: Finalize");
+               break;
+
+       case kDSOEventType_Connected:
+        LogMsg("DNSPushDSOCallback: Connected to %##s", &server->serverName);
+        server->connectState = DNSPushServerConnected;
+        for (activity = dso->activities; activity; activity = activity->next) {
+            DNSPushNotificationSendSubscriptionChange(mDNStrue, dso, activity->context);
+        }
+               break;
+
+       case kDSOEventType_ConnectFailed:
+        DNSPushStop(m, server);
+        LogMsg("DNSPushDSOCallback: Connection to %##s failed", &server->serverName);
+               break;
+
+       case kDSOEventType_Disconnected:
+        disconnect_context = event_context;
+
+        // If a network glitch broke the connection, try to reconnect immediately.  But if this happens
+        // twice, don't just blindly reconnect.
+        if (disconnect_context->reconnect_delay == 0) {
+            if ((server->lastDisconnect + 90 * mDNSPlatformOneSecond) - m->timenow > 0) {
+                reconnect_when = 3600000; // If we get two disconnects in quick succession, wait an hour before trying again.
+            } else {
+                DNSPushStartConnecting(server);
+                LogMsg("DNSPushDSOCallback: Connection to %##s disconnected, trying immediate reconnect",
+                       &server->serverName);
+            }
+        } else {
+            reconnect_when = disconnect_context->reconnect_delay;
+        }
+        if (reconnect_when != 0) {
+            LogMsg("DNSPushDSOCallback: Holding server %##s out as not reconnectable for %lf seconds",
+                   &server->serverName, 1000.0 * (reconnect_when - m->timenow) / (double)mDNSPlatformOneSecond);
+            dso_schedule_reconnect(m, server->connectInfo, reconnect_when);
+        }
+        server->lastDisconnect = m->timenow;
+        server->connection = mDNSNULL;
+               break;
+
+        // We don't reconnect unless there is demand.   The reason we have this event is so that we can
+        // leave the DNSPushNotificationServer data structure around to _prevent_ attempts to reconnect
+        // before the reconnect delay interval has expired.   When we get this call, we just free up the
+        // server.
+    case kDSOEventType_ShouldReconnect:
+        // This should be unnecessary, but it would be bad to accidentally have a question pointing at
+        // a server that had been freed, so make sure we don't.
+        LogMsg("DNSPushDSOCallback: ShouldReconnect timer for %##s fired, disposing of it.", &server->serverName);
+        DNSPushStop(m, server);
+        DNSPushServerFree(m, server);
+        break;
+
+    case kDSOEventType_Keepalive:
+        LogMsg("DNSPushDSOCallback: Keepalive timer for %##s fired.", &server->serverName);
+        keepalive_context = event_context;
+        DNSPushSendKeepalive(server, keepalive_context->inactivity_timeout, keepalive_context->keepalive_interval);
+        break;
 
+    case kDSOEventType_KeepaliveRcvd:
+        LogMsg("DNSPushDSOCallback: Keepalive message received from %##s.", &server->serverName);
+        break;
+        
+    case kDSOEventType_Inactive:
+        // The set of activities went to zero, and we set the idle timeout.   And it expired without any
+        // new activities starting.   So we can disconnect.
+        LogMsg("DNSPushDSOCallback: Inactivity timer for %##s fired, disposing of it.", &server->serverName);
+        DNSPushStop(m, server);
+        DNSPushServerFree(m, server);
+        break;
+
+    case kDSOEventType_RetryDelay:
+        disconnect_context = event_context;
+        DNSPushStop(m, server);
+        dso_schedule_reconnect(m, server->connectInfo, disconnect_context->reconnect_delay);
+        break;
+    }
 }
 
-mDNSlocal  void reconcileDNSPushConnection(mDNS *m, DNSQuestion *q)
+DNSPushNotificationServer *GetConnectionToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
 {
     DNSPushNotificationZone   *zone;
     DNSPushNotificationServer *server;
-    DNSPushNotificationServer *nextServer;
-    DNSPushNotificationZone   *nextZone;
+    DNSPushNotificationZone   *newZone;
+    DNSPushNotificationServer *newServer;
+    char name[MAX_ESCAPED_DOMAIN_NAME];
 
-    // Update the counts
+    // If we already have a question for this zone and if the server is the same, reuse it
     for (zone = m->DNSPushZones; zone != mDNSNULL; zone = zone->next)
     {
-        if (SameDomainName(&zone->zoneName, &q->nta->ChildName))
+        LogMsg("GetConnectionToDNSPushNotificationServer: zone compare zone %##s question %##s", &zone->zoneName, &q->nta->ChildName);
+        if (SameDomainName(&q->nta->ChildName, &zone->zoneName))
         {
-            zone->numberOfQuestions--;
-            for (server = zone->servers; server != mDNSNULL; server = server->next)
-            {
-                if (mDNSSameAddress(&server->serverAddr, &q->dnsPushServerAddr))
-                    server->numberOfQuestions--;
+            DNSPushNotificationServer *zoneServer = mDNSNULL;
+            zoneServer = zone->server;
+            if (zoneServer != mDNSNULL) {
+                LogMsg("GetConnectionToDNSPushNotificationServer: server compare server %##s question %##s",
+                       &zoneServer->serverName, &q->nta->Host);
+                if (SameDomainName(&q->nta->Host, &zoneServer->serverName))
+                {
+                    LogMsg("GetConnectionToDNSPushNotificationServer: server and zone already present.");
+                    zone->numberOfQuestions++;
+                    zoneServer->numberOfQuestions++;
+                    return zoneServer;
+                }
             }
         }
     }
 
-    // Now prune the lists
-    server = m->DNSPushServers;
-    nextServer = mDNSNULL;
-    while(server != mDNSNULL)
+    // If we have a connection to this server but it is for a differnt zone, create a new zone entry and reuse the connection
+    for (server = m->DNSPushServers; server != mDNSNULL; server = server->next)
     {
-        nextServer = server->next;
-        if (server->numberOfQuestions <= 0)
+        LogMsg("GetConnectionToDNSPushNotificationServer: server compare server %##s question %##s",
+               &server->serverName, &q->nta->Host);
+        if (SameDomainName(&q->nta->Host, &server->serverName))
         {
-            DisposeTCPConn(server->connection);
-            if (server == m->DNSPushServers)
-                m->DNSPushServers = nextServer;
-            mDNSPlatformMemFree(server);
-            server = nextServer;
+            newZone = (DNSPushNotificationZone *) mDNSPlatformMemAllocateClear(sizeof(*newZone));
+            if (newZone == NULL)
+            {
+                return NULL;
+            }
+            newZone->numberOfQuestions = 1;
+            newZone->zoneName = q->nta->ChildName;
+            newZone->server = server;
+
+            // Add the new zone to the begining of the list
+            newZone->next = m->DNSPushZones;
+            m->DNSPushZones = newZone;
+
+            server->numberOfQuestions++;
+            LogMsg("GetConnectionToDNSPushNotificationServer: server already present.");
+            return server;
         }
-        else server = server->next;
     }
 
-    zone = m->DNSPushZones;
-    nextZone = mDNSNULL;
-    while(zone != mDNSNULL)
+    // If we do not have any existing connections, create a new connection
+    newServer = (DNSPushNotificationServer *) mDNSPlatformMemAllocateClear(sizeof(*newServer));
+    if (newServer == NULL)
     {
-        nextZone = zone->next;
-        if (zone->numberOfQuestions <= 0)
-        {
-            if (zone == m->DNSPushZones)
-                m->DNSPushZones = nextZone;
-            mDNSPlatformMemFree(zone);
-            zone = nextZone;
-        }
-        else zone = zone->next;
+        return NULL;
+    }
+    newZone = (DNSPushNotificationZone *) mDNSPlatformMemAllocateClear(sizeof(*newZone));
+    if (newZone == NULL)
+    {
+        mDNSPlatformMemFree(newServer);
+        return NULL;
+    }
+
+    newServer->m = m;
+    newServer->numberOfQuestions = 1;
+    AssignDomainName(&newServer->serverName, &q->nta->Host);
+    newServer->port = q->nta->Port;
+    newServer->qDNSServer = q->qDNSServer;
+    ConvertDomainNameToCString(&newServer->serverName, name);
+    newServer->connection = dso_create(mDNSfalse, 10, name, DNSPushDSOCallback, newServer, NULL);
+    if (newServer->connection == NULL)
+    {
+        mDNSPlatformMemFree(newServer);
+        mDNSPlatformMemFree(newZone);
+        return NULL;
+    }
+    newServer->connectInfo = dso_connect_state_create(name, mDNSNULL, newServer->port, 10,
+                                                      AbsoluteMaxDNSMessageData, AbsoluteMaxDNSMessageData,
+                                                      DNSPushDSOCallback, newServer->connection, newServer, "GetDSOConnectionToPushServer");
+    if (newServer->connectInfo)
+    {
+        dso_connect_state_use_tls(newServer->connectInfo);
+        DNSPushStartConnecting(newServer);
     }
+    else
+    {
+        newServer->connectState = DNSPushServerConnectFailed;
+    }    
+    newZone->numberOfQuestions = 1;
+    newZone->zoneName = q->nta->ChildName;
+    newZone->server = newServer;
+
+    // Add the new zone to the begining of the list
+    newZone->next   = m->DNSPushZones;
+    m->DNSPushZones = newZone;
+
+    newServer->next   = m->DNSPushServers;
+    m->DNSPushServers = newServer;
+    LogMsg("GetConnectionToDNSPushNotificationServer: allocated new server.");
 
+    return newServer;
 }
 
-mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+DNSPushNotificationServer *SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
 {
-    mDNSu8     *end = mDNSNULL;
-    InitializeDNSMessage(&m->omsg.h, q->TargetQID, UnSubscribeFlags);
-    end = putQuestion(&m->omsg, end, m->omsg.data + AbsoluteMaxDNSMessageData, &q->qname, q->qtype, q->qclass);
-    if (!end)
+    DNSPushNotificationServer *server = GetConnectionToDNSPushNotificationServer(m, q);
+    char name[MAX_ESCAPED_DOMAIN_NAME + 9];  // type(hex)+class(hex)+name
+    dso_activity_t *activity;
+    if (server == mDNSNULL) return server;
+
+    // Now we have a connection to a push notification server.   It may be pending, or it may be active,
+    // but either way we can add a DNS Push subscription to the server object.
+    mDNS_snprintf(name, sizeof name, "%04x%04x", q->qtype, q->qclass);
+    ConvertDomainNameToCString(&q->qname, &name[8]);
+    activity = dso_add_activity(server->connection, name, kDNSPushActivity_Subscription, q, mDNSNULL);
+    if (activity == mDNSNULL)
     {
-        LogMsg("ERROR: UnSubscribeToDNSPushNotificationServer - putQuestion failed");
-        return;
+        LogInfo("SubscribeToDNSPushNotificationServer: failed to add question %##s", &q->qname);
+        return mDNSNULL;
+    }
+    // If we're already connected, send the subscribe request immediately.
+    if (server->connectState == DNSPushServerConnected || server->connectState == DNSPushServerSessionEstablished)
+    {
+        DNSPushNotificationSendSubscriptionChange(mDNStrue, server->connection, q);
     }
+    return server;
+}
 
-    mDNSSendDNSMessage(m, &m->omsg, end, mDNSInterface_Any, q->LocalSocket, &q->dnsPushServerAddr, q->dnsPushServerPort, q->tcp->sock, mDNSNULL, mDNSfalse);
+mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+    LogInfo("DiscoverDNSPushNotificationServer: StartGetZoneData for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
+    q->ThisQInterval = LLQ_POLL_INTERVAL + mDNSRandom(LLQ_POLL_INTERVAL/10);    // Retry in approx 15 minutes
+    q->LastQTime     = m->timenow;
+    SetNextQueryTime(m, q);
+    if (q->nta) CancelGetZoneData(m, q->nta);
+    q->nta = StartGetZoneData(m, &q->qname, ZoneServiceDNSPush, DNSPushNotificationGotZoneData, q);
+    q->state = LLQ_DNSPush_ServerDiscovery;
+}
 
-    reconcileDNSPushConnection(m, q);
+mDNSexport void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
+{
+    dso_activity_t *activity;
+    
+    if (q->dnsPushServer != mDNSNULL)
+    {
+        if (q->dnsPushServer->connection != mDNSNULL)
+        {
+            if (q->dnsPushServer->connectState == DNSPushServerSessionEstablished ||
+                q->dnsPushServer->connectState == DNSPushServerConnected)
+            {
+                // Ignore any response we get to a pending subscribe.
+                dso_ignore_response(q->dnsPushServer->connection, q);
+                DNSPushNotificationSendSubscriptionChange(mDNSfalse, q->dnsPushServer->connection, q);
+            }
+            // activities linger even if we are not connected.
+            activity = dso_find_activity(q->dnsPushServer->connection, mDNSNULL, kDNSPushActivity_Subscription, q);
+            if (activity != mDNSNULL) {
+                dso_drop_activity(q->dnsPushServer->connection, activity);
+            }
+        }
+        DNSPushReconcileConnection(m, q);
+    }
+    // We let the DSO Idle mechanism clean up the connection to the server.
 }
+#endif // MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
 
-#endif // DNS_PUSH_ENABLED
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
 #endif
@@ -6165,7 +6450,7 @@ mDNSexport void RetrySearchDomainQuestions(mDNS *const m)
     (void) m;
 }
 
-mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
+mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
 {
     (void) m;
     (void) info;
@@ -6174,7 +6459,6 @@ mDNSexport mStatus mDNS_SetSecretForDomain(mDNS *m, DomainAuthInfo *info, const
     (void) b64keydata;
     (void) hostname;
     (void) port;
-    (void) autoTunnel;
 
     return mStatus_UnsupportedErr;
 }
@@ -6213,8 +6497,8 @@ mDNSexport mStatus mDNS_StopNATOperation(mDNS *const m, NATTraversalInfo *traver
 }
 
 mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, const mDNSInterfaceID interface, const mDNSs32 serviceID, const mDNSAddr *addr,
-                                        const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSu32 resGroupID,
-                                        mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+                                        const mDNSIPPort port, ScopeType scopeType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained, mDNSBool isCLAT46,
+                                        mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
 {
     (void) m;
     (void) d;
@@ -6226,6 +6510,8 @@ mDNSexport DNSServer *mDNS_AddDNSServer(mDNS *const m, const domainname *d, cons
     (void) timeout;
     (void) isCell;
     (void) isExpensive;
+    (void) isCLAT46;
+    (void) isConstrained;
     (void) resGroupID;
     (void) reqA;
     (void) reqAAAA;
@@ -6305,3 +6591,12 @@ mDNSexport void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q)
 
 #endif // !UNICAST_DISABLED
 
+
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
index d3141dd5b25943db7d5e4d8c19c4ced541b6eb52..ee8339327d25b40c1b833b6b465530365647d66e 100755 (executable)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
 
 #include "mDNSEmbeddedAPI.h"
 #include "DNSCommon.h"
+#include <sys/types.h>
+#include "dns_sd.h"
+
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+#include "dso.h"
+#include "dso-transport.h"
+#endif
 
 #ifdef  __cplusplus
 extern "C" {
@@ -75,16 +81,46 @@ extern "C" {
 // validation (for optional case only) for any questions that uses this server
 #define MAX_DNSSEC_RETRANSMISSIONS 3
 
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+// Push notification structures
+struct mDNS_DNSPushNotificationServer
+{
+    dso_connect_state_t       *connectInfo;       // DSO Connection state information
+    dso_state_t               *connection;        // DNS Stateful Operations/TCP Connection pointer, might be null.
+    mDNSu32                    numberOfQuestions; // Number of questions for this server
+    DNSPushServer_ConnectState connectState;      // Current status of connection attempt to this server
+    mDNSs32                    lastDisconnect;    // Last time we got a disconnect, used to avoid constant reconnects
+    domainname                 serverName;        // The hostname returned by the _dns-push-tls._tcp.<zone> SRV lookup
+    mDNSIPPort                 port;              // The port from the SRV lookup
+    DNSServer                 *qDNSServer;        // DNS server stolen from the question that created this server structure.
+    mDNS                      *m;
+    DNSPushNotificationServer *next;
+} ;
+
+struct mDNS_DNSPushNotificationZone
+{
+    domainname zoneName;
+    DNSPushNotificationServer *server; // DNS Push Notification Servers for this zone
+    mDNSu32 numberOfQuestions;          // Number of questions for this zone
+    DNSPushNotificationZone *next;
+} ;
+#endif
+
 // Entry points into unicast-specific routines
 
 extern void LLQGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
 extern void startLLQHandshake(mDNS *m, DNSQuestion *q);
 extern void sendLLQRefresh(mDNS *m, DNSQuestion *q);
 
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
 extern void DNSPushNotificationGotZoneData(mDNS *const m, mStatus err, const ZoneData *zoneInfo);
 extern void DiscoverDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
-extern void SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern DNSPushNotificationServer *GetConnectionToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern DNSPushNotificationServer *SubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
 extern void UnSubscribeToDNSPushNotificationServer(mDNS *m, DNSQuestion *q);
+extern void DNSPushReconcileConnection(mDNS *m, DNSQuestion *q);
+extern void DNSPushServerDrop(DNSPushNotificationServer *server);
+#endif
 
 extern void SleepRecordRegistrations(mDNS *m);
 
@@ -128,7 +164,7 @@ extern mStatus         uDNS_SetupDNSConfig(mDNS *const m);
 extern void uDNS_SetupWABQueries(mDNS *const m);
 extern void uDNS_StartWABQueries(mDNS *const m, int queryType);
 extern void uDNS_StopWABQueries(mDNS *const m, int queryType);
-extern domainname      *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, mDNSs8 *searchIndex, mDNSBool ignoreDotLocal);
+extern domainname      *uDNS_GetNextSearchDomain(mDNSInterfaceID InterfaceID, int *searchIndex, mDNSBool ignoreDotLocal);
     
 extern void uDNS_RestartQuestionAsTCP(mDNS *m, DNSQuestion *const q, const mDNSAddr *const srcaddr, const mDNSIPPort srcport);
 
@@ -150,10 +186,15 @@ extern void uDNS_ReceiveNATPacket(mDNS *m, const mDNSInterfaceID InterfaceID, mD
 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, NATTProtocol protocol);
 
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
 // DNS Push Notification
 extern void SubscribeToDNSPushNotification(mDNS *m, DNSQuestion *q);
+#endif
     
-    
+extern CacheRecord* mDNSCoreReceiveCacheCheck(mDNS *const m, const DNSMessage *const response, uDNS_LLQType LLQType,
+                                                                                         const mDNSu32 slot, CacheGroup *cg, DNSQuestion *unicastQuestion,
+                                              CacheRecord ***cfp, CacheRecord **NSECCachePtr, mDNSInterfaceID InterfaceID);
+
 #ifdef  __cplusplus
 }
 #endif
diff --git a/mDNSMacOSX/ApplePlatformFeatures.h b/mDNSMacOSX/ApplePlatformFeatures.h
new file mode 100644 (file)
index 0000000..77f3eab
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2018-2019 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.
+ */
+
+#ifndef __ApplePlatformFeatures_h
+#define __ApplePlatformFeatures_h
+
+#include <TargetConditionals.h>
+
+// Feature: Bonjour-On-Demand
+// Radar:   <rdar://problem/23523784>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_BONJOUR_ON_DEMAND)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_BONJOUR_ON_DEMAND          1
+#endif
+
+// Feature: Cache memory limit
+// Radar:   <rdar://problem/15629764>
+// Enabled: Yes, but only for device OSes, such as iOS, tvOS, and watchOS, i.e., when TARGET_OS_IPHONE is 1.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_CACHE_MEM_LIMIT)
+    #if !defined(TARGET_OS_IPHONE)
+        #error "Expected TARGET_OS_IPHONE to be defined."
+    #endif
+    #if TARGET_OS_IPHONE
+        #define MDNSRESPONDER_SUPPORTS_APPLE_CACHE_MEM_LIMIT        1
+    #else
+        #define MDNSRESPONDER_SUPPORTS_APPLE_CACHE_MEM_LIMIT        0
+    #endif
+#endif
+
+// Feature: D2D
+// Radar:   <rdar://problem/28062515>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_D2D)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_D2D                        1
+#endif
+
+// Feature: DNS64 IPv6 synthesis.
+// Radar:   <rdar://problem/32297396>
+// Enabled: Yes, but only for iOS and macOS, which support the DNS proxy network extension.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_DNS64)
+    #if (!defined(TARGET_OS_IOS) || !defined(TARGET_OS_OSX))
+        #error "Expected TARGET_OS_IOS and TARGET_OS_OSX to be defined."
+    #endif
+    #if (TARGET_OS_IOS || TARGET_OS_OSX)
+        #define MDNSRESPONDER_SUPPORTS_APPLE_DNS64                  1
+    #else
+        #define MDNSRESPONDER_SUPPORTS_APPLE_DNS64                  0
+    #endif
+#endif
+
+// Feature: DNS-SD XPC service
+// Radar:   <rdar://problem/43866363>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE          1
+#endif
+
+// Feature: Ignore /etc/hosts file on customer builds.
+// Radar:   <rdar://problem/34745220>
+// Enabled: Yes, except for macOS.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_IGNORE_HOSTS_FILE)
+    #if !defined(TARGET_OS_OSX)
+        #error "Expected TARGET_OS_OSX to be defined."
+    #endif
+    #if !TARGET_OS_OSX
+        #define MDNSRESPONDER_SUPPORTS_APPLE_IGNORE_HOSTS_FILE      1
+    #else
+        #define MDNSRESPONDER_SUPPORTS_APPLE_IGNORE_HOSTS_FILE      0
+    #endif
+#endif
+
+// Feature: AWD metrics collection
+// Radar:   <rdar://problem/24146300>
+// Enabled: Yes, but for iOS only.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_METRICS)
+    #if !defined(TARGET_OS_IOS)
+        #error "Expected TARGET_OS_IOS to be defined."
+    #endif
+    #if TARGET_OS_IOS
+        #define MDNSRESPONDER_SUPPORTS_APPLE_METRICS                1
+    #else
+        #define MDNSRESPONDER_SUPPORTS_APPLE_METRICS                0
+    #endif
+#endif
+
+// Feature: Support for having finer granularity of log redaction, by using os_log based-log routine.
+// Radar:   <rdar://problem/42814956>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_OS_LOG)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_OS_LOG                     1
+#endif
+
+// Feature: Preallocate mDNSResponder's cache memory. For testing purposes only.
+// Radar:   <rdar://problem/29545890>
+// Enabled: No.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_PREALLOCATED_CACHE)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_PREALLOCATED_CACHE         0
+#endif
+
+// Feature: Randomized AWDL Hostname
+// Radar:   <rdar://problem/47525004>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_RANDOM_AWDL_HOSTNAME)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_RANDOM_AWDL_HOSTNAME       1
+#endif
+
+// Feature: Reachability trigger
+// Radar:   <rdar://problem/11374446>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_REACHABILITY_TRIGGER)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_REACHABILITY_TRIGGER       1
+#endif
+
+// Feature: "SlowActivation" processing for flapping interfaces.
+//          Disabled to address stale Bonjour record issues during flapping network interface transitions.
+// Radar:   <rdar://problem/44694746>
+// Enabled: No.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_SLOW_ACTIVATION)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_SLOW_ACTIVATION            0
+#endif
+
+// Feature: Suspicious Reply Defense
+// Radar:   <rdar://problem/50050767>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_SUSPICIOUS_REPLY_DEFENSE)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_SUSPICIOUS_REPLY_DEFENSE   1
+#endif
+
+// Feature: Symptoms Reporting
+// Radar:   <rdar://problem/20194922>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_SYMPTOMS)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_SYMPTOMS                   1
+#endif
+
+// Feature: Support for performing dot-local queries via mDNS and DNS in parallel.
+// Radar:   <rdar://problem/4786302>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_UNICAST_DOTLOCAL)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_UNICAST_DOTLOCAL           1
+#endif
+
+// Feature: Allow browses and registrations over interfaces that aren't ready yet.
+// Radar:   <rdar://problem/20181903>
+// Enabled: Yes.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_UNREADY_INTERFACES)
+    #define MDNSRESPONDER_SUPPORTS_APPLE_UNREADY_INTERFACES         1
+#endif
+
+// Feature: Support for Web Content Filter
+// Radar:   <rdar://problem/7409981>
+// Enabled: Yes, if SDK has <WebFilterDNS/WebFilterDNS.h>.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_APPLE_WEB_CONTENT_FILTER)
+    #if __has_include(<WebFilterDNS/WebFilterDNS.h>)
+        #define MDNSRESPONDER_SUPPORTS_APPLE_WEB_CONTENT_FILTER     1
+    #else
+        #define MDNSRESPONDER_SUPPORTS_APPLE_WEB_CONTENT_FILTER     0
+    #endif
+#endif
+
+#endif  // __ApplePlatformFeatures_h
diff --git a/mDNSMacOSX/BATS/mDNSResponder.plist b/mDNSMacOSX/BATS/mDNSResponder.plist
deleted file mode 100644 (file)
index 66a8c49..0000000
+++ /dev/null
@@ -1,627 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>Project</key>
-       <string>mDNSResponder</string>
-       <key>RadarComponents</key>
-       <dict>
-               <key>Name</key>
-               <string>mDNSResponder</string>
-               <key>Version</key>
-               <string>all</string>
-       </dict>
-       <key>Tests</key>
-       <array>
-               <dict>
-                       <key>TestName</key>
-                       <string>GAIPerf Advanced</string>
-                       <key>Description</key>
-                       <string>Tests correctness of resolving hostnames via DNS using the GAIPerf Advanced test suite.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <false/>
-                       <key>Timeout</key>
-                       <integer>600</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>gaiperf</string>
-                               <string>--suite</string>
-                               <string>advanced</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--skipPathEval</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 1-1-1</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>1</string>
-                               <string>--txtSize</string>
-                               <string>1</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>1</string>
-                               <string>--countAAAA</string>
-                               <string>1</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 1-1-1 (No Additionals)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records. Responses from mdnsreplier contain no additional answers.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>1</string>
-                               <string>--txtSize</string>
-                               <string>1</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>1</string>
-                               <string>--countAAAA</string>
-                               <string>1</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--noAdditionals</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 10-100-2</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>10</string>
-                               <string>--txtSize</string>
-                               <string>100</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>2</string>
-                               <string>--countAAAA</string>
-                               <string>2</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 10-100-2 (No Additionals)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. Responses from mdnsreplier contain no additonal answers.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>10</string>
-                               <string>--txtSize</string>
-                               <string>100</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>2</string>
-                               <string>--countAAAA</string>
-                               <string>2</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--noAdditionals</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 100-500-5</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>100</string>
-                               <string>--txtSize</string>
-                               <string>500</string>
-                               <string>--browseTime</string>
-                               <string>5</string>
-                               <string>--countA</string>
-                               <string>5</string>
-                               <string>--countAAAA</string>
-                               <string>5</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 100-500-5 (No Additionals)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records. Responses from mdnsreplier contain no additonal answers.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>100</string>
-                               <string>--txtSize</string>
-                               <string>500</string>
-                               <string>--browseTime</string>
-                               <string>5</string>
-                               <string>--countA</string>
-                               <string>5</string>
-                               <string>--countAAAA</string>
-                               <string>5</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--noAdditionals</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 1-1-1 (No Cache Flush)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records. Cache is not flushed beforehand.</string>
-                       <key>AsRoot</key>
-                       <false/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>1</string>
-                               <string>--txtSize</string>
-                               <string>1</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>1</string>
-                               <string>--countAAAA</string>
-                               <string>1</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 1-1-1 (No Cache Flush, No Additionals)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of one service instance with a one-byte TXT record and one pair of A and AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
-                       <key>AsRoot</key>
-                       <false/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>1</string>
-                               <string>--txtSize</string>
-                               <string>1</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>1</string>
-                               <string>--countAAAA</string>
-                               <string>1</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--noAdditionals</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 10-100-2 (No Cache Flush)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. Cache is not flushed beforehand.</string>
-                       <key>AsRoot</key>
-                       <false/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>10</string>
-                               <string>--txtSize</string>
-                               <string>100</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>2</string>
-                               <string>--countAAAA</string>
-                               <string>2</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 10-100-2 (No Cache Flush, No Additionals)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
-                       <key>AsRoot</key>
-                       <false/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>10</string>
-                               <string>--txtSize</string>
-                               <string>100</string>
-                               <string>--browseTime</string>
-                               <string>3</string>
-                               <string>--countA</string>
-                               <string>2</string>
-                               <string>--countAAAA</string>
-                               <string>2</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--noAdditionals</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 100-500-5 (No Cache Flush)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records. Cache is not flushed beforehand.</string>
-                       <key>AsRoot</key>
-                       <false/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>100</string>
-                               <string>--txtSize</string>
-                               <string>500</string>
-                               <string>--browseTime</string>
-                               <string>5</string>
-                               <string>--countA</string>
-                               <string>5</string>
-                               <string>--countAAAA</string>
-                               <string>5</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery 100-500-5 (No Cache Flush, No Additionals)</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of 100 service instances with 500-byte TXT records and five pairs of A and AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
-                       <key>AsRoot</key>
-                       <false/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>100</string>
-                               <string>--txtSize</string>
-                               <string>500</string>
-                               <string>--browseTime</string>
-                               <string>5</string>
-                               <string>--countA</string>
-                               <string>5</string>
-                               <string>--countAAAA</string>
-                               <string>5</string>
-                               <string>--ipv4</string>
-                               <string>--ipv6</string>
-                               <string>--noAdditionals</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery w/Packet Drops 10</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of ten service instances with 100-byte TXT records and two pairs of A and AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>30</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>10</string>
-                               <string>--txtSize</string>
-                               <string>100</string>
-                               <string>--browseTime</string>
-                               <string>16</string>
-                               <string>--countA</string>
-                               <string>2</string>
-                               <string>--countAAAA</string>
-                               <string>2</string>
-                               <string>--ipv6</string>
-                               <string>--udrop</string>
-                               <string>0.5</string>
-                               <string>--mdrop</string>
-                               <string>0.5</string>
-                               <string>--maxDropCount</string>
-                               <string>3</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNS Discovery w/Packet Drops 100</string>
-                       <key>Description</key>
-                       <string>Tests mDNS discovery and resolution of 100 service instances with 100-byte TXT records and two pairs of A and AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>30</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>mdnsdiscovery</string>
-                               <string>--instanceCount</string>
-                               <string>100</string>
-                               <string>--txtSize</string>
-                               <string>100</string>
-                               <string>--browseTime</string>
-                               <string>18</string>
-                               <string>--countA</string>
-                               <string>2</string>
-                               <string>--countAAAA</string>
-                               <string>2</string>
-                               <string>--ipv6</string>
-                               <string>--udrop</string>
-                               <string>0.5</string>
-                               <string>--mdrop</string>
-                               <string>0.5</string>
-                               <string>--maxDropCount</string>
-                               <string>3</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--flushCache</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>DotLocal Queries</string>
-                       <key>Description</key>
-                       <string>Tests DNS and mDNS queries for domain names in the local domain.</string>
-                       <key>AsRoot</key>
-                       <false/>
-                       <key>RequiresWiFi</key>
-                       <true/>
-                       <key>Timeout</key>
-                       <integer>40</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>dotlocal</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>TCP Fallback</string>
-                       <key>Description</key>
-                       <string>Tests mDNSResponder&apos;s TCP fallback mechanism, which is triggered by UDP responses with invalid message IDs that would otherwise be acceptable.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <false/>
-                       <key>Timeout</key>
-                       <integer>60</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/local/bin/dnssdutil</string>
-                               <string>test</string>
-                               <string>gaiperf</string>
-                               <string>--suite</string>
-                               <string>basic</string>
-                               <string>--format</string>
-                               <string>json</string>
-                               <string>--appendNewLine</string>
-                               <string>--skipPathEval</string>
-                               <string>--badUDPMode</string>
-                       </array>
-               </dict>
-               <dict>
-                       <key>TestName</key>
-                       <string>mDNSResponder Leaks</string>
-                       <key>Description</key>
-                       <string>Checks mDNSResponder for memory leaks.</string>
-                       <key>AsRoot</key>
-                       <true/>
-                       <key>RequiresWiFi</key>
-                       <false/>
-                       <key>Timeout</key>
-                       <integer>10</integer>
-                       <key>IgnoreOutput</key>
-                       <true/>
-                       <key>Command</key>
-                       <array>
-                               <string>/usr/bin/leaks</string>
-                               <string>mDNSResponder</string>
-                       </array>
-               </dict>
-       </array>
-</dict>
-</plist>
index 4a35ff0b4e24a286c1c96bd0fcb49688f212340f..3acddd2e23df2e98c85980ae900e64ebd12fd0a3 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2015-2019 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.
@@ -277,8 +276,7 @@ mDNSlocal requestList_t * addToRequestList(requestList_t ** listHead, const doma
 
     if (!*ptr)
     {
-        *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
-        mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+        *ptr = (requestList_t *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
         (*ptr)->type = type;
         (*ptr)->flags = flags;
         AssignDomainName(&(*ptr)->name, name);
@@ -709,8 +707,7 @@ mDNSlocal responseList_t * addToResponseList(serviceHash_t peerBloomFilter, mDNS
 
     if (!*ptr)
     {
-        *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
-        mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+        *ptr = (responseList_t *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
         (*ptr)->peerBloomFilter = peerBloomFilter;
         memcpy(& (*ptr)->peerMac, ptrToMAC, sizeof(mDNSEthAddr));
     }
diff --git a/mDNSMacOSX/Bonjour Safari Extension/Base.lproj/SafariExtensionViewController.xib b/mDNSMacOSX/Bonjour Safari Extension/Base.lproj/SafariExtensionViewController.xib
new file mode 100644 (file)
index 0000000..4bb2cfa
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14205.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
+    <dependencies>
+        <deployment identifier="macosx"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14205.2"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <customObject id="-2" userLabel="File's Owner" customClass="SafariExtensionViewController">
+            <connections>
+                <outlet property="domainBrowserView" destination="37z-K3-tt2" id="lMe-Hz-bIu"/>
+                <outlet property="mainSplitView" destination="j4B-ff-oDf" id="As5-d3-ZaT"/>
+                <outlet property="serviceBrowserView" destination="Z6A-YV-gRJ" id="vPa-V8-NPE"/>
+                <outlet property="view" destination="j4B-ff-oDf" id="Ajs-fF-Ums"/>
+            </connections>
+        </customObject>
+        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+        <splitView arrangesAllSubviews="NO" dividerStyle="paneSplitter" id="j4B-ff-oDf">
+            <rect key="frame" x="0.0" y="0.0" width="309" height="200"/>
+            <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+            <subviews>
+                <customView fixedFrame="YES" id="Z6A-YV-gRJ" customClass="CNServiceBrowserView">
+                    <rect key="frame" x="0.0" y="0.0" width="309" height="114"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                    <connections>
+                        <outlet property="delegate" destination="-2" id="Aj5-LX-1WO"/>
+                    </connections>
+                </customView>
+                <customView fixedFrame="YES" id="37z-K3-tt2" customClass="CNDomainBrowserView">
+                    <rect key="frame" x="0.0" y="124" width="309" height="76"/>
+                    <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                    <userDefinedRuntimeAttributes>
+                        <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="YES"/>
+                    </userDefinedRuntimeAttributes>
+                    <connections>
+                        <outlet property="delegate" destination="-2" id="oQE-Gn-Jaw"/>
+                    </connections>
+                </customView>
+            </subviews>
+            <holdingPriorities>
+                <real value="250"/>
+                <real value="250"/>
+            </holdingPriorities>
+            <connections>
+                <outlet property="delegate" destination="-2" id="umg-fZ-b72"/>
+            </connections>
+            <point key="canvasLocation" x="-752" y="-484"/>
+        </splitView>
+    </objects>
+</document>
diff --git a/mDNSMacOSX/Bonjour Safari Extension/BonjourSafariExtension.entitlements b/mDNSMacOSX/Bonjour Safari Extension/BonjourSafariExtension.entitlements
new file mode 100644 (file)
index 0000000..625af03
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.security.app-sandbox</key>
+       <true/>
+       <key>com.apple.security.files.user-selected.read-only</key>
+       <true/>
+       <key>com.apple.security.network.client</key>
+       <true/>
+</dict>
+</plist>
diff --git a/mDNSMacOSX/Bonjour Safari Extension/CNServiceBrowserView.h b/mDNSMacOSX/Bonjour Safari Extension/CNServiceBrowserView.h
new file mode 100644 (file)
index 0000000..9af0289
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@protocol CNServiceBrowserViewDelegate;
+
+IB_DESIGNABLE
+
+@interface CNServiceBrowserView : NSView
+
+@property (strong) IBInspectable       NSArray *                                                       serviceTypes;
+@property (strong) IBInspectable       NSDictionary *                                          localizedServiceTypesDictionary;
+@property (weak)   IBOutlet                    id<CNServiceBrowserViewDelegate>        delegate;
+
+- (void)newServiceBrowse:(NSArray *)domainPath;
+
+@end
+
+@protocol CNServiceBrowserViewDelegate <NSObject>
+
+@optional
+
+- (void)bonjourServiceSelected:(NSString *)service type:(NSString *)type atDomain:(NSString *)domain;
+- (void)doubleAction:(NSURL *)url;
+
+@end
+
diff --git a/mDNSMacOSX/Bonjour Safari Extension/CNServiceBrowserView.m b/mDNSMacOSX/Bonjour Safari Extension/CNServiceBrowserView.m
new file mode 100644 (file)
index 0000000..3adc624
--- /dev/null
@@ -0,0 +1,644 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#import "CNServiceBrowserView.h"
+#import "CNDomainBrowserPathUtils.h"
+#include <dns_sd.h>
+
+#import <SafariServices/SafariServices.h>
+
+#define SHOW_SERVICETYPE_IF_SEARCH_COUNT       0
+
+const NSString *    _CNInstanceKey_fullName             = @"fullName";
+const NSString *    _CNInstanceKey_name                 = @"name";
+const NSString *    _CNInstanceKey_serviceType          = @"serviceType";
+const NSString *    _CNInstanceKey_domainPath           = @"domainPath";
+const NSString *    _CNInstanceKey_resolveUrl           = @"resolveUrl";
+const NSString *    _CNInstanceKey_resolveInstance      = @"resolveInstance";
+
+@interface _DNSServiceRefWrapper : NSObject
+{
+    DNSServiceRef    _ref;
+}
+
+- (instancetype)initWithRef:(DNSServiceRef)ref;
+@end
+
+@implementation _DNSServiceRefWrapper
+
+- (instancetype)initWithRef:(DNSServiceRef)ref
+{
+    if( self = [super init] )
+    {
+        _ref = ref;
+    }
+    return( self );
+}
+
+- (void)dealloc
+{
+    if( _ref ) DNSServiceRefDeallocate( _ref );
+}
+
+@end
+
+@implementation NSArray( CaseInsensitiveStringArrayCompare )
+
+- (BOOL)caseInsensitiveStringMatch:(NSArray *)inArray
+{
+    BOOL match = YES;
+    
+    if( self.count != [inArray count] )    match = NO;    //    Nil zero len ok
+    else
+    {
+        NSInteger    i = 0;
+        for( NSString * next in self )
+        {
+            NSString * inNext = inArray[i++];
+            if( ![inNext isKindOfClass: [NSString class]] || ![next isKindOfClass: [NSString class]] )
+            {
+                match = NO;
+                break;
+            }
+            else if( [next caseInsensitiveCompare: inNext] != NSOrderedSame )
+            {
+                match = NO;
+                break;
+            }
+        }
+    }
+    
+    return( match );
+}
+
+@end
+
+@protocol CNServiceTypeLocalizerDelegate <NSObject>
+@property (strong) NSDictionary * localizedServiceTypesDictionary;
+@end
+
+@interface CNServiceTypeLocalizer : NSValueTransformer
+{
+       id<CNServiceTypeLocalizerDelegate>      _delegate;
+}
+- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate;
+
+@end
+
+@implementation CNServiceTypeLocalizer
+
+- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate
+{
+       if( self = [super init] )
+       {
+               _delegate = delegate;
+       }
+       return( self );
+}
+
++ (Class)transformedValueClass
+{
+       return [NSString class];
+}
+
++ (BOOL)allowsReverseTransformation
+{
+       return NO;
+}
+
+- (nullable id)transformedValue:(nullable id)value
+{
+       id      result = value;
+       
+       if( value && _delegate && [_delegate respondsToSelector: @selector(localizedServiceTypesDictionary)] )
+       {
+               NSString *      localizedValue = [_delegate.localizedServiceTypesDictionary objectForKey: value];
+               if( localizedValue ) result = localizedValue;
+       }
+       
+       return( result );
+}
+
+@end
+
+@implementation NSBrowser( PathArray )
+
+- (NSArray *)pathArrayToColumn:(NSInteger)column includeSelectedRow:(BOOL)includeSelection
+{
+       NSMutableArray * pathArray = [NSMutableArray array];
+       if( !includeSelection ) column--;
+       for( NSInteger c = 0 ; c <= column ; c++ )
+       {
+               NSBrowserCell *cell = [self selectedCellInColumn: c];
+               if( cell ) [pathArray addObject: [cell stringValue]];
+       }
+       
+       return( pathArray );
+}
+
+@end
+
+static void resolveReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context );
+static void browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context );
+
+@interface CNServiceBrowserView ()
+
+@property (strong) NSTableView *                       instanceTable;
+@property (strong) NSArrayController *         instanceC;
+@property (strong) NSTableColumn *                     instanceNameColumn;
+@property (strong) NSTableColumn *                     instanceServiceTypeColumn;
+@property (strong) NSTableColumn *                     instancePathPopupColumn;
+
+@property (strong) CNServiceTypeLocalizer * serviceTypeLocalizer;
+
+@property (strong) NSArray *                currentDomainPath;
+@property (strong) NSMutableArray *         instanceRs;
+@property (strong) NSMutableDictionary *    instanceD;
+@property (strong) NSMutableArray *         instanceA;
+
+@property (strong) dispatch_queue_t         instanceBrowseQ;
+
+@end
+
+@implementation CNServiceBrowserView
+
+@synthesize serviceTypes = _serviceTypes;
+
+- (instancetype)initWithFrame:(NSRect)frameRect
+{
+       if( self = [super initWithFrame: frameRect] )
+       {
+               [self commonInit];
+       }
+       return( self );
+}
+
+- (nullable instancetype)initWithCoder:(NSCoder *)coder
+{
+       if( self = [super initWithCoder: coder] )
+       {
+               [self commonInit];
+       }
+       return( self );
+}
+
+
+- (void)contentViewsInit
+{
+       NSRect  frame = self.frame;
+       self.instanceC = [[NSArrayController alloc] init];
+       self.serviceTypeLocalizer = [[CNServiceTypeLocalizer alloc] initWithDelegate: (id<CNServiceTypeLocalizerDelegate>)self];
+       
+       //      My table view
+       NSTableView * tableView = [[NSTableView alloc] initWithFrame: frame];
+       tableView.columnAutoresizingStyle = NSTableViewFirstColumnOnlyAutoresizingStyle;
+       tableView.allowsColumnReordering = NO;
+       tableView.delegate = (id<NSTableViewDelegate>)self;
+    tableView.doubleAction = @selector( doubleAction:);
+       [tableView bind: NSContentBinding toObject: self.instanceC withKeyPath: @"arrangedObjects" options: nil];
+       self.instanceTable = tableView;
+
+       //      Scroll view for table
+       NSScrollView * tableContainer = [[NSScrollView alloc] initWithFrame: frame];
+       tableContainer.autoresizingMask = (NSViewHeightSizable | NSViewWidthSizable);
+       [tableContainer setDocumentView: tableView];
+
+       //      Name column
+       NSTableColumn * column = [[NSTableColumn alloc] init];
+       column.resizingMask = (NSTableColumnAutoresizingMask);
+       column.width = frame.size.width / 3;
+       column.minWidth = column.width / 2;
+       NSTextFieldCell * cell = [[NSTextFieldCell alloc] init];
+       cell.truncatesLastVisibleLine = YES;
+       column.dataCell = cell;
+       [column.headerCell setStringValue: NSLocalizedString( @"_dnsBrowser.instances.name", nil )];
+       [column bind: NSValueBinding toObject: self.instanceC withKeyPath: @"arrangedObjects.name" options: nil];
+       [tableView addTableColumn: column];
+       self.instanceNameColumn = column;
+       
+       //      Service type column
+       column = [[NSTableColumn alloc] init];
+       column.resizingMask = (NSTableColumnNoResizing);
+       column.width = frame.size.width / 3;
+       column.dataCell = [[NSTextFieldCell alloc] init];
+       [column.headerCell setStringValue: NSLocalizedString( @"_dnsBrowser.instances.type", nil )];
+       [column bind: NSValueBinding toObject: self.instanceC withKeyPath: @"arrangedObjects.serviceType" options: @{ NSValueTransformerBindingOption: self.serviceTypeLocalizer }];
+       [tableView addTableColumn: column];
+       self.instanceServiceTypeColumn = column;
+       
+       //      Path popup column
+       column = [[NSTableColumn alloc] init];
+       column.resizingMask = (NSTableColumnNoResizing);
+       column.width = frame.size.width / 3;
+       NSPopUpButtonCell * popUpCell = [[NSPopUpButtonCell alloc] init];
+       popUpCell.pullsDown = YES;
+       popUpCell.arrowPosition = NSPopUpArrowAtBottom;
+       popUpCell.autoenablesItems = YES;
+       popUpCell.preferredEdge = NSRectEdgeMaxY;
+    popUpCell.bezelStyle = NSBezelStyleTexturedSquare;
+       popUpCell.font = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
+       column.dataCell = popUpCell;
+       [column.headerCell setStringValue: NSLocalizedString( @"_dnsBrowser.instances.domain", nil )];
+       [column bind: NSContentBinding toObject: self.instanceC withKeyPath: @"arrangedObjects.domainPath" options: nil];
+       [tableView addTableColumn: column];
+       self.instancePathPopupColumn = column;
+    
+       [self addSubview: tableContainer];
+}
+
+- (void)commonInit
+{
+    self.serviceTypes = @[@"_http._tcp"];
+    self.instanceRs = [NSMutableArray array];
+    self.instanceD = [NSMutableDictionary dictionary];
+    self.instanceA = [NSMutableArray array];
+    
+    [self contentViewsInit];
+}
+
+- (void) setServiceTypes:(NSArray *)serviceTypes
+{
+       if( ![_serviceTypes isEqualTo: serviceTypes] )
+       {
+               _serviceTypes = serviceTypes;
+       }
+}
+
+- (NSArray *) serviceTypes
+{
+       return( _serviceTypes );
+}
+
+- (BOOL)foundInstancesWithMoreThanOneServiceType
+{
+    BOOL result = NO;
+    
+#if SHOW_SERVICETYPE_IF_SEARCH_COUNT
+    result = (_serviceTypes.count > 1);
+#else
+    if( _instanceD.count )
+    {
+        NSString * serviceType;
+        for( NSDictionary *next in [_instanceD allValues] )
+        {
+            if( !serviceType )
+            {
+                serviceType = next[_CNInstanceKey_serviceType];
+                continue;
+            }
+            else if( [next[_CNInstanceKey_serviceType] caseInsensitiveCompare: serviceType] != NSOrderedSame )
+            {
+                result = YES;
+                break;
+            }
+        }
+    }
+#endif
+    
+    return( result );
+}
+
+- (BOOL)foundInstancesInMoreThanCurrentDomainPath
+{
+    BOOL result = NO;
+    
+    if( _instanceD.count )
+    {
+        NSArray * selectedPathArray = [[_currentDomainPath reverseObjectEnumerator] allObjects];
+        if( !selectedPathArray.count ) selectedPathArray = [NSArray arrayWithObject: @"local"];
+        for( NSDictionary *next in [_instanceD allValues] )
+        {
+            if( [next[_CNInstanceKey_domainPath] caseInsensitiveStringMatch: selectedPathArray] )    continue;
+            else
+            {
+                result = YES;
+                break;
+            }
+        }
+    }
+    
+#if DEBUG_DOMAIN_POPUPS
+    return( YES );
+#else
+    return( result );
+#endif
+}
+
+#pragma mark - Notifications
+
+- (void)tableViewSelectionDidChange:(NSNotification *)notification
+{
+       if( _delegate && [_delegate respondsToSelector: @selector(bonjourServiceSelected:type:atDomain:)] &&
+           notification.object == self.instanceTable )
+       {
+               NSTableView * table = (NSTableView *)notification.object;
+               NSDictionary * record = nil;
+               if( table.selectedRow >= 0 && table.selectedRow < (NSInteger)[self.instanceC.content count] ) record = (NSDictionary *)self.instanceC.content[table.selectedRow];
+               
+        [_delegate bonjourServiceSelected: record[_CNInstanceKey_name]
+                                     type: record[_CNInstanceKey_serviceType]
+                                 atDomain: record ? DomainPathToDNSDomain( [[record[_CNInstanceKey_domainPath] reverseObjectEnumerator] allObjects] ) : nil];
+    }
+}
+
+
+#pragma mark - Delegates
+
+- (void)tableView:(NSTableView *)tableView willDisplayCell:(id)cell forTableColumn:(nullable NSTableColumn *)tableColumn row:(NSInteger)row
+{
+    (void)tableColumn;    // Unused
+    (void)row;            // Unused
+    if( tableView == self.instanceTable )
+       {
+               if( [cell isKindOfClass: [NSPopUpButtonCell class]] )
+               {
+                       NSPopUpButtonCell *     popCell = cell;
+                       if( popCell.numberOfItems > 1  )        popCell.arrowPosition = NSPopUpArrowAtBottom;
+                       else                                                            popCell.arrowPosition = NSPopUpNoArrow;
+               }
+       }
+}
+
+#if 0
+- (void)tableView:(NSTableView *)tableView didClickTableColumn:(NSTableColumn *)tableColumn
+{
+}
+#endif
+
+- (void) handleBrowseResults
+{
+    dispatch_async( dispatch_get_main_queue(), ^{
+        [self bonjourBrowserServiceBrowseUpdate: self->_instanceA];
+    });
+}
+
+- (void)bonjourBrowserServiceBrowseUpdate:(NSArray *)services
+{
+    self.instanceC.content = [services sortedArrayUsingComparator: ^( id obj1, id obj2 ) {
+        return (NSComparisonResult)[ obj1[_CNInstanceKey_name] compare: obj2[_CNInstanceKey_name]];
+    }];
+    [self adjustInstancesColumnWidths];
+}
+
+- (void) adjustInstancesColumnWidths
+{
+    self.instanceServiceTypeColumn.hidden = ![self foundInstancesWithMoreThanOneServiceType];
+    self.instancePathPopupColumn.hidden = ![self foundInstancesInMoreThanCurrentDomainPath];
+    
+    if( !self.instanceServiceTypeColumn.hidden || !self.instancePathPopupColumn.hidden )
+    {
+        BOOL        sizeChanged = NO;
+        CGFloat        maxWidthType = 0;
+        CGFloat        maxWidthDomain = 0;
+        BOOL        needRoomForPopup = NO;
+        NSDictionary * fontAttrType = @{ NSFontAttributeName: ((NSTextFieldCell *)self.instanceServiceTypeColumn.dataCell).font };
+        NSDictionary * fontAttrDomain = @{ NSFontAttributeName: ((NSTextFieldCell *)self.instancePathPopupColumn.dataCell).font };
+        
+        for( NSDictionary * next in self.instanceC.content )
+        {
+            NSString * serviceType = [self.serviceTypeLocalizer transformedValue: next[_CNInstanceKey_serviceType]];
+            NSSize        nextSize = [serviceType sizeWithAttributes: fontAttrType];
+            maxWidthType = MAX( nextSize.width, maxWidthType );
+            
+            NSArray *    path = next[_CNInstanceKey_domainPath];
+            nextSize = [path[0] sizeWithAttributes: fontAttrDomain];
+            maxWidthDomain = MAX( nextSize.width, maxWidthDomain );
+            if( path.count > 1 ) needRoomForPopup = YES;
+        }
+        
+#define EDGE_GAP    5
+#define POPUP_ARROW    22
+        
+        if( !self.instanceServiceTypeColumn.hidden )
+        {
+            maxWidthType += (EDGE_GAP * 2);
+            if( self.instanceServiceTypeColumn.width != maxWidthType )
+            {
+                self.instanceServiceTypeColumn.width = self.instanceServiceTypeColumn.minWidth = self.instanceServiceTypeColumn.maxWidth = maxWidthType;
+                sizeChanged = YES;
+            }
+        }
+        
+        if( !self.instancePathPopupColumn.hidden )
+        {
+            maxWidthDomain += (EDGE_GAP * 2) + needRoomForPopup ? POPUP_ARROW : 0;
+            if( self.instancePathPopupColumn.width != maxWidthDomain )
+            {
+                self.instancePathPopupColumn.width = self.instancePathPopupColumn.minWidth = self.instancePathPopupColumn.maxWidth = maxWidthDomain;
+                sizeChanged = YES;
+            }
+        }
+        
+        if( sizeChanged )
+        {
+            [self.instancePathPopupColumn.tableView sizeToFit];
+        }
+    }
+}
+
+#pragma mark - Dispatch
+
+static void finalizer( void * context )
+{
+    CNServiceBrowserView *self = (__bridge CNServiceBrowserView *)context;
+//    NSLog( @"finalizer: %@", self );
+    (void)CFBridgingRelease( (__bridge void *)self );
+}
+
+#pragma mark - Commands
+
+- (void)doubleAction:(id)sender
+{
+    if( _delegate && [_delegate respondsToSelector: @selector(doubleAction:)] &&
+       sender == self.instanceTable )
+    {
+        NSTableView * table = (NSTableView *)sender;
+        NSDictionary * record = nil;
+        if( table.selectedRow >= 0 && table.selectedRow < (NSInteger)[self.instanceC.content count] ) record = (NSDictionary *)self.instanceC.content[table.selectedRow];
+        [_delegate doubleAction: record[_CNInstanceKey_resolveUrl]];
+    }
+}
+
+- (void)newServiceBrowse:(NSArray *)domainPath
+{
+       if( _serviceTypes.count)
+       {
+        self.instanceC.content = nil;
+        [self browseForServiceTypes: _serviceTypes inDomainPath: domainPath];
+       }
+}
+
+- (void)browseForServiceTypes:(NSArray *)serviceTypes inDomainPath:(NSArray *)domainPath
+{
+    if( serviceTypes.count /*&& domainPath.count*/ )
+    {
+        _serviceTypes = [serviceTypes copy];
+        _currentDomainPath = [domainPath copy];
+        
+        NSString * domainStr = DomainPathToDNSDomain( _currentDomainPath );
+        
+        [_instanceRs removeAllObjects];
+        if( !_instanceBrowseQ )
+        {
+            self.instanceBrowseQ = dispatch_queue_create( "DNSServiceBrowse", DISPATCH_QUEUE_PRIORITY_DEFAULT );
+            dispatch_set_context( _instanceBrowseQ, (void *)CFBridgingRetain( self ) );
+            dispatch_set_finalizer_f( _instanceBrowseQ, finalizer );
+        }
+        
+        dispatch_sync( _instanceBrowseQ, ^{
+            [self->_instanceD removeAllObjects];
+            [self->_instanceA removeAllObjects];
+        });
+        
+        DNSServiceErrorType error;
+        DNSServiceRef mainRef;
+        if( (error = DNSServiceCreateConnection( &mainRef )) != 0 )
+            NSLog(@"DNSServiceCreateConnection failed error: %ld", error);
+        else
+        {
+            for( NSString * nextService in _serviceTypes )
+            {
+                DNSServiceRef ref = mainRef;
+                if( (error = DNSServiceBrowse( &ref, kDNSServiceFlagsShareConnection, 0, [nextService UTF8String], [domainStr UTF8String], browseReply, (__bridge void *)self )) != 0 )
+                    NSLog(@"DNSServiceBrowse failed error: %ld", error);
+                else
+                {
+                    [_instanceRs addObject: [[_DNSServiceRefWrapper alloc] initWithRef: ref]];
+                }
+            }
+            [_instanceRs addObject: [[_DNSServiceRefWrapper alloc] initWithRef: mainRef]];
+            if( !error )
+            {
+                error = DNSServiceSetDispatchQueue( mainRef, _instanceBrowseQ );
+                if( error ) NSLog( @"DNSServiceSetDispatchQueue error: %d", error );
+            }
+        }
+    }
+}
+
+- (void)resolveServiceInstance:(NSMutableDictionary *)record
+{
+    __weak NSDictionary *   weakRecord = record;
+    DNSServiceRef           ref;
+    DNSServiceErrorType     error;
+    NSString *              domainPath = DomainPathToDNSDomain( record[_CNInstanceKey_domainPath] );
+    
+    if( (error = DNSServiceResolve( &ref, (DNSServiceFlags)0, kDNSServiceInterfaceIndexAny, [record[_CNInstanceKey_name] UTF8String], [record[_CNInstanceKey_serviceType] UTF8String], [domainPath UTF8String], resolveReply, (__bridge void *)weakRecord )) != 0 )
+    {
+        NSLog(@"DNSServiceResolve failed error: %ld", error);
+    }
+    else
+    {
+        record[_CNInstanceKey_resolveInstance] = [[_DNSServiceRefWrapper alloc] initWithRef: ref];
+        error = DNSServiceSetDispatchQueue( ref, _instanceBrowseQ );
+        if( error ) NSLog( @"resolve DNSServiceSetDispatchQueue error: %d", error );
+    }
+}
+
+#pragma mark - Static Callbacks
+
+static void resolveReply( DNSServiceRef sdRef,
+                  DNSServiceFlags flags,
+                  uint32_t interfaceIndex,
+                  DNSServiceErrorType errorCode,
+                  const char *fullname,
+                  const char *hosttarget,
+                  uint16_t port,                                   /* In network byte order */
+                  uint16_t txtLen,
+                  const unsigned char *txtRecord,
+                  void *context )
+{
+    (void)sdRef;            //    Unused
+    (void)flags;            //    Unused
+    (void)interfaceIndex;   //    Unused
+    (void)errorCode;        //    Unused
+    (void)fullname;         //    Unused
+    __weak NSMutableDictionary * record = (__bridge __weak NSMutableDictionary *)context;
+    if( record && hosttarget )
+    {
+        NSURLComponents * urlComponents = [[NSURLComponents alloc] init];
+        urlComponents.scheme = @"http";
+        urlComponents.host = [NSString stringWithUTF8String: hosttarget];
+        if( TXTRecordContainsKey( txtLen, txtRecord, "path" ) )
+        {
+            uint8_t         valueLen;
+            const u_char *  valuePtr = TXTRecordGetValuePtr( txtLen, txtRecord, "path", &valueLen );
+            urlComponents.path = (__bridge_transfer NSString *)CFStringCreateWithBytes( kCFAllocatorDefault, valuePtr, valueLen, kCFStringEncodingUTF8, false );
+        }
+        if( port ) urlComponents.port = [NSNumber numberWithShort: NTOHS( port )];
+        record[_CNInstanceKey_resolveUrl] = urlComponents.URL;
+    }
+}
+
+static void browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context )
+{
+    (void)sdRef;            //    Unused
+    (void)interfaceIndex;   //    Unused
+    (void)errorCode;        //    Unused
+    CNServiceBrowserView *self = (__bridge CNServiceBrowserView *)context;
+    char fullNameBuffer[kDNSServiceMaxDomainName];
+    if( DNSServiceConstructFullName( fullNameBuffer, serviceName, regtype, replyDomain ) == kDNSServiceErr_NoError )
+    {
+        NSString *fullName = @(fullNameBuffer);
+        NSString *name = [NSString stringWithUTF8String: serviceName];
+        NSArray *pathArray = DNSDomainToDomainPath( [NSString stringWithUTF8String: replyDomain] );
+        
+        if( flags & kDNSServiceFlagsAdd )
+        {
+            BOOL    okToAdd = YES;
+            NSString * newServiceType = [[NSString stringWithUTF8String: regtype] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString: @"."]];
+            NSString * oldServiceType = [self.instanceD objectForKey: name][_CNInstanceKey_serviceType];
+            if( oldServiceType && ![newServiceType isEqualToString: oldServiceType] )
+            {
+                NSInteger newIndex = [self.serviceTypes indexOfObject: newServiceType];
+                NSInteger oldIndex = [self.serviceTypes indexOfObject: oldServiceType];
+                if( newIndex != NSNotFound && oldIndex != NSNotFound && oldIndex < newIndex ) okToAdd = NO;
+            }
+            if( okToAdd )
+            {
+                NSMutableDictionary * record = [NSMutableDictionary dictionary];
+                record[_CNInstanceKey_fullName] = fullName;
+                record[_CNInstanceKey_name] = name;
+                record[_CNInstanceKey_serviceType] = newServiceType;
+                record[_CNInstanceKey_domainPath] = [[pathArray reverseObjectEnumerator] allObjects];
+                [self.instanceD setObject: record
+                                   forKey: name];
+                [self resolveServiceInstance: record];
+            }
+        }
+        else
+        {
+            NSString * newServiceType = [[NSString stringWithUTF8String: regtype] stringByTrimmingCharactersInSet: [NSCharacterSet characterSetWithCharactersInString: @"."]];
+            NSDictionary * oldRecord = [self.instanceD objectForKey: name];
+            if( [oldRecord[_CNInstanceKey_serviceType] isEqualToString: newServiceType] )
+            {
+                [self.instanceD removeObjectForKey: name];
+            }
+        }
+        
+        if( !(flags & kDNSServiceFlagsMoreComing) )
+        {
+            dispatch_async( dispatch_get_main_queue(), ^{
+                [self.instanceA setArray: [[self.instanceD allValues] sortedArrayUsingComparator: ^( id obj1, id obj2 ) {
+                    return (NSComparisonResult)[obj1[_CNInstanceKey_name] compare: obj2[_CNInstanceKey_name] options: NSCaseInsensitiveSearch];
+                }]];
+                [self handleBrowseResults];
+            });
+        }
+    }
+}
+
+@end
diff --git a/mDNSMacOSX/Bonjour Safari Extension/Info.plist b/mDNSMacOSX/Bonjour Safari Extension/Info.plist
new file mode 100644 (file)
index 0000000..59fe5a8
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>$(DEVELOPMENT_LANGUAGE)</string>
+       <key>CFBundleDisplayName</key>
+       <string>Bonjour Safari Extension</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>XPC!</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.1</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+       <key>NSExtension</key>
+       <dict>
+               <key>NSExtensionPointIdentifier</key>
+               <string>com.apple.Safari.extension</string>
+               <key>NSExtensionPrincipalClass</key>
+               <string>SafariExtensionHandler</string>
+               <key>SFSafariToolbarItem</key>
+               <dict>
+                       <key>Action</key>
+                       <string>Popover</string>
+                       <key>Identifier</key>
+                       <string>Button</string>
+                       <key>Image</key>
+                       <string>ToolbarItemIcon.png</string>
+                       <key>Label</key>
+                       <string>Browse</string>
+               </dict>
+               <key>SFSafariWebsiteAccess</key>
+               <dict>
+                       <key>Level</key>
+                       <string>All</string>
+               </dict>
+       </dict>
+       <key>NSHumanReadableDescription</key>
+       <string>Bonjour service browsing done correctly!</string>
+</dict>
+</plist>
diff --git a/mDNSMacOSX/Bonjour Safari Extension/Localizable.strings b/mDNSMacOSX/Bonjour Safari Extension/Localizable.strings
new file mode 100644 (file)
index 0000000..9da1ddb
--- /dev/null
@@ -0,0 +1,11 @@
+/* 
+  Localizable.strings
+  Domain Browser
+
+  Created by Phil on 1/7/16.
+  Copyright © 2016 Phil. All rights reserved.
+*/
+
+"_dnsBrowser.instances.name" = "Name";
+"_dnsBrowser.instances.type" = "Kind";
+"_dnsBrowser.instances.domain" = "Domain";
diff --git a/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionHandler.h b/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionHandler.h
new file mode 100644 (file)
index 0000000..ce8f793
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import <SafariServices/SafariServices.h>
+
+@interface SafariExtensionHandler : SFSafariExtensionHandler
+
+@end
diff --git a/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionHandler.m b/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionHandler.m
new file mode 100644 (file)
index 0000000..9e8e626
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import "SafariExtensionHandler.h"
+#import "SafariExtensionViewController.h"
+
+//#define SHOW_BROWSE_COUNT 1
+
+#if SHOW_BROWSE_COUNT
+#include <dns_sd.h>
+
+static void browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context );
+#endif
+
+@interface SafariExtensionHandler ()
+
+@property (strong) NSMutableDictionary *    instanceD;
+#if SHOW_BROWSE_COUNT
+@property (strong) dispatch_queue_t         instanceBrowseQ;
+@property (assign) DNSServiceRef            instanceRef;    //  Never released!!!
+#endif
+
+@end
+
+@implementation SafariExtensionHandler
+
+- (instancetype)init
+{
+    if( self = [super init] )
+    {
+#if SHOW_BROWSE_COUNT
+        self.instanceD = [NSMutableDictionary dictionary];
+        [self startInstanceBrowse];
+#endif
+    }
+    return( self );
+}
+
+- (void)validateToolbarItemInWindow:(SFSafariWindow *)window validationHandler:(void (^)(BOOL enabled, NSString *badgeText))validationHandler {
+    // This method will be called whenever some state changes in the passed in window. You should use this as a chance to enable or disable your toolbar item and set badge text.
+    (void)window;    // Unused
+    validationHandler(YES, _instanceD.count ? [NSNumber numberWithInteger: _instanceD.count].stringValue : @"");
+}
+
+- (SFSafariExtensionViewController *)popoverViewController {
+    return [SafariExtensionViewController sharedController];
+}
+
+#if SHOW_BROWSE_COUNT
+- (void)startInstanceBrowse
+{
+    if( !_instanceBrowseQ )
+    {
+        self.instanceBrowseQ = dispatch_queue_create( "DNSAllServiceBrowse", DISPATCH_QUEUE_PRIORITY_DEFAULT );
+        dispatch_set_context( _instanceBrowseQ, (void *)CFBridgingRetain( self ) );
+        dispatch_set_finalizer_f( _instanceBrowseQ, finalizer );
+    }
+    
+    dispatch_sync( _instanceBrowseQ, ^{
+        [_instanceD removeAllObjects];
+    });
+    
+    DNSServiceErrorType error;
+    if( (error = DNSServiceBrowse( &_instanceRef, 0/*no flags*/, 0, @"_http._tcp".UTF8String, "", browseReply, (__bridge void *)self )) != 0 )
+        NSLog(@"DNSServiceBrowse failed error: %ld", error);
+    
+    if( !error )
+    {
+        error = DNSServiceSetDispatchQueue( _instanceRef, _instanceBrowseQ );
+        if( error ) NSLog( @"DNSServiceSetDispatchQueue error: %d", error );
+    }
+}
+
+#pragma mark - Dispatch
+
+static void finalizer( void * context )
+{
+    SafariExtensionHandler *self = (__bridge SafariExtensionHandler *)context;
+    NSLog( @"finalizer: %@", self );
+    (void)CFBridgingRelease( (__bridge void *)self );
+}
+
+#pragma mark - DNS callbacks
+
+static void browseReply( DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context )
+{
+    (void)sdRef;            //    Unused
+    (void)interfaceIndex;   //    Unused
+    (void)errorCode;        //    Unused
+    SafariExtensionHandler *self = (__bridge SafariExtensionHandler *)context;
+    char fullNameBuffer[kDNSServiceMaxDomainName];
+    if( DNSServiceConstructFullName( fullNameBuffer, serviceName, regtype, replyDomain ) == kDNSServiceErr_NoError )
+    {
+        NSString *fullName = @(fullNameBuffer);
+        
+        if( flags & kDNSServiceFlagsAdd )
+        {
+            [self.instanceD setObject: fullName
+                               forKey: fullName];
+        }
+        else
+        {
+            [self.instanceD removeObjectForKey: fullName];
+        }
+    }
+}
+#endif
+
+@end
diff --git a/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionViewController.h b/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionViewController.h
new file mode 100644 (file)
index 0000000..abb1cb8
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import <SafariServices/SafariServices.h>
+
+#import "CNServiceBrowserView.h"
+#import "CNDomainBrowserView.h"
+
+@interface SafariExtensionViewController : SFSafariExtensionViewController
+
+@property (weak)   IBOutlet            NSSplitView *                mainSplitView;
+@property (weak)   IBOutlet            CNServiceBrowserView *       serviceBrowserView;
+@property (weak)   IBOutlet            CNDomainBrowserView *        domainBrowserView;
+
++ (SafariExtensionViewController *)sharedController;
+
+@end
diff --git a/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionViewController.m b/mDNSMacOSX/Bonjour Safari Extension/SafariExtensionViewController.m
new file mode 100644 (file)
index 0000000..8531765
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import "SafariExtensionViewController.h"
+#import "CNDomainBrowserPathUtils.h"
+
+@interface SafariExtensionViewController ()
+
+@end
+
+@implementation SafariExtensionViewController
+
++ (SafariExtensionViewController *)sharedController {
+    static SafariExtensionViewController *sharedController = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        sharedController = [[SafariExtensionViewController alloc] init];
+    });
+    return sharedController;
+}
+
+- (void)viewWillAppear
+{
+    [super viewWillAppear];
+    [_domainBrowserView startBrowse];
+    [_mainSplitView adjustSubviews];
+}
+
+- (void) viewWillDisappear
+{
+    [super viewWillDisappear];
+    [_domainBrowserView stopBrowse];
+}
+
+#pragma mark - BServiceBrowser Delegates
+
+- (void)bonjourServiceSelected:(NSString *)service type:(NSString *)type atDomain:(NSString *)domain
+{
+    (void)service;  // unused
+    (void)type;     // unused
+    (void)domain;   // unused
+}
+
+- (void)doubleAction:(NSURL *)url
+{
+    if (url)
+    {
+        [SFSafariApplication getActiveWindowWithCompletionHandler:^(SFSafariWindow * _Nullable activeWindow) {
+            [activeWindow openTabWithURL: url makeActiveIfPossible: YES completionHandler:^(SFSafariTab * _Nullable tab) {
+                (void)tab;         // Unused
+            }];
+        }];
+        [self dismissPopover];
+    }
+}
+
+#pragma mark - BonjourBrowser Delegates
+
+- (void)domainBrowserDomainUpdate:(NSString *)defaultDomain
+{
+    [_serviceBrowserView newServiceBrowse: DNSDomainToDomainPath(defaultDomain)];
+    if( !_domainBrowserView.selectedDNSDomain.length )
+    {
+        [_mainSplitView setPosition: [_mainSplitView maxPossiblePositionOfDividerAtIndex: 0] ofDividerAtIndex: 0];
+    }
+    else
+    {
+        [_mainSplitView adjustSubviews];
+        [_domainBrowserView showSelectedRow];
+    }
+}
+
+- (void)domainBrowserDomainSelected:(NSString *)domain
+{
+    [_serviceBrowserView newServiceBrowse: DNSDomainToDomainPath(domain)];
+}
+
+#pragma mark - SplitView Delegate
+
+- (CGFloat)splitView:(NSSplitView *)splitView constrainSplitPosition:(CGFloat)proposedPosition ofSubviewAt:(NSInteger)dividerIndex
+{
+    (void)splitView; // Unused
+#define TOP_MIN        40
+    CGFloat    pos;
+    CGFloat bottomMinHeight = [_domainBrowserView minimumHeight];
+    
+    if( proposedPosition < TOP_MIN )
+    {
+        pos = TOP_MIN;
+    }
+    else if( proposedPosition < [_mainSplitView maxPossiblePositionOfDividerAtIndex: dividerIndex] - bottomMinHeight )
+    {
+        pos = proposedPosition;
+    }
+    else
+    {
+        pos = [_mainSplitView maxPossiblePositionOfDividerAtIndex: dividerIndex] - bottomMinHeight;
+    }
+    
+    //    Make sure selected rows stay in view
+    [_domainBrowserView showSelectedRow];
+    
+    return( pos );
+}
+
+- (BOOL)splitView:(NSSplitView *)splitView shouldHideDividerAtIndex:(NSInteger)dividerIndex
+{
+    (void)splitView;       // Unused
+    (void)dividerIndex;    // Unused
+    return( ![_domainBrowserView foundInstanceInMoreThanLocalDomain] );
+}
+
+- (BOOL)splitView:(NSSplitView *)splitView shouldAdjustSizeOfSubview:(NSView *)view
+{
+    (void)splitView;    // Unused
+    (void)view;         // Unused
+    return YES;         // Having this override seems to make some non-wanted resizes to not occur
+}
+
+@end
diff --git a/mDNSMacOSX/Bonjour Safari Extension/ToolbarItemIcon.png b/mDNSMacOSX/Bonjour Safari Extension/ToolbarItemIcon.png
new file mode 100644 (file)
index 0000000..bc38234
Binary files /dev/null and b/mDNSMacOSX/Bonjour Safari Extension/ToolbarItemIcon.png differ
diff --git a/mDNSMacOSX/Bonjour Safari Extension/script.js b/mDNSMacOSX/Bonjour Safari Extension/script.js
new file mode 100644 (file)
index 0000000..34f7e35
--- /dev/null
@@ -0,0 +1,3 @@
+document.addEventListener("DOMContentLoaded", function(event) {
+    safari.extension.dispatchMessage("Hello World!");
+});
diff --git a/mDNSMacOSX/Bonjour Safari Menu/AppDelegate.h b/mDNSMacOSX/Bonjour Safari Menu/AppDelegate.h
new file mode 100644 (file)
index 0000000..96c3556
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface AppDelegate : NSObject <NSApplicationDelegate>
+
+
+@end
+
diff --git a/mDNSMacOSX/Bonjour Safari Menu/AppDelegate.m b/mDNSMacOSX/Bonjour Safari Menu/AppDelegate.m
new file mode 100644 (file)
index 0000000..45276fa
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import "AppDelegate.h"
+
+@interface AppDelegate ()
+
+@end
+
+@implementation AppDelegate
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+    // Insert code here to initialize your application
+    (void)aNotification;    // Unused
+}
+
+
+- (void)applicationWillTerminate:(NSNotification *)aNotification {
+    // Insert code here to tear down your application
+    (void)aNotification;    // Unused
+}
+
+
+@end
diff --git a/mDNSMacOSX/Bonjour Safari Menu/Assets.xcassets/AppIcon.appiconset/Contents.json b/mDNSMacOSX/Bonjour Safari Menu/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644 (file)
index 0000000..2db2b1c
--- /dev/null
@@ -0,0 +1,58 @@
+{
+  "images" : [
+    {
+      "idiom" : "mac",
+      "size" : "16x16",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "16x16",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "32x32",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "32x32",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "128x128",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "128x128",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "256x256",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "256x256",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "512x512",
+      "scale" : "1x"
+    },
+    {
+      "idiom" : "mac",
+      "size" : "512x512",
+      "scale" : "2x"
+    }
+  ],
+  "info" : {
+    "version" : 1,
+    "author" : "xcode"
+  }
+}
\ No newline at end of file
diff --git a/mDNSMacOSX/Bonjour Safari Menu/Base.lproj/Main.storyboard b/mDNSMacOSX/Bonjour Safari Menu/Base.lproj/Main.storyboard
new file mode 100644 (file)
index 0000000..48c941d
--- /dev/null
@@ -0,0 +1,725 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="13168.4" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="13168.4"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--Application-->
+        <scene sceneID="JPo-4y-FX3">
+            <objects>
+                <application id="hnw-xV-0zn" sceneMemberID="viewController">
+                    <menu key="mainMenu" title="Main Menu" systemMenu="main" id="AYu-sK-qS6">
+                        <items>
+                            <menuItem title="Bonjour Browser" id="1Xt-HY-uBw">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Bonjour Browser" systemMenu="apple" id="uQy-DD-JDr">
+                                    <items>
+                                        <menuItem title="About Bonjour Browser" id="5kV-Vb-QxS">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="orderFrontStandardAboutPanel:" target="Ady-hI-5gd" id="Exp-CZ-Vem"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="VOq-y0-SEH"/>
+                                        <menuItem title="Preferences…" keyEquivalent="," id="BOF-NM-1cW"/>
+                                        <menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
+                                        <menuItem title="Services" id="NMo-om-nkz">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="4je-JR-u6R"/>
+                                        <menuItem title="Hide Bonjour Browser" keyEquivalent="h" id="Olw-nP-bQN">
+                                            <connections>
+                                                <action selector="hide:" target="Ady-hI-5gd" id="PnN-Uc-m68"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Hide Others" keyEquivalent="h" id="Vdr-fp-XzO">
+                                            <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                            <connections>
+                                                <action selector="hideOtherApplications:" target="Ady-hI-5gd" id="VT4-aY-XCT"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Show All" id="Kd2-mp-pUS">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="unhideAllApplications:" target="Ady-hI-5gd" id="Dhg-Le-xox"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="kCx-OE-vgT"/>
+                                        <menuItem title="Quit Bonjour Browser" keyEquivalent="q" id="4sb-4s-VLi">
+                                            <connections>
+                                                <action selector="terminate:" target="Ady-hI-5gd" id="Te7-pn-YzF"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="File" id="dMs-cI-mzQ">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="File" id="bib-Uj-vzu">
+                                    <items>
+                                        <menuItem title="New" keyEquivalent="n" id="Was-JA-tGl">
+                                            <connections>
+                                                <action selector="newDocument:" target="Ady-hI-5gd" id="4Si-XN-c54"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Open…" keyEquivalent="o" id="IAo-SY-fd9">
+                                            <connections>
+                                                <action selector="openDocument:" target="Ady-hI-5gd" id="bVn-NM-KNZ"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Open Recent" id="tXI-mr-wws">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="oas-Oc-fiZ">
+                                                <items>
+                                                    <menuItem title="Clear Menu" id="vNY-rz-j42">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="clearRecentDocuments:" target="Ady-hI-5gd" id="Daa-9d-B3U"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
+                                        <menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
+                                            <connections>
+                                                <action selector="performClose:" target="Ady-hI-5gd" id="HmO-Ls-i7Q"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Save…" keyEquivalent="s" id="pxx-59-PXV">
+                                            <connections>
+                                                <action selector="saveDocument:" target="Ady-hI-5gd" id="teZ-XB-qJY"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Save As…" keyEquivalent="S" id="Bw7-FT-i3A">
+                                            <connections>
+                                                <action selector="saveDocumentAs:" target="Ady-hI-5gd" id="mDf-zr-I0C"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Revert to Saved" keyEquivalent="r" id="KaW-ft-85H">
+                                            <connections>
+                                                <action selector="revertDocumentToSaved:" target="Ady-hI-5gd" id="iJ3-Pv-kwq"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="aJh-i4-bef"/>
+                                        <menuItem title="Page Setup…" keyEquivalent="P" id="qIS-W8-SiK">
+                                            <modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
+                                            <connections>
+                                                <action selector="runPageLayout:" target="Ady-hI-5gd" id="Din-rz-gC5"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Print…" keyEquivalent="p" id="aTl-1u-JFS">
+                                            <connections>
+                                                <action selector="print:" target="Ady-hI-5gd" id="qaZ-4w-aoO"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Edit" id="5QF-Oa-p0T">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Edit" id="W48-6f-4Dl">
+                                    <items>
+                                        <menuItem title="Undo" keyEquivalent="z" id="dRJ-4n-Yzg">
+                                            <connections>
+                                                <action selector="undo:" target="Ady-hI-5gd" id="M6e-cu-g7V"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Redo" keyEquivalent="Z" id="6dh-zS-Vam">
+                                            <connections>
+                                                <action selector="redo:" target="Ady-hI-5gd" id="oIA-Rs-6OD"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="WRV-NI-Exz"/>
+                                        <menuItem title="Cut" keyEquivalent="x" id="uRl-iY-unG">
+                                            <connections>
+                                                <action selector="cut:" target="Ady-hI-5gd" id="YJe-68-I9s"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Copy" keyEquivalent="c" id="x3v-GG-iWU">
+                                            <connections>
+                                                <action selector="copy:" target="Ady-hI-5gd" id="G1f-GL-Joy"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Paste" keyEquivalent="v" id="gVA-U4-sdL">
+                                            <connections>
+                                                <action selector="paste:" target="Ady-hI-5gd" id="UvS-8e-Qdg"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Paste and Match Style" keyEquivalent="V" id="WeT-3V-zwk">
+                                            <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                            <connections>
+                                                <action selector="pasteAsPlainText:" target="Ady-hI-5gd" id="cEh-KX-wJQ"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Delete" id="pa3-QI-u2k">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="delete:" target="Ady-hI-5gd" id="0Mk-Ml-PaM"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Select All" keyEquivalent="a" id="Ruw-6m-B2m">
+                                            <connections>
+                                                <action selector="selectAll:" target="Ady-hI-5gd" id="VNm-Mi-diN"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="uyl-h8-XO2"/>
+                                        <menuItem title="Find" id="4EN-yA-p0u">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Find" id="1b7-l0-nxx">
+                                                <items>
+                                                    <menuItem title="Find…" tag="1" keyEquivalent="f" id="Xz5-n4-O0W">
+                                                        <connections>
+                                                            <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="cD7-Qs-BN4"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="YEy-JH-Tfz">
+                                                        <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                                        <connections>
+                                                            <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="WD3-Gg-5AJ"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Find Next" tag="2" keyEquivalent="g" id="q09-fT-Sye">
+                                                        <connections>
+                                                            <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="NDo-RZ-v9R"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Find Previous" tag="3" keyEquivalent="G" id="OwM-mh-QMV">
+                                                        <connections>
+                                                            <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="HOh-sY-3ay"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="buJ-ug-pKt">
+                                                        <connections>
+                                                            <action selector="performFindPanelAction:" target="Ady-hI-5gd" id="U76-nv-p5D"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Jump to Selection" keyEquivalent="j" id="S0p-oC-mLd">
+                                                        <connections>
+                                                            <action selector="centerSelectionInVisibleArea:" target="Ady-hI-5gd" id="IOG-6D-g5B"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                        <menuItem title="Spelling and Grammar" id="Dv1-io-Yv7">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Spelling" id="3IN-sU-3Bg">
+                                                <items>
+                                                    <menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="HFo-cy-zxI">
+                                                        <connections>
+                                                            <action selector="showGuessPanel:" target="Ady-hI-5gd" id="vFj-Ks-hy3"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Check Document Now" keyEquivalent=";" id="hz2-CU-CR7">
+                                                        <connections>
+                                                            <action selector="checkSpelling:" target="Ady-hI-5gd" id="fz7-VC-reM"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem isSeparatorItem="YES" id="bNw-od-mp5"/>
+                                                    <menuItem title="Check Spelling While Typing" id="rbD-Rh-wIN">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleContinuousSpellChecking:" target="Ady-hI-5gd" id="7w6-Qz-0kB"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Check Grammar With Spelling" id="mK6-2p-4JG">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleGrammarChecking:" target="Ady-hI-5gd" id="muD-Qn-j4w"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Correct Spelling Automatically" id="78Y-hA-62v">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleAutomaticSpellingCorrection:" target="Ady-hI-5gd" id="2lM-Qi-WAP"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                        <menuItem title="Substitutions" id="9ic-FL-obx">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Substitutions" id="FeM-D8-WVr">
+                                                <items>
+                                                    <menuItem title="Show Substitutions" id="z6F-FW-3nz">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="orderFrontSubstitutionsPanel:" target="Ady-hI-5gd" id="oku-mr-iSq"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem isSeparatorItem="YES" id="gPx-C9-uUO"/>
+                                                    <menuItem title="Smart Copy/Paste" id="9yt-4B-nSM">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleSmartInsertDelete:" target="Ady-hI-5gd" id="3IJ-Se-DZD"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Smart Quotes" id="hQb-2v-fYv">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleAutomaticQuoteSubstitution:" target="Ady-hI-5gd" id="ptq-xd-QOA"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Smart Dashes" id="rgM-f4-ycn">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleAutomaticDashSubstitution:" target="Ady-hI-5gd" id="oCt-pO-9gS"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Smart Links" id="cwL-P1-jid">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleAutomaticLinkDetection:" target="Ady-hI-5gd" id="Gip-E3-Fov"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Data Detectors" id="tRr-pd-1PS">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleAutomaticDataDetection:" target="Ady-hI-5gd" id="R1I-Nq-Kbl"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Text Replacement" id="HFQ-gK-NFA">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleAutomaticTextReplacement:" target="Ady-hI-5gd" id="DvP-Fe-Py6"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                        <menuItem title="Transformations" id="2oI-Rn-ZJC">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Transformations" id="c8a-y6-VQd">
+                                                <items>
+                                                    <menuItem title="Make Upper Case" id="vmV-6d-7jI">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="uppercaseWord:" target="Ady-hI-5gd" id="sPh-Tk-edu"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Make Lower Case" id="d9M-CD-aMd">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="lowercaseWord:" target="Ady-hI-5gd" id="iUZ-b5-hil"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Capitalize" id="UEZ-Bs-lqG">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="capitalizeWord:" target="Ady-hI-5gd" id="26H-TL-nsh"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                        <menuItem title="Speech" id="xrE-MZ-jX0">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Speech" id="3rS-ZA-NoH">
+                                                <items>
+                                                    <menuItem title="Start Speaking" id="Ynk-f8-cLZ">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="startSpeaking:" target="Ady-hI-5gd" id="654-Ng-kyl"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Stop Speaking" id="Oyz-dy-DGm">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="stopSpeaking:" target="Ady-hI-5gd" id="dX8-6p-jy9"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Format" id="jxT-CU-nIS">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Format" id="GEO-Iw-cKr">
+                                    <items>
+                                        <menuItem title="Font" id="Gi5-1S-RQB">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Font" systemMenu="font" id="aXa-aM-Jaq">
+                                                <items>
+                                                    <menuItem title="Show Fonts" keyEquivalent="t" id="Q5e-8K-NDq"/>
+                                                    <menuItem title="Bold" tag="2" keyEquivalent="b" id="GB9-OM-e27"/>
+                                                    <menuItem title="Italic" tag="1" keyEquivalent="i" id="Vjx-xi-njq"/>
+                                                    <menuItem title="Underline" keyEquivalent="u" id="WRG-CD-K1S">
+                                                        <connections>
+                                                            <action selector="underline:" target="Ady-hI-5gd" id="FYS-2b-JAY"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem isSeparatorItem="YES" id="5gT-KC-WSO"/>
+                                                    <menuItem title="Bigger" tag="3" keyEquivalent="+" id="Ptp-SP-VEL"/>
+                                                    <menuItem title="Smaller" tag="4" keyEquivalent="-" id="i1d-Er-qST"/>
+                                                    <menuItem isSeparatorItem="YES" id="kx3-Dk-x3B"/>
+                                                    <menuItem title="Kern" id="jBQ-r6-VK2">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <menu key="submenu" title="Kern" id="tlD-Oa-oAM">
+                                                            <items>
+                                                                <menuItem title="Use Default" id="GUa-eO-cwY">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="useStandardKerning:" target="Ady-hI-5gd" id="6dk-9l-Ckg"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Use None" id="cDB-IK-hbR">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="turnOffKerning:" target="Ady-hI-5gd" id="U8a-gz-Maa"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Tighten" id="46P-cB-AYj">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="tightenKerning:" target="Ady-hI-5gd" id="hr7-Nz-8ro"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Loosen" id="ogc-rX-tC1">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="loosenKerning:" target="Ady-hI-5gd" id="8i4-f9-FKE"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                            </items>
+                                                        </menu>
+                                                    </menuItem>
+                                                    <menuItem title="Ligatures" id="o6e-r0-MWq">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <menu key="submenu" title="Ligatures" id="w0m-vy-SC9">
+                                                            <items>
+                                                                <menuItem title="Use Default" id="agt-UL-0e3">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="useStandardLigatures:" target="Ady-hI-5gd" id="7uR-wd-Dx6"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Use None" id="J7y-lM-qPV">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="turnOffLigatures:" target="Ady-hI-5gd" id="iX2-gA-Ilz"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Use All" id="xQD-1f-W4t">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="useAllLigatures:" target="Ady-hI-5gd" id="KcB-kA-TuK"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                            </items>
+                                                        </menu>
+                                                    </menuItem>
+                                                    <menuItem title="Baseline" id="OaQ-X3-Vso">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <menu key="submenu" title="Baseline" id="ijk-EB-dga">
+                                                            <items>
+                                                                <menuItem title="Use Default" id="3Om-Ey-2VK">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="unscript:" target="Ady-hI-5gd" id="0vZ-95-Ywn"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Superscript" id="Rqc-34-cIF">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="superscript:" target="Ady-hI-5gd" id="3qV-fo-wpU"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Subscript" id="I0S-gh-46l">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="subscript:" target="Ady-hI-5gd" id="Q6W-4W-IGz"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Raise" id="2h7-ER-AoG">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="raiseBaseline:" target="Ady-hI-5gd" id="4sk-31-7Q9"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem title="Lower" id="1tx-W0-xDw">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="lowerBaseline:" target="Ady-hI-5gd" id="OF1-bc-KW4"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                            </items>
+                                                        </menu>
+                                                    </menuItem>
+                                                    <menuItem isSeparatorItem="YES" id="Ndw-q3-faq"/>
+                                                    <menuItem title="Show Colors" keyEquivalent="C" id="bgn-CT-cEk">
+                                                        <connections>
+                                                            <action selector="orderFrontColorPanel:" target="Ady-hI-5gd" id="mSX-Xz-DV3"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem isSeparatorItem="YES" id="iMs-zA-UFJ"/>
+                                                    <menuItem title="Copy Style" keyEquivalent="c" id="5Vv-lz-BsD">
+                                                        <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                                        <connections>
+                                                            <action selector="copyFont:" target="Ady-hI-5gd" id="GJO-xA-L4q"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Paste Style" keyEquivalent="v" id="vKC-jM-MkH">
+                                                        <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                                        <connections>
+                                                            <action selector="pasteFont:" target="Ady-hI-5gd" id="JfD-CL-leO"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                        <menuItem title="Text" id="Fal-I4-PZk">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <menu key="submenu" title="Text" id="d9c-me-L2H">
+                                                <items>
+                                                    <menuItem title="Align Left" keyEquivalent="{" id="ZM1-6Q-yy1">
+                                                        <connections>
+                                                            <action selector="alignLeft:" target="Ady-hI-5gd" id="zUv-R1-uAa"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Center" keyEquivalent="|" id="VIY-Ag-zcb">
+                                                        <connections>
+                                                            <action selector="alignCenter:" target="Ady-hI-5gd" id="spX-mk-kcS"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Justify" id="J5U-5w-g23">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="alignJustified:" target="Ady-hI-5gd" id="ljL-7U-jND"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Align Right" keyEquivalent="}" id="wb2-vD-lq4">
+                                                        <connections>
+                                                            <action selector="alignRight:" target="Ady-hI-5gd" id="r48-bG-YeY"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem isSeparatorItem="YES" id="4s2-GY-VfK"/>
+                                                    <menuItem title="Writing Direction" id="H1b-Si-o9J">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <menu key="submenu" title="Writing Direction" id="8mr-sm-Yjd">
+                                                            <items>
+                                                                <menuItem title="Paragraph" enabled="NO" id="ZvO-Gk-QUH">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                </menuItem>
+                                                                <menuItem id="YGs-j5-SAR">
+                                                                    <string key="title">       Default</string>
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="makeBaseWritingDirectionNatural:" target="Ady-hI-5gd" id="qtV-5e-UBP"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem id="Lbh-J2-qVU">
+                                                                    <string key="title">       Left to Right</string>
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="makeBaseWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="S0X-9S-QSf"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem id="jFq-tB-4Kx">
+                                                                    <string key="title">       Right to Left</string>
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="makeBaseWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="5fk-qB-AqJ"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem isSeparatorItem="YES" id="swp-gr-a21"/>
+                                                                <menuItem title="Selection" enabled="NO" id="cqv-fj-IhA">
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                </menuItem>
+                                                                <menuItem id="Nop-cj-93Q">
+                                                                    <string key="title">       Default</string>
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="makeTextWritingDirectionNatural:" target="Ady-hI-5gd" id="lPI-Se-ZHp"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem id="BgM-ve-c93">
+                                                                    <string key="title">       Left to Right</string>
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="makeTextWritingDirectionLeftToRight:" target="Ady-hI-5gd" id="caW-Bv-w94"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                                <menuItem id="RB4-Sm-HuC">
+                                                                    <string key="title">       Right to Left</string>
+                                                                    <modifierMask key="keyEquivalentModifierMask"/>
+                                                                    <connections>
+                                                                        <action selector="makeTextWritingDirectionRightToLeft:" target="Ady-hI-5gd" id="EXD-6r-ZUu"/>
+                                                                    </connections>
+                                                                </menuItem>
+                                                            </items>
+                                                        </menu>
+                                                    </menuItem>
+                                                    <menuItem isSeparatorItem="YES" id="fKy-g9-1gm"/>
+                                                    <menuItem title="Show Ruler" id="vLm-3I-IUL">
+                                                        <modifierMask key="keyEquivalentModifierMask"/>
+                                                        <connections>
+                                                            <action selector="toggleRuler:" target="Ady-hI-5gd" id="FOx-HJ-KwY"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Copy Ruler" keyEquivalent="c" id="MkV-Pr-PK5">
+                                                        <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+                                                        <connections>
+                                                            <action selector="copyRuler:" target="Ady-hI-5gd" id="71i-fW-3W2"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                    <menuItem title="Paste Ruler" keyEquivalent="v" id="LVM-kO-fVI">
+                                                        <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+                                                        <connections>
+                                                            <action selector="pasteRuler:" target="Ady-hI-5gd" id="cSh-wd-qM2"/>
+                                                        </connections>
+                                                    </menuItem>
+                                                </items>
+                                            </menu>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="View" id="H8h-7b-M4v">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="View" id="HyV-fh-RgO">
+                                    <items>
+                                        <menuItem title="Show Toolbar" keyEquivalent="t" id="snW-S8-Cw5">
+                                            <modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
+                                            <connections>
+                                                <action selector="toggleToolbarShown:" target="Ady-hI-5gd" id="BXY-wc-z0C"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Customize Toolbar…" id="1UK-8n-QPP">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="runToolbarCustomizationPalette:" target="Ady-hI-5gd" id="pQI-g3-MTW"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="hB3-LF-h0Y"/>
+                                        <menuItem title="Show Sidebar" keyEquivalent="s" id="kIP-vf-haE">
+                                            <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+                                            <connections>
+                                                <action selector="toggleSourceList:" target="Ady-hI-5gd" id="iwa-gc-5KM"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Enter Full Screen" keyEquivalent="f" id="4J7-dP-txa">
+                                            <modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
+                                            <connections>
+                                                <action selector="toggleFullScreen:" target="Ady-hI-5gd" id="dU3-MA-1Rq"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Window" id="aUF-d1-5bR">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
+                                    <items>
+                                        <menuItem title="Minimize" keyEquivalent="m" id="OY7-WF-poV">
+                                            <connections>
+                                                <action selector="performMiniaturize:" target="Ady-hI-5gd" id="VwT-WD-YPe"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem title="Zoom" id="R4o-n2-Eq4">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
+                                            </connections>
+                                        </menuItem>
+                                        <menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
+                                        <menuItem title="Bring All to Front" id="LE2-aR-0XJ">
+                                            <modifierMask key="keyEquivalentModifierMask"/>
+                                            <connections>
+                                                <action selector="arrangeInFront:" target="Ady-hI-5gd" id="DRN-fu-gQh"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                            <menuItem title="Help" id="wpr-3q-Mcd">
+                                <modifierMask key="keyEquivalentModifierMask"/>
+                                <menu key="submenu" title="Help" systemMenu="help" id="F2S-fz-NVQ">
+                                    <items>
+                                        <menuItem title="Bonjour Browser Help" keyEquivalent="?" id="FKE-Sm-Kum">
+                                            <connections>
+                                                <action selector="showHelp:" target="Ady-hI-5gd" id="y7X-2Q-9no"/>
+                                            </connections>
+                                        </menuItem>
+                                    </items>
+                                </menu>
+                            </menuItem>
+                        </items>
+                    </menu>
+                    <connections>
+                        <outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
+                    </connections>
+                </application>
+                <customObject id="Voe-Tx-rLC" customClass="AppDelegate"/>
+                <customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="75" y="0.0"/>
+        </scene>
+        <!--Window Controller-->
+        <scene sceneID="R2V-B0-nI4">
+            <objects>
+                <windowController id="B8D-0N-5wS" sceneMemberID="viewController">
+                    <window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA">
+                        <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
+                        <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+                        <rect key="contentRect" x="196" y="240" width="480" height="270"/>
+                        <rect key="screenRect" x="0.0" y="0.0" width="1680" height="1027"/>
+                        <connections>
+                            <outlet property="delegate" destination="B8D-0N-5wS" id="fUp-Xf-31I"/>
+                        </connections>
+                    </window>
+                    <connections>
+                        <segue destination="XfG-lQ-9wD" kind="relationship" relationship="window.shadowedContentViewController" id="cq2-FE-JQM"/>
+                    </connections>
+                </windowController>
+                <customObject id="Oky-zY-oP4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="75" y="250"/>
+        </scene>
+        <!--View Controller-->
+        <scene sceneID="hIz-AP-VOD">
+            <objects>
+                <viewController id="XfG-lQ-9wD" customClass="ViewController" sceneMemberID="viewController">
+                    <view key="view" wantsLayer="YES" id="m2S-Jp-Qdl">
+                        <rect key="frame" x="0.0" y="0.0" width="480" height="98"/>
+                        <autoresizingMask key="autoresizingMask"/>
+                        <subviews>
+                            <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="f6l-UI-b0D">
+                                <rect key="frame" x="18" y="61" width="444" height="17"/>
+                                <textFieldCell key="cell" controlSize="mini" sendsActionOnEndEditing="YES" title="Bonjour Extension is now available in Safari Preferences -&gt; Extensions." id="6Xu-Rw-IYC">
+                                    <font key="font" metaFont="system"/>
+                                    <color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
+                                    <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                                </textFieldCell>
+                            </textField>
+                            <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="5MO-TQ-SSP">
+                                <rect key="frame" x="207" y="13" width="66" height="32"/>
+                                <buttonCell key="cell" type="push" title="Quit" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="4ZK-hH-R4H">
+                                    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                    <font key="font" metaFont="system"/>
+                                </buttonCell>
+                                <connections>
+                                    <action selector="quitApplication:" target="XfG-lQ-9wD" id="hQ6-fO-Ta5"/>
+                                </connections>
+                            </button>
+                        </subviews>
+                        <constraints>
+                            <constraint firstItem="f6l-UI-b0D" firstAttribute="leading" secondItem="m2S-Jp-Qdl" secondAttribute="leading" constant="20" symbolic="YES" id="5Ip-jd-yAV"/>
+                            <constraint firstAttribute="trailing" secondItem="f6l-UI-b0D" secondAttribute="trailing" constant="20" symbolic="YES" id="8gP-Ct-bgO"/>
+                            <constraint firstAttribute="bottom" secondItem="5MO-TQ-SSP" secondAttribute="bottom" constant="20" symbolic="YES" id="DJs-6e-2R0"/>
+                            <constraint firstItem="f6l-UI-b0D" firstAttribute="top" secondItem="m2S-Jp-Qdl" secondAttribute="top" constant="20" symbolic="YES" id="I3T-04-FFK"/>
+                            <constraint firstItem="5MO-TQ-SSP" firstAttribute="centerX" secondItem="m2S-Jp-Qdl" secondAttribute="centerX" id="Vv7-8v-iuF"/>
+                            <constraint firstItem="5MO-TQ-SSP" firstAttribute="top" secondItem="f6l-UI-b0D" secondAttribute="bottom" constant="20" symbolic="YES" id="rPC-vd-MAr"/>
+                        </constraints>
+                    </view>
+                </viewController>
+                <customObject id="rPt-NT-nkU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
+            </objects>
+            <point key="canvasLocation" x="75" y="575"/>
+        </scene>
+    </scenes>
+</document>
diff --git a/mDNSMacOSX/Bonjour Safari Menu/BonjourSafariMenu.entitlements b/mDNSMacOSX/Bonjour Safari Menu/BonjourSafariMenu.entitlements
new file mode 100644 (file)
index 0000000..f2ef3ae
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>com.apple.security.app-sandbox</key>
+    <true/>
+    <key>com.apple.security.files.user-selected.read-only</key>
+    <true/>
+</dict>
+</plist>
diff --git a/mDNSMacOSX/Bonjour Safari Menu/Info.plist b/mDNSMacOSX/Bonjour Safari Menu/Info.plist
new file mode 100644 (file)
index 0000000..e40caef
--- /dev/null
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>$(DEVELOPMENT_LANGUAGE)</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIconFile</key>
+       <string></string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+       <key>LSMinimumSystemVersion</key>
+       <string>$(MACOSX_DEPLOYMENT_TARGET)</string>
+       <key>NSMainStoryboardFile</key>
+       <string>Main</string>
+       <key>NSPrincipalClass</key>
+       <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/mDNSMacOSX/Bonjour Safari Menu/ViewController.h b/mDNSMacOSX/Bonjour Safari Menu/ViewController.h
new file mode 100644 (file)
index 0000000..6a1f407
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+@interface ViewController : NSViewController
+
+
+@end
+
diff --git a/mDNSMacOSX/Bonjour Safari Menu/ViewController.m b/mDNSMacOSX/Bonjour Safari Menu/ViewController.m
new file mode 100644 (file)
index 0000000..c321124
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import "ViewController.h"
+
+@implementation ViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    // Do any additional setup after loading the view.
+}
+
+
+- (void)setRepresentedObject:(id)representedObject {
+    [super setRepresentedObject:representedObject];
+
+    // Update the view, if already loaded.
+}
+
+- (IBAction)quitApplication:(id)sender
+{
+    (void)sender;       // Unused
+    [NSApplication.sharedApplication terminate: sender];
+}
+
+@end
diff --git a/mDNSMacOSX/Bonjour Safari Menu/main.m b/mDNSMacOSX/Bonjour Safari Menu/main.m
new file mode 100644 (file)
index 0000000..c500f39
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ *
+ * Copyright (c) 2017 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, const char * argv[]) {
+    return NSApplicationMain(argc, argv);
+}
index ff201c9fa68afe79cf4e728c646a39b58d673172..e495cc67291cf89647b91da32a04c7769d2c8a1a 100644 (file)
@@ -315,13 +315,13 @@ void CBonjourTop::UpdateRecord(CStringTree&  Cache,CDNSRecord* pDNSRecord,BJStri
     if (pRecord == NULL)
     {
         pRecord = (CStringNode*) Cache.FindwithAddRecord(&nHashValue);
-        strcpy(pRecord->m_Value, RecordName.GetBuffer());
+        strlcpy(pRecord->m_Value, RecordName.GetBuffer(), sizeof(pRecord->m_Value));
     }
 
     if (pRecord == NULL)
         return;
     CDeviceNode dummyDevice;
-    CDeviceNode *device = &dummyDevice;
+    CDeviceNode *device;
     CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
 
     device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
@@ -534,14 +534,14 @@ void CBonjourTop::UpdateShortRecord(CStringShortTree*  Cache,CDNSRecord* pDNSRec
     }
 
     BJ_UINT64 nHashValue = 0;
-    char deviceOS = '?';
 
     nHashValue = Hash(RecordName.GetBuffer());
     CStringShortNode* pRecord = Cache->Find(&nHashValue);
     if (pRecord == NULL)
     {
         pRecord = (CStringShortNode*) Cache->FindwithAddRecord(&nHashValue);
-        strcpy(pRecord->m_Value, RecordName.GetBuffer());
+        if (pRecord)
+            strlcpy(pRecord->m_Value, RecordName.GetBuffer(), sizeof(pRecord->m_Value));
     }
 
     if (pRecord == NULL)
@@ -550,12 +550,11 @@ void CBonjourTop::UpdateShortRecord(CStringShortTree*  Cache,CDNSRecord* pDNSRec
     }
 
     CDeviceNode dummyDevice;
-    CDeviceNode *device = &dummyDevice;
+    CDeviceNode *device;
     CIPDeviceNode *pipNode = m_IPtoNameMap.Find(&m_Frame.m_SourceIPAddress);
 
     device = (pipNode)? pipNode->pDeviceNode : &dummyDevice;
     pRecord->m_nBytes += 10 + nBytes;
-    deviceOS = device->GetDeviceOS();
     device->frameTotal.Increment(m_nFrameCount);
 
     if (pRecord->m_nLastFrameIndex != m_nFrameCount)
@@ -1849,22 +1848,10 @@ void CStringNode::UpdateOSTypeCounts(CDeviceMap* pGlobalDeviceMap,CIPAddrMap *pI
     m_nDeviceTotaliOSCount = 0;
     m_nDeviceTotalOSXCount = 0;
     m_DeviceAskingTree.GetDeviceOSTypes(m_DeviceAskingTree.GetRoot(),pIp2NameMap,m_nDeviceAskingiOSCount,m_nDeviceAskingOSXCount,nDeviceUnknown);
-    if (m_DeviceAskingTree.GetCount() != m_nDeviceAskingiOSCount + m_nDeviceAskingOSXCount+nDeviceUnknown)
-    {
-        nDeviceUnknown = 0;
-    }
     nDeviceUnknown = 0;
     m_DeviceAnsweringTree.GetDeviceOSTypes(m_DeviceAnsweringTree.GetRoot(),pIp2NameMap,m_nDeviceAnsweringiOSCount,m_nDeviceAnsweringOSXCount,nDeviceUnknown);
-    if (m_DeviceAnsweringTree.GetCount() != m_nDeviceAnsweringiOSCount + m_nDeviceAnsweringOSXCount+nDeviceUnknown)
-    {
-        nDeviceUnknown = 0;
-    }
     nDeviceUnknown = 0;
     m_DeviceTotalTree.GetDeviceOSTypes(m_DeviceTotalTree.GetRoot(), pIp2NameMap, m_nDeviceTotaliOSCount, m_nDeviceTotalOSXCount, nDeviceUnknown);
-    if (m_DeviceTotalTree.GetCount() != m_nDeviceTotaliOSCount + m_nDeviceTotalOSXCount + nDeviceUnknown)
-    {
-        nDeviceUnknown = 0;
-    }
 }
 
 void CStringNode::Print(bool bCursers,bool bDescendingSort,BJ_UINT32 &nIndex, BJ_UINT32 nStartIndex,BJ_UINT32 nEndIndex)
index 9a678c0dacc7fa812c06a7929acce245426e99e8..d915b54bf8c231f20985df5d8a054de79dcc87e9 100644 (file)
@@ -315,7 +315,7 @@ public:
                m_nAnswerFrames = pSrc->m_nAnswerFrames;
                m_nAnswerFramesiOS = pSrc->m_nAnswerFramesiOS;
                m_nAnswerFramesOSX = pSrc->m_nAnswerFramesOSX;
-               strcpy(m_Value,pSrc->m_Value);
+               strlcpy(m_Value,pSrc->m_Value,sizeof(m_Value));
                m_nDeviceAskingCount = pSrc->m_nDeviceAskingCount;
                m_nDeviceAskingiOSCount = pSrc->m_nDeviceAskingiOSCount;
                m_nDeviceAskingOSXCount = pSrc->m_nDeviceAskingOSXCount;
@@ -415,7 +415,7 @@ public:
                m_nFrames = pSrc->m_nFrames;
                m_nQuestionFrames = pSrc->m_nQuestionFrames;
                m_nAnswerFrames = pSrc->m_nAnswerFrames;
-               strcpy(m_Value,pSrc->m_Value);
+               strlcpy(m_Value,pSrc->m_Value,sizeof(m_Value));
                m_nDeviceAskingCount = pSrc->m_nDeviceAskingCount;
                m_nDeviceAnsweringCount = pSrc->m_nDeviceAnsweringCount;
                m_nDeviceTotalCount = pSrc->m_nDeviceTotalCount;
index 9387fcab61edd0da1c9392c9517a14ced2f0e692..c42822cf7175af5d75a0ff82863c923e109086e1 100644 (file)
@@ -156,9 +156,10 @@ void CollectByService::Collect(CDNSFrame* pFrame,CollectByAbstract* nextCollectB
 
 
         CServiceNode *pNode= m_Cache.FindwithAddRecord(&RecordName);
-        if (pNode->pNext == NULL)
+        if ((pNode->pNext == NULL) && nextCollectBy)
             pNode->pNext = nextCollectBy->Factory();
-        pNode->pNext->Collect(pFrame,nextCollectBy?nextCollectBy->pNext:NULL);
+        if (pNode->pNext)
+            pNode->pNext->Collect(pFrame,nextCollectBy?nextCollectBy->pNext:NULL);
 
     }
 
@@ -226,9 +227,10 @@ void CollectByIPAddressType::Collect(CDNSFrame* pFrame,CollectByAbstract* nextCo
     }
     if (pFrame->m_SourceIPAddress.IsIPv6())
     {
-        if (pIPv6Next == NULL)
+        if ((pIPv6Next == NULL) && nextCollectBy)
             pIPv6Next = nextCollectBy->Factory();
-        pIPv6Next->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
+        if (pIPv6Next)
+            pIPv6Next->Collect(pFrame, nextCollectBy?nextCollectBy->pNext:NULL);
     }
 }
 void CollectByIPAddressType::Export(FILE* hFile,BJString sPrevColumns)
index 1e8586a089448d1ad67f52b7a791809e2f6c61f1..fc85a83ab3934c989d0e79b956f34f6ec3b04efe 100644 (file)
@@ -175,7 +175,6 @@ BJ_BOOL CDNSFrame::ParseDnsRecord(CDNSRecord::dnsItemType eItemType)
 
     //temp
     BJ_UINT16 nRdataLen = 0;
-    BJ_UINT16 nRdataLen2 = 0;
 
     if (pTemp > m_pEndBuffer)
     {
@@ -240,8 +239,6 @@ BJ_BOOL CDNSFrame::ParseDnsRecord(CDNSRecord::dnsItemType eItemType)
         if (nRdataLen > 1024*10)
         {
             printf("large Rdata ??");
-            nRdataLen2 = (pTemp[8] << 8) | pTemp[9];
-
         }
         //    printf("Namelen=%u, Type=%u, class=%u, TTL=%u, RDLength=%u\n", m_dnsItems[ndnsIndex].nNameLength,m_dnsItems[ndnsIndex].RecType,nClass,nTTL,m_dnsItems[ndnsIndex].nRdataLen);
         pTemp += 10 + pRecord->m_nRdataLen;
index 5a6fcdf10972b558be581070563d094940db462b..5fbcf59b2e5836a668f46efe71f38b282731dea7 100644 (file)
@@ -44,7 +44,8 @@ BJString& BJString::operator=(const char* str)
 
 BJString& BJString::operator=(const BJString& str)
 {
-    Set(str.GetBuffer());
+    if (&str != this)
+        Set(str.GetBuffer());
     return *this;
 }
 bool BJString::operator==(const char* str)
@@ -118,8 +119,8 @@ BJString& BJString::operator+=(const char* str)
 
     BJString temp = buffer;
     Create((BJ_UINT32)(strlen(buffer) + strlen(str)));
-    strcpy(buffer,temp.GetBuffer());
-    strcat(buffer,str);
+    strlcpy(buffer, temp.GetBuffer(), length + 1);
+    strlcat(buffer, str, length + 1);
     return *this;
 }
 BJString& BJString::operator+=(const BJString&str)
@@ -142,7 +143,7 @@ void BJString::Set(const char* str)
         len = 250;
     Create(len);
     if (buffer && str)
-           strcpy(buffer, str);
+        strlcpy(buffer, str, length + 1);
 
 }
 void BJString::Set(const char* str, BJ_UINT32 len)
@@ -164,7 +165,7 @@ void BJString::Append(const char* str, BJ_UINT32 len)
         BJString temp = buffer;
         Create((BJ_UINT32)(strlen(buffer) + strlen(str)));
         if (buffer && temp.buffer)
-            strcpy(buffer,temp.GetBuffer());
+            strlcpy(buffer, temp.GetBuffer(), length + 1);
     }
     strncat(buffer,str,len);
 }
@@ -210,15 +211,13 @@ void BJString::Format(BJ_UINT64 number,BJ_FORMAT_STYLE style)
 
 void BJString::Create(BJ_UINT32 len)
 {
-    if (length >= len)
-    {
-        if (length > 0)
-            memset(buffer, 0, len+1);
-        return;
-    }
-
     if (buffer)
     {
+        if (length >= len)
+        {
+            memset(buffer, 0, len + 1);
+            return;
+        }
         delete buffer;
         buffer = NULL;
         length = 0;
index 57c70179e489ada4333929192e5529d95ec57c68..5ed3dee09d9ab755f6551d20ab38c1b68eb1ea12 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2011-2019 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.
@@ -30,7 +29,7 @@
 #include "DNSSECSupport.h"
 
 #if TARGET_OS_IPHONE
-#include "SecRSAKey.h"                  // For RSA_SHA1 etc. verification
+#include <Security/SecRSAKey.h>                  // For RSA_SHA1 etc. verification
 #else
 #include <Security/Security.h>
 #endif
@@ -54,7 +53,7 @@ mDNSlocal mStatus enc_create(AlgContext *ctx)
     {
     case ENC_BASE32:
     case ENC_BASE64:
-        ptr = (encContext *)mDNSPlatformMemAllocate(sizeof(encContext));
+        ptr = (encContext *) mDNSPlatformMemAllocateClear(sizeof(*ptr));
         if (!ptr) return mStatus_NoMemoryErr;
         break;
     default:
@@ -161,12 +160,12 @@ mDNSlocal mStatus sha_create(AlgContext *ctx)
     switch (ctx->alg)
     {
     case SHA1_DIGEST_TYPE:
-        ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
+        ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
         if (!ptr) return mStatus_NoMemoryErr;
         CC_SHA1_Init((CC_SHA1_CTX *)ptr);
         break;
     case SHA256_DIGEST_TYPE:
-        ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
+        ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
         if (!ptr) return mStatus_NoMemoryErr;
         CC_SHA256_Init((CC_SHA256_CTX *)ptr);
         break;
@@ -282,17 +281,17 @@ mDNSlocal mStatus rsa_sha_create(AlgContext *ctx)
     {
     case CRYPTO_RSA_NSEC3_SHA1:
     case CRYPTO_RSA_SHA1:
-        ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
+        ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA1_CTX));
         if (!ptr) return mStatus_NoMemoryErr;
         CC_SHA1_Init((CC_SHA1_CTX *)ptr);
         break;
     case CRYPTO_RSA_SHA256:
-        ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
+        ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA256_CTX));
         if (!ptr) return mStatus_NoMemoryErr;
         CC_SHA256_Init((CC_SHA256_CTX *)ptr);
         break;
     case CRYPTO_RSA_SHA512:
-        ptr = mDNSPlatformMemAllocate(sizeof(CC_SHA512_CTX));
+        ptr = (mDNSu8 *) mDNSPlatformMemAllocate(sizeof(CC_SHA512_CTX));
         if (!ptr) return mStatus_NoMemoryErr;
         CC_SHA512_Init((CC_SHA512_CTX *)ptr);
         break;
@@ -644,8 +643,8 @@ mDNSlocal Boolean VerifyData(SecKeyRef key, CFStringRef digestStr, mDNSu8 *diges
     }
     
     CFBooleanRef boolRef = SecTransformExecute(verifyXForm, &error);
-    ret = boolRef ? CFBooleanGetValue(boolRef) : false;
-    if (boolRef) CFRelease(boolRef);
+    ret = (boolRef != NULL) ? CFBooleanGetValue(boolRef) : false;
+    if (boolRef != NULL) CFRelease(boolRef);
     CFRelease(verifyXForm);
 
     if (error != NULL)
index 6ad8e945dd1250387c0cca7dd993fad38ea443c6..4194d6f86ea8c378aa5439e0ff97d764aac556f8 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
@@ -33,7 +32,7 @@ D2DStatus D2DStartBrowsingForKeyOnTransport(const Byte *key, const size_t keySiz
 D2DStatus D2DStopBrowsingForKeyOnTransport(const Byte *key, const size_t keySize, D2DTransportType transport) __attribute__((weak_import));
 void D2DStartResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
 void D2DStopResolvingPairOnTransport(const Byte *key, const size_t keySize, const Byte *value, const size_t valueSize, D2DTransportType transport) __attribute__((weak_import));
-D2DStatus D2DTerminate() __attribute__((weak_import));
+D2DStatus D2DTerminate(void) __attribute__((weak_import));
 
 #pragma mark - D2D Support
 
@@ -245,8 +244,7 @@ mDNSlocal void D2DBrowseListRetain(const domainname *const name, mDNSu16 type)
 
     if (!*ptr)
     {
-        *ptr = mDNSPlatformMemAllocate(sizeof(**ptr));
-        mDNSPlatformMemZero(*ptr, sizeof(**ptr));
+        *ptr = (D2DBrowseListElem *) mDNSPlatformMemAllocateClear(sizeof(**ptr));
         (*ptr)->type = type;
         AssignDomainName(&(*ptr)->name, name);
     }
@@ -351,7 +349,7 @@ mDNSlocal mStatus xD2DParse(const mDNSu8 * const lhs, const mDNSu16 lhs_len, con
         LogInfo("xD2DParse: got rr: %s", CRDisplayString(m, &m->rec.r));
     }
 
-    *D2DListp = mDNSPlatformMemAllocate(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
+    *D2DListp = (D2DRecordListElem *) mDNSPlatformMemAllocateClear(sizeof(D2DRecordListElem) + (m->rec.r.resrec.rdlength <= sizeof(RDataBody) ? 0 : m->rec.r.resrec.rdlength - sizeof(RDataBody)));
     if (!*D2DListp) return mStatus_NoMemoryErr;
 
     AuthRecord *rr = &(*D2DListp)->ar;
@@ -926,6 +924,31 @@ mDNSexport void external_stop_resolving_service(mDNSInterfaceID InterfaceID, con
     }
 }
 
+mDNSexport mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags)
+{
+    // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
+    if (    (((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL | kDNSServiceFlagsAutoTrigger)))
+            || mDNSPlatformInterfaceIsD2D(InterfaceID) || (InterfaceID == mDNSInterface_BLE))
+        && IsLocalDomain(domain))
+    {
+        return mDNStrue;
+    }
+    else
+        return mDNSfalse;
+}
+
+// Used to derive the original D2D specific flags specified by the client in the registration
+// when we don't have access to the original flag (kDNSServiceFlags*) values.
+mDNSexport mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType)
+{
+    mDNSu32 flags = 0;
+    if ((authRecType == AuthRecordAnyIncludeP2P) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
+        flags |= kDNSServiceFlagsIncludeP2P;
+    else if ((authRecType == AuthRecordAnyIncludeAWDL) || (authRecType == AuthRecordAnyIncludeAWDLandP2P))
+        flags |= kDNSServiceFlagsIncludeAWDL;
+    return flags;
+}
+
 void initializeD2DPlugins(mDNS *const m)
 {
         // We only initialize if mDNSCore successfully initialized.
index a9850728a8a5cba86c5c6c7262c39cc624dc2a22..be008fd03d8ef825cde51fdb92a0cee382291b85 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2015-2016 Apple Inc. All rights reserved.
+ * Copyright (c) 2015-2018 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.
@@ -30,6 +30,21 @@ extern void internal_stop_advertising_service(const ResourceRecord *const resour
 void xD2DAddToCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
 void xD2DRemoveFromCache(D2DStatus result, D2DServiceInstance instanceHandle, D2DTransportType transportType, const Byte *key, size_t keySize, const Byte *value, size_t valueSize);
 
+extern mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags);
+extern mDNSu32 deriveD2DFlagsFromAuthRecType(AuthRecType authRecType);
+extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
+extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
+extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
+extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
+extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
+extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
+extern void external_connection_release(const domainname *instance);
+
+extern void D2D_start_advertising_interface(NetworkInterfaceInfo *interface);
+extern void D2D_stop_advertising_interface(NetworkInterfaceInfo *interface);
+extern void D2D_start_advertising_record(AuthRecord *ar);
+extern void D2D_stop_advertising_record(AuthRecord *ar);
+
 #if ENABLE_BLE_TRIGGERED_BONJOUR
 // Just define as the current max value for now for BLE.c prototype.
 // TODO: Will need to define in DeviceToDeviceManager.framework if we convert the
index e167cdde7164747a3cb838edadba40a64ecc75be..3aa54c86b6ae9dbe50e92dc4a89f88a05f4bab12 100644 (file)
  * limitations under the License.
  */
 
-#include <TargetConditionals.h>
-
-// DNS64 code is only for iOS, which is currently the only Apple OS that supports DNS proxy network extensions.
-
-#if TARGET_OS_IOS
 #include "DNS64.h"
 
-#include <AssertMacros.h>
-
-#if __has_include(<nw/private.h>)
-    #include <nw/private.h>
-#else
-    #include <network/nat64.h>
-#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
 
+#include <AssertMacros.h>
+#include <nw/private.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "dns_sd.h"
 #include "dns_sd_internal.h"
+#include "mDNSMacOSX.h"
 #include "uDNS.h"
 
 //===========================================================================================================================
@@ -54,12 +46,13 @@ check_compile_time(sizeof_field(DNS64, qnameStash)  == kDNS64IPv4OnlyFQDNLength)
 //  Local Prototypes
 //===========================================================================================================================
 
-mDNSlocal mStatus   DNS64GetIPv6Addrs(mDNS *m, mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
-mDNSlocal mStatus   DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
-mDNSlocal mDNSBool  DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr);
-mDNSlocal mDNSu32   DNS64IPv4OnlyFQDNHash(void);
-mDNSlocal void      DNS64RestartQuestion(mDNS *m, DNSQuestion *q, DNS64State newState);
-mDNSlocal mDNSBool  DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr);
+mDNSlocal mStatus   _DNS64GetIPv6Addrs(mDNS *m, mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount);
+mDNSlocal mStatus   _DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount);
+mDNSlocal mDNSBool  _DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr);
+mDNSlocal mDNSu32   _DNS64IPv4OnlyFQDNHash(void);
+mDNSlocal void      _DNS64RestartQuestion(mDNS *m, DNSQuestion *q, DNS64State newState);
+mDNSlocal mDNSBool  _DNS64InterfaceSupportsNAT64(uint32_t inIfIndex);
+mDNSlocal mDNSBool  _DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr);
 
 //===========================================================================================================================
 //  DNS64StateMachine
@@ -83,21 +76,21 @@ mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceR
             if ((inQ->qtype      == kDNSType_AAAA) &&
                 (inRR->rrtype    == kDNSType_AAAA) &&
                 (inRR->rrclass   == kDNSClass_IN) &&
-                ((inQ->qnamehash != DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
+                ((inQ->qnamehash != _DNS64IPv4OnlyFQDNHash()) || !SameDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN)) &&
                 inQ->qDNSServer &&
-                nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface))
+                _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)))
             {
-                DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
+                _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscovery);
                 return (mDNStrue);
             }
             else if ((inQ->qtype == kDNSType_PTR) &&
                 (inRR->rrtype    == kDNSType_PTR) &&
                 (inRR->rrclass   == kDNSClass_IN) &&
                 inQ->qDNSServer &&
-                nw_nat64_does_interface_index_support_nat64((uint32_t)(uintptr_t)inQ->qDNSServer->interface) &&
-                DNS64GetReverseIPv6Addr(&inQ->qname, NULL))
+                _DNS64InterfaceSupportsNAT64((uint32_t)((uintptr_t)inQ->qDNSServer->interface)) &&
+                _DNS64GetReverseIPv6Addr(&inQ->qname, NULL))
             {
-                DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
+                _DNS64RestartQuestion(m, inQ, kDNS64State_PrefixDiscoveryPTR);
                 return (mDNStrue);
             }
         }
@@ -113,12 +106,12 @@ mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceR
             (inRR->rrtype     == kDNSType_AAAA) &&
             (inRR->rrclass    == kDNSClass_IN))
         {
-            DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
+            _DNS64RestartQuestion(m, inQ, kDNS64State_QueryA);
             return (mDNStrue);
         }
         else
         {
-            DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
+            _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
             return (mDNStrue);
         }
         break;
@@ -127,7 +120,7 @@ mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceR
     // whether or not to change it to a reverse IPv4 question.
 
     case kDNS64State_PrefixDiscoveryPTR:
-        DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
+        _DNS64RestartQuestion(m, inQ, kDNS64State_QueryPTR);
         return (mDNStrue);
         break;
 
@@ -144,13 +137,13 @@ mDNSexport mDNSBool DNS64StateMachine(mDNS *m, DNSQuestion *inQ, const ResourceR
                 (inRR->rrtype     == kDNSType_A) &&
                 (inRR->rrclass    == kDNSClass_IN) &&
                 inQ->qDNSServer &&
-                DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
+                _DNS64TestIPv6Synthesis(m, inQ->qDNSServer->resGroupID, &inRR->rdata->u.ipv4))
             {
                 inQ->dns64.state = kDNS64State_QueryA2;
             }
             else
             {
-                DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
+                _DNS64RestartQuestion(m, inQ, kDNS64State_QueryAAAA);
                 return (mDNStrue);
             }
         }
@@ -191,7 +184,7 @@ mDNSexport mStatus DNS64AnswerCurrentQuestion(mDNS *m, const ResourceRecord *inR
 
     require_action_quiet(q->qDNSServer, exit, err = mStatus_BadParamErr);
 
-    err = DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
+    err = _DNS64GetPrefixes(m, q->qDNSServer->resGroupID, &prefixes, &prefixCount);
     require_noerr_quiet(err, exit);
 
     newRR               = *inRR;
@@ -228,7 +221,7 @@ mDNSexport void DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ)
         struct in6_addr     v6Addr;
 
         inQ->dns64.state = kDNS64State_ReverseIPv6;
-        if (inQ->qDNSServer && DNS64GetReverseIPv6Addr(&inQ->qname, &v6Addr))
+        if (inQ->qDNSServer && _DNS64GetReverseIPv6Addr(&inQ->qname, &v6Addr))
         {
             mStatus                 err;
             nw_nat64_prefix_t *     prefixes;
@@ -237,7 +230,7 @@ mDNSexport void DNS64HandleNewQuestion(mDNS *m, DNSQuestion *inQ)
             struct in_addr          v4Addr;
             char                    qnameStr[MAX_REVERSE_MAPPING_NAME_V4];
 
-            err = DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
+            err = _DNS64GetPrefixes(m, inQ->qDNSServer->resGroupID, &prefixes, &prefixCount);
             require_noerr_quiet(err, exit);
 
             for (i = 0; i < prefixCount; i++)
@@ -318,7 +311,7 @@ mDNSexport void DNS64RestartQuestions(mDNS *m)
         if (q->dns64.state != kDNS64State_Initial)
         {
             SetValidDNSServers(m, q);
-            q->triedAllServersOnce = 0;
+            q->triedAllServersOnce = mDNSfalse;
             newServer = GetServerForQuestion(m, q);
             if (q->qDNSServer != newServer)
             {
@@ -346,7 +339,7 @@ mDNSexport void DNS64RestartQuestions(mDNS *m)
 }
 
 //===========================================================================================================================
-//  DNS64GetIPv6Addrs
+//  _DNS64GetIPv6Addrs
 //===========================================================================================================================
 
 #define IsPositiveAAAAFromResGroup(RR, RES_GROUP_ID)        \
@@ -356,7 +349,7 @@ mDNSexport void DNS64RestartQuestions(mDNS *m)
     ((RR)->RecordType != kDNSRecordTypePacketNegative) &&   \
     !(RR)->InterfaceID)
 
-mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
+mDNSlocal mStatus _DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct in6_addr **outAddrs, uint32_t *outAddrCount)
 {
     mStatus                 err;
     const CacheGroup *      cg;
@@ -365,7 +358,7 @@ mDNSlocal mStatus DNS64GetIPv6Addrs(mDNS *m, const mDNSu32 inResGroupID, struct
     uint32_t                addrCount;
     uint32_t                recordCount;
 
-    cg = CacheGroupForName(m, DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
+    cg = CacheGroupForName(m, _DNS64IPv4OnlyFQDNHash(), kDNS64IPv4OnlyFQDN);
     require_action_quiet(cg, exit, err = mStatus_NoSuchRecord);
 
     recordCount = 0;
@@ -402,10 +395,10 @@ exit:
 }
 
 //===========================================================================================================================
-//  DNS64GetPrefixes
+//  _DNS64GetPrefixes
 //===========================================================================================================================
 
-mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
+mDNSlocal mStatus _DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefix_t **outPrefixes, uint32_t *outPrefixCount)
 {
     mStatus                 err;
     struct in6_addr *       v6Addrs;
@@ -413,7 +406,7 @@ mDNSlocal mStatus DNS64GetPrefixes(mDNS *m, mDNSu32 inResGroupID, nw_nat64_prefi
     nw_nat64_prefix_t *     prefixes;
     int32_t                 prefixCount;
 
-    err = DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
+    err = _DNS64GetIPv6Addrs(m, inResGroupID, &v6Addrs, &v6AddrCount);
     require_noerr_quiet(err, exit);
 
     prefixCount = nw_nat64_copy_prefixes_from_ipv4only_records(v6Addrs, v6AddrCount, &prefixes);
@@ -428,12 +421,12 @@ exit:
 }
 
 //===========================================================================================================================
-//  DNS64GetReverseIPv6Addr
+//  _DNS64GetReverseIPv6Addr
 //===========================================================================================================================
 
 #define kReverseIPv6Domain  ((const domainname *) "\x3" "ip6" "\x4" "arpa")
 
-mDNSlocal mDNSBool DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr)
+mDNSlocal mDNSBool _DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6_addr *outAddr)
 {
     const mDNSu8 *      ptr;
     int                 i;
@@ -473,10 +466,10 @@ mDNSlocal mDNSBool DNS64GetReverseIPv6Addr(const domainname *inQName, struct in6
 }
 
 //===========================================================================================================================
-//  DNS64IPv4OnlyFQDNHash
+//  _DNS64IPv4OnlyFQDNHash
 //===========================================================================================================================
 
-mDNSlocal mDNSu32 DNS64IPv4OnlyFQDNHash(void)
+mDNSlocal mDNSu32 _DNS64IPv4OnlyFQDNHash(void)
 {
     static dispatch_once_t      sHashOnce;
     static mDNSu32              sHash;
@@ -487,10 +480,10 @@ mDNSlocal mDNSu32 DNS64IPv4OnlyFQDNHash(void)
 }
 
 //===========================================================================================================================
-//  DNS64RestartQuestion
+//  _DNS64RestartQuestion
 //===========================================================================================================================
 
-mDNSlocal void DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
+mDNSlocal void _DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State inNewState)
 {
     mDNS_StopQuery_internal(m, inQ);
 
@@ -506,7 +499,7 @@ mDNSlocal void DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State
 
         memcpy(inQ->dns64.qnameStash, &inQ->qname, sizeof(inQ->dns64.qnameStash));
         AssignDomainName(&inQ->qname, kDNS64IPv4OnlyFQDN);
-        inQ->qnamehash = DNS64IPv4OnlyFQDNHash();
+        inQ->qnamehash = _DNS64IPv4OnlyFQDNHash();
         inQ->qtype = kDNSType_AAAA;
         break;
 
@@ -534,10 +527,25 @@ mDNSlocal void DNS64RestartQuestion(mDNS *const m, DNSQuestion *inQ, DNS64State
 }
 
 //===========================================================================================================================
-//  DNS64TestIPv6Synthesis
+//  _DNS64InterfaceSupportsNAT64
+//===========================================================================================================================
+
+mDNSlocal mDNSBool _DNS64InterfaceSupportsNAT64(uint32_t inIfIndex)
+{
+    mdns_interface_monitor_t monitor = GetInterfaceMonitorForIndex(inIfIndex);
+    if (monitor && !mdns_interface_monitor_has_ipv4_connectivity(monitor) &&
+        mdns_interface_monitor_has_ipv6_connectivity(monitor))
+    {
+        return (mDNStrue);
+    }
+    return (mDNSfalse);
+}
+
+//===========================================================================================================================
+//  _DNS64TestIPv6Synthesis
 //===========================================================================================================================
 
-mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
+mDNSlocal mDNSBool _DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const mDNSv4Addr *inV4Addr)
 {
     mStatus                 err;
     nw_nat64_prefix_t *     prefixes    = NULL;
@@ -547,7 +555,7 @@ mDNSlocal mDNSBool DNS64TestIPv6Synthesis(mDNS *m, mDNSu32 inResGroupID, const m
     struct in6_addr         synthV6;
     mDNSBool                result      = mDNSfalse;
 
-    err = DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
+    err = _DNS64GetPrefixes(m, inResGroupID, &prefixes, &prefixCount);
     require_noerr_quiet(err, exit);
 
     memcpy(&v4Addr.s_addr, inV4Addr->b, 4);
@@ -564,4 +572,4 @@ exit:
     if (prefixes) free(prefixes);
     return (result);
 }
-#endif  // TARGET_OS_IOS
+#endif  // MDNSRESPONDER_SUPPORTS(APPLE, DNS64)
index 8a2e70b98e38ed2a6127605507ed795cf9523fcb..5e9f005d3fae58bc7a46608044b93b6da4314783 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2011-2013 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2011-2019 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.
@@ -23,7 +22,7 @@
 #include <sys/event.h>
 #include <netinet/tcp.h>
 
-mDNSexport mDNS mDNSStorage;
+extern mDNS mDNSStorage;
 
 #define ValidSocket(s) ((s) >= 0)
 
@@ -72,7 +71,7 @@ mDNSlocal int ProxyTCPRead(ProxyTCPInfo_t *tcpInfo)
             return -1;
         }
 
-        tcpInfo->reply = mallocL("ProxyTCPInfo", tcpInfo->replyLen);
+        tcpInfo->reply = (DNSMessage *) mallocL("ProxyTCPInfo", tcpInfo->replyLen);
         if (!tcpInfo->reply)
         {
             LogMsg("ProxyTCPRead: Memory failure");
@@ -103,7 +102,6 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context, __unu
     mDNSIPPort senderPort;
     ProxyTCPInfo_t *ti = (ProxyTCPInfo_t *)context;
     TCPSocket *sock = &ti->sock;
-    KQSocketSet *kq = &sock->ss;
     struct tcp_info tcp_if;
     socklen_t size = sizeof(tcp_if);
     int32_t intf_id = 0;
@@ -122,7 +120,7 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context, __unu
         return;
     }
     // We read all the data and hence not interested in read events anymore
-    KQueueSet(s1, EV_DELETE, EVFILT_READ, sock->kqEntry);
+    KQueueSet(s1, EV_DELETE, EVFILT_READ, &sock->kqEntry);
 
     mDNSPlatformMemZero(&to, sizeof(to));
     mDNSPlatformMemZero(&from, sizeof(from));
@@ -187,7 +185,7 @@ mDNSlocal void ProxyTCPSocketCallBack(int s1, short filter, void *context, __unu
     // We pass sock for the TCPSocket and the "ti" for context as that's what we want to free at the end.
     // In the UDP case, there is just a single socket and nothing to free. Hence, the context (last argument)
     // would be NULL.
-    kq->m->p->TCPProxyCallback(sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr,
+    ti->sock.m->p->TCPProxyCallback(sock, ti->reply, (mDNSu8 *)ti->reply + ti->replyLen, &senderAddr, senderPort, &destAddr,
         UnicastDNSPort, (mDNSInterfaceID)(uintptr_t)intf_id, ti);
 }
 
@@ -197,40 +195,30 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context, __unused mDNS
     struct sockaddr_storage ss;
     socklen_t sslen = sizeof(ss);
     const int on = 1;
-    KQSocketSet *listenSet = (KQSocketSet *)context;
+    TCPSocket *listenSock = (TCPSocket *)context;
 
     (void) filter;
 
     while ((newfd = accept(s1, (struct sockaddr *)&ss, &sslen)) != -1)
     {
         int err;
-        int *s;
-        KQueueEntry *k;
-        KQSocketSet *kq;
 
         // Even though we just need a single KQueueEntry, for simplicity we re-use
         // the KQSocketSet
-        ProxyTCPInfo_t *ti = mallocL("ProxyTCPContext", sizeof(ProxyTCPInfo_t));
+        ProxyTCPInfo_t * const ti = (ProxyTCPInfo_t *)callocL("ProxyTCPContext", sizeof(*ti));
         if (!ti)
         {
             LogMsg("ProxyTCPAccept: cannot allocate TCPSocket");
             close(newfd);
             return;
         }
-        mDNSPlatformMemZero(ti, sizeof(ProxyTCPInfo_t));
-        
-        TCPSocket *sock = &ti->sock;
-
-        kq = &sock->ss;
-        kq->sktv4 = -1;
-        kq->sktv6 = -1;
-        kq->m = listenSet->m;
+        TCPSocket * const sock = &ti->sock;
+        sock->fd = -1;
+        sock->m  = listenSock->m;
 
         fcntl(newfd, F_SETFL, fcntl(newfd, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
         if (ss.ss_family == AF_INET)
         {
-            s =  &kq->sktv4;
-            k =  &kq->kqsv4;
             // Receive interface identifiers
             err = setsockopt(newfd, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
             if (err)
@@ -243,8 +231,6 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context, __unused mDNS
         }
         else
         {
-            s =  &kq->sktv6;
-            k =  &kq->kqsv6;
             // We want to receive destination addresses and receive interface identifiers
             err = setsockopt(newfd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
             if (err)
@@ -255,21 +241,21 @@ mDNSlocal void ProxyTCPAccept(int s1, short filter, void *context, __unused mDNS
                 return;
             }
         }
-        *s = newfd;
         // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
         // from which we can infer the destination address family. Hence we need to remember that here.
         // Instead of remembering the address family, we remember the right fd.
         sock->fd = newfd;
-        sock->kqEntry = k;
-        k->KQcallback = ProxyTCPSocketCallBack;
-        k->KQcontext  = ti;
-        k->KQtask     = "TCP Proxy packet reception";
+        sock->kqEntry.KQcallback = ProxyTCPSocketCallBack;
+        sock->kqEntry.KQcontext  = ti;
+        sock->kqEntry.KQtask     = "TCP Proxy packet reception";
 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-        k->readSource = mDNSNULL;
-        k->writeSource = mDNSNULL;
-        k->fdClosed = mDNSfalse;
+        sock->kqEntry.readSource = mDNSNULL;
+        sock->kqEntry.writeSource = mDNSNULL;
+        sock->kqEntry.fdClosed = mDNSfalse;
 #endif
-        KQueueSet(*s, EV_ADD, EVFILT_READ, k);
+        sock->connected = mDNStrue;
+        sock->m = listenSock->m;
+        KQueueSet(newfd, EV_ADD, EVFILT_READ, &sock->kqEntry);
     }
 }
 
@@ -350,19 +336,15 @@ mDNSlocal mStatus SetupUDPProxySocket(int skt, KQSocketSet *cp, u_short sa_famil
     return(err);
 }
 
-mDNSlocal mStatus SetupTCPProxySocket(int skt, KQSocketSet *cp, u_short sa_family, mDNSBool useBackgroundTrafficClass)
+mDNSlocal mStatus SetupTCPProxySocket(int skt, TCPSocket *sock, u_short sa_family, mDNSBool useBackgroundTrafficClass)
 {
-    int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
-    KQueueEntry *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
     mStatus err;
-
-    cp->m = &mDNSStorage;
-    // XXX may not be used by the TCP codepath 
-    cp->closeFlag = mDNSNULL;
+    mDNS *m = &mDNSStorage;
 
     // for TCP sockets, the traffic class is set once and not changed
     // setTrafficClass(skt, useBackgroundTrafficClass);
     (void) useBackgroundTrafficClass;
+    (void) sa_family;
 
     // All the socket setup has already been done 
     err = listen(skt, NUM_PROXY_TCP_CONNS);
@@ -373,16 +355,17 @@ mDNSlocal mStatus SetupTCPProxySocket(int skt, KQSocketSet *cp, u_short sa_famil
     }
     fcntl(skt, F_SETFL, fcntl(skt, F_GETFL, 0) | O_NONBLOCK); // set non-blocking
     
-    *s = skt;
-    k->KQcallback  = ProxyTCPAccept;
-    k->KQcontext   = cp;
-    k->KQtask      = "TCP Accept";
+    sock->fd = skt;
+    sock->kqEntry.KQcallback  = ProxyTCPAccept;
+    sock->kqEntry.KQcontext   = sock;
+    sock->kqEntry.KQtask      = "TCP Accept";
 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-    k->readSource  = mDNSNULL;
-    k->writeSource = mDNSNULL;
-    k->fdClosed    = mDNSfalse;
+    sock->kqEntry.readSource  = mDNSNULL;
+    sock->kqEntry.writeSource = mDNSNULL;
+    sock->kqEntry.fdClosed    = mDNSfalse;
 #endif
-    KQueueSet(*s, EV_ADD, EVFILT_READ, k);
+    sock->m = m;
+    KQueueSet(skt, EV_ADD, EVFILT_READ, &sock->kqEntry);
     return mStatus_NoError;
 }
 
@@ -443,15 +426,19 @@ mDNSlocal void BindDPSocket(int fd, int sa_family)
 mDNSlocal void SetupDNSProxySkts(int fd[4])
 {
     mDNS *const m = &mDNSStorage;
-       int i;
+    int i;
     mStatus err;
     KQSocketSet *udpSS;
-    KQSocketSet *tcpSS;
+    TCPSocket *v4, *v6;
 
     udpSS       = &m->p->UDPProxy.ss;
-    tcpSS       = &m->p->TCPProxy.ss;
     udpSS->port = UnicastDNSPort;
-    tcpSS->port = UnicastDNSPort;
+    v4 = &m->p->TCPProxyV4;
+    v6 = &m->p->TCPProxyV6;
+    v4->m = m;
+    v4->port = UnicastDNSPort;
+    v6->m = m;
+    v6->port = UnicastDNSPort;
 
     LogMsg("SetupDNSProxySkts: %d, %d, %d, %d", fd[0], fd[1], fd[2], fd[3]);
 
@@ -465,11 +452,11 @@ mDNSlocal void SetupDNSProxySkts(int fd[4])
     if (err)
         LogMsg("SetupDNSProxySkts: ERROR!! UDPv6 Socket");
 
-    err = SetupTCPProxySocket(fd[2], tcpSS, AF_INET, mDNSfalse);
+    err = SetupTCPProxySocket(fd[2], v4, AF_INET, mDNSfalse);
     if (err)
         LogMsg("SetupDNSProxySkts: ERROR!! TCPv4 Socket");
 
-    err = SetupTCPProxySocket(fd[3], tcpSS, AF_INET6, mDNSfalse);
+    err = SetupTCPProxySocket(fd[3], v6, AF_INET6, mDNSfalse);
     if (err)
         LogMsg("SetupDNSProxySkts: ERROR!! TCPv6 Socket");
 
@@ -528,7 +515,6 @@ mDNSexport void mDNSPlatformDisposeProxyContext(void *context)
 {
     ProxyTCPInfo_t *ti;
     TCPSocket *sock;
-    KQSocketSet *kq;
 
     if (!context)
         return;
@@ -536,22 +522,22 @@ mDNSexport void mDNSPlatformDisposeProxyContext(void *context)
     ti = (ProxyTCPInfo_t *)context;
     sock = &ti->sock;
 
-    kq = &sock->ss;
-    if (kq->sktv4 != -1)
-    {
-        shutdown(kq->sktv4, 2);
-        mDNSPlatformCloseFD(&kq->kqsv4, kq->sktv4);
-    }
-    if (kq->sktv6 != -1)
+    if (sock->fd >= 0)
     {
-        shutdown(kq->sktv6, 2);
-        mDNSPlatformCloseFD(&kq->kqsv6, kq->sktv6);
+        mDNSPlatformCloseFD(&sock->kqEntry, sock->fd);
+        sock->fd = -1;
     }
-    if (kq->closeFlag)
-        *kq->closeFlag = 1;
 
     if (ti->reply)
         freeL("ProxyTCPInfoLen", ti->reply);
     freeL("ProxyTCPContext", ti);
 }
 
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
index 6db54b1c9cdff38ab633cfb70cb60149c18360c9..6e1ac46b00169e4133dcc5a9dd432c6cb3c19316 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2013 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2012-2019 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.
@@ -115,7 +114,7 @@ mDNSlocal void AddTrustAnchor(mDNS *const m, const domainname *zone, mDNSu16 key
         tmp = tmp->next;
     }
 
-    ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
+    ta = (TrustAnchor *) mDNSPlatformMemAllocateClear(sizeof(*ta));
     if (!ta)
     {
         LogMsg("AddTrustAnchor: malloc failure ta");
@@ -155,7 +154,7 @@ mDNSlocal mDNSu8 *ConvertDigest(char *digest, int digestType, int *diglen)
         LogMsg("ConvertDigest: digest type %d not supported", digestType);
         return mDNSNULL;
     }
-    dig = mDNSPlatformMemAllocate(*diglen);
+    dig = (mDNSu8 *) mDNSPlatformMemAllocate(*diglen);
     if (!dig)
     {
         LogMsg("ConvertDigest: malloc failure");
@@ -435,13 +434,12 @@ mDNSlocal void FetchRootTA(mDNS *const m)
 
     (void) m;
 
-    TrustAnchor *ta = (TrustAnchor *)mDNSPlatformMemAllocate(sizeof(TrustAnchor));
+    TrustAnchor *ta = (TrustAnchor *) mDNSPlatformMemAllocateClear(sizeof(*ta));
     if (!ta)
     {
         LogMsg("FetchRootTA: TrustAnchor alloc failed");
         return;
     }
-    memset(ta, 0, sizeof(TrustAnchor));
 
     url = CFURLCreateWithString(NULL, urlString, NULL);
     if (!url)
@@ -632,18 +630,18 @@ mDNSexport mStatus DNSSECPlatformInit(mDNS *const m)
 
     char *digest = "F122E47B5B7D2B6A5CC0A21EADA11D96BB9CC927";
     mDNSu8 *dig = ConvertDigest(digest, 1, &diglen);
-    AddTrustAnchor(m, testZone, 23044, 5, 1, diglen, dig);
+    if (dig) AddTrustAnchor(m, testZone, 23044, 5, 1, diglen, dig);
 
     char *digest1 = "D795AE5E1AFB200C6139474199B70EAD3F3484553FD97BE5A43704B8A4791F21";
     dig = ConvertDigest(digest1, 2, &diglen);
-    AddTrustAnchor(m, testZone, 23044, 5, 2, diglen, dig);
+    if (dig) AddTrustAnchor(m, testZone, 23044, 5, 2, diglen, dig);
 
     // Add the TA for root zone manually here. We will dynamically fetch the root TA and
     // update it shortly. If that fails e.g., disconnected from the network, we still
     // have something to work with.
     char *digest2 = "49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5";
     dig = ConvertDigest(digest2, 2, &diglen);
-    AddTrustAnchor(m, (const domainname *)"\000", 19036, 8, 2, diglen, dig);
+    if (dig) AddTrustAnchor(m, (const domainname *)"\000", 19036, 8, 2, diglen, dig);
 
 #if !TARGET_OS_IPHONE
     DNSSECProbeQuestion.ThisQInterval = -1;
index b80c2bf2f574b7b507742b0c3baef91bc93638c6..89e5c2f17dd86f0f9f530e08b1831f0414e0fa22 100644 (file)
@@ -35,6 +35,8 @@ extern const NSString *    _CNSubDomainKey_subPath;
 - (void)startBrowser;
 - (void)stopBrowser;
 
+- (BOOL)foundInstanceInMoreThanLocalDomain;
+
 @property (readonly) NSArray *          defaultDomainPath;
 @property (readonly) NSArray *          flattenedDNSDomains;
 
index 379837727798a9f20b4f69f7aad7b7c4e165cf6d..48a60acc9ae3df36d8ddfc5f35adc9afa700b861 100644 (file)
@@ -34,7 +34,7 @@ const NSString *    _CNSubDomainKey_reverseDomainPath   = @"reverseDomainPath";
 
 @implementation _CNDomainBrowser
 
-void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
+static void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *replyDomain, void *context);
 
 - (instancetype)initWithDelegate:(id<_CNDomainBrowserDelegate>)delegate
 {
@@ -67,12 +67,13 @@ void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceInd
             dispatch_set_finalizer_f(queue, finalizer);
             
             DNSServiceRef ref;
-            if (DNSServiceEnumerateDomains(&ref, _browseRegistration ? kDNSServiceFlagsRegistrationDomains : kDNSServiceFlagsBrowseDomains, 0, enumReply, (__bridge void *)self))
-                NSLog(@"DNSServiceEnumerateDomains failed");
+            DNSServiceErrorType error;
+            if ((error = DNSServiceEnumerateDomains(&ref, self->_browseRegistration ? kDNSServiceFlagsRegistrationDomains : kDNSServiceFlagsBrowseDomains, 0, enumReply, (__bridge void *)self)) != 0)
+                NSLog(@"DNSServiceEnumerateDomains failed err: %ld", error);
             else
             {
-                _browseDomainR = ref;
-                (void)DNSServiceSetDispatchQueue(_browseDomainR, queue);
+                self->_browseDomainR = ref;
+                (void)DNSServiceSetDispatchQueue(self->_browseDomainR, queue);
             }
         });
     }
@@ -87,6 +88,26 @@ void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceInd
     }
 }
 
+- (BOOL)foundInstanceInMoreThanLocalDomain
+{
+    BOOL result = YES;
+    
+    if( self.browseDomainD.count )
+    {
+        for( NSDictionary *next in [self.browseDomainD allValues] )
+        {
+            if( [next[_CNSubDomainKey_reverseDomainPath][0] isEqual: @"local"] )            continue;
+            else
+            {
+                result = YES;
+                break;
+            }
+        }
+    }
+    
+    return( result );
+}
+
 - (NSArray *)defaultDomainPath
 {
     NSArray * revDomainArray = nil;
@@ -131,7 +152,7 @@ void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceInd
     if ([_delegate respondsToSelector: @selector(bonjourBrowserDomainUpdate:)])
     {
         dispatch_async(self.callbackQueue, ^{
-            [_delegate bonjourBrowserDomainUpdate: [self defaultDomainPath]];
+            [self->_delegate bonjourBrowserDomainUpdate: [self defaultDomainPath]];
         });
     }
 }
@@ -146,7 +167,7 @@ void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceInd
 static void finalizer(void * context)
 {
     _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
-    NSLog(@"finalizer: %@", self);
+//    NSLog(@"finalizer: %@", self);
     (void)CFBridgingRelease((__bridge void *)self);
 }
 
@@ -154,7 +175,7 @@ static void finalizer(void * context)
 
 #pragma mark - Static Callbacks
 
-void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
+static void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
                const char *replyDomain, void *context)
 {
        (void)sdRef;
@@ -166,8 +187,8 @@ void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceInd
     _CNDomainBrowser *self = (__bridge _CNDomainBrowser *)context;
     NSString *key = [NSString stringWithUTF8String: replyDomain];
     
-    if (self.ignoreLocal && [key isEqualToString: @"local."])   return;
-    if (self.ignoreBTMM && [key hasSuffix: @".members.btmm.icloud.com."])   return;
+    if (self.ignoreLocal && [key isEqualToString: @"local."])               goto exit;
+    if (self.ignoreBTMM && [key hasSuffix: @".members.btmm.icloud.com."])   goto exit;
     
     if (!(flags & kDNSServiceFlagsAdd))
     {
@@ -180,7 +201,8 @@ void enumReply(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceInd
                                           _CNSubDomainKey_defaultFlag: (flags & kDNSServiceFlagsDefault) ? @YES : @NO }
                                forKey: key];
     }
-    
+
+exit:
     if (!(flags & kDNSServiceFlagsMoreComing))
     {
         [self reloadBrowser];
index ccc381b38d18b7520af62bc4a59c91a96ab1636f..d5f362476b5e55e8fd5042ce46792cad9e31b9eb 100644 (file)
@@ -37,14 +37,18 @@ IB_DESIGNABLE
 - (void)startBrowse;
 - (void)stopBrowse;
 
+- (CGFloat)minimumHeight;
+- (void)showSelectedRow;
+- (BOOL)foundInstanceInMoreThanLocalDomain;
+
 @end
 
 @protocol CNDomainBrowserViewDelegate <NSObject>
 
 @optional
 
-- (void)bonjourBrowserDomainSelected:(NSString *)domain;
-- (void)bonjourBrowserDomainUpdate:(NSString *)defaultDomain;
+- (void)domainBrowserDomainSelected:(NSString *)domain;
+- (void)domainBrowserDomainUpdate:(NSString *)defaultDomain;
 
 @end
 
index 1bb52602711686d22279d6057a814d788a6fb8d8..13670ab5509e14720b067f845687fc664b7d9481 100644 (file)
 #import "_CNDomainBrowser.h"
 #import "CNDomainBrowserPathUtils.h"
 
-#define DEBUG_POPUP_CELLS                                      0
-#define SHOW_SERVICETYPE_IF_SEARCH_COUNT       0
-#define TEST_LEGACYBROWSE                   0
-
 #define BROWSER_CELL_SPACING                4
-
-@protocol CNServiceTypeLocalizerDelegate <NSObject>
-@property (strong) NSDictionary * localizedServiceTypesDictionary;
-@end
-
-@interface CNServiceTypeLocalizer : NSValueTransformer
-{
-       id<CNServiceTypeLocalizerDelegate>      _delegate;
-}
-- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate;
-
-@end
-
-@implementation CNServiceTypeLocalizer
-
-- (instancetype)initWithDelegate:(id<CNServiceTypeLocalizerDelegate>)delegate
-{
-       if (self = [super init])
-       {
-               _delegate = delegate;
-       }
-       return(self);
-}
-
-+ (Class)transformedValueClass
-{
-       return [NSString class];
-}
-
-+ (BOOL)allowsReverseTransformation
-{
-       return NO;
-}
-
-- (nullable id)transformedValue:(nullable id)value
-{
-       id      result = value;
-       
-       if (value && _delegate && [_delegate respondsToSelector: @selector(localizedServiceTypesDictionary)])
-       {
-               NSString *      localizedValue = [_delegate.localizedServiceTypesDictionary objectForKey: value];
-               if (localizedValue) result = localizedValue;
-       }
-       
-       return(result);
-}
-
-@end
+#define INITIAL_LEGACYBROWSE                1
 
 @implementation NSBrowser(PathArray)
 
@@ -93,7 +42,6 @@
 @interface CNDomainBrowserView ()
 
 @property (strong) _CNDomainBrowser *      bonjour;
-@property (strong) NSSplitView *                       mainSplitView;
 
 @property (strong) NSTableView *                       instanceTable;
 @property (strong) NSArrayController *         instanceC;
 @property (strong) NSTableColumn *                     instancePathPopupColumn;
 
 @property (strong) NSBrowser *                         browser;
-
-@property (strong) CNServiceTypeLocalizer * serviceTypeLocalizer;
+#if INITIAL_LEGACYBROWSE
+@property (assign) BOOL                     initialPathSet;
+#endif
 
 @end
 
 {
        NSRect  frame = self.frame;
        self.instanceC = [[NSArrayController alloc] init];
-       self.serviceTypeLocalizer = [[CNServiceTypeLocalizer alloc] initWithDelegate: (id<CNServiceTypeLocalizerDelegate>)self];
-               
+    
        //      Bottom browser
     frame.origin.x = frame.origin.y = 0;
        NSBrowser * browserView = [[NSBrowser alloc] initWithFrame: frame];
        browserView.hasHorizontalScroller = YES;
        browserView.columnResizingType = NSBrowserNoColumnResizing;
        browserView.minColumnWidth = 50;
+    browserView.translatesAutoresizingMaskIntoConstraints = NO;
        self.browser = browserView;
 
     [self addSubview: browserView];
+    
+    [self addConstraint:
+     [NSLayoutConstraint constraintWithItem:_browser
+                                  attribute:NSLayoutAttributeLeft
+                                  relatedBy:NSLayoutRelationEqual
+                                     toItem:self
+                                  attribute:NSLayoutAttributeLeft
+                                 multiplier:1
+                                   constant:0]];
+    [self addConstraint:
+     [NSLayoutConstraint constraintWithItem:_browser
+                                  attribute:NSLayoutAttributeRight
+                                  relatedBy:NSLayoutRelationEqual
+                                     toItem:self
+                                  attribute:NSLayoutAttributeRight
+                                 multiplier:1
+                                   constant:0]];
+    [self addConstraint:
+     [NSLayoutConstraint constraintWithItem:_browser
+                                  attribute:NSLayoutAttributeBottom
+                                  relatedBy:NSLayoutRelationEqual
+                                     toItem:self
+                                  attribute:NSLayoutAttributeBottom
+                                 multiplier:1
+                                   constant:0]];
+    [self addConstraint:
+     [NSLayoutConstraint constraintWithItem:_browser
+                                  attribute:NSLayoutAttributeTop
+                                  relatedBy:NSLayoutRelationEqual
+                                     toItem:self
+                                  attribute:NSLayoutAttributeTop
+                                 multiplier:1
+                                   constant:0]];
 }
 
 - (void)commonInit
        [self contentViewsInit];
 }
 
-- (void)viewWillMoveToWindow:(NSWindow *)newWindow
+- (void)viewWillMoveToSuperview:(NSView *)newSuperview
 {
-    [super viewWillMoveToWindow: newWindow];
-    if (newWindow)
+    [super viewWillMoveToSuperview: newSuperview];
+    if (newSuperview && !_bonjour)
     {
-        [self.mainSplitView adjustSubviews];
+        [self awakeFromNib];
     }
 }
 
 - (void)stopBrowse
 {
     [self.bonjour stopBrowser];
+    _initialPathSet = NO;
 }
 
 - (BOOL)isBrowsing
     return(self.bonjour.isBrowsing);
 }
 
+- (CGFloat)minimumHeight
+{
+    return self.selectedDNSDomain.length ? [self.browser frameOfRow: [self.browser selectedRowInColumn: self.browser.lastVisibleColumn] inColumn: self.browser.lastVisibleColumn].size.height : 0.0;
+}
+
+- (void)showSelectedRow
+{
+    for( NSInteger i = self.browser.firstVisibleColumn ; i <= self.browser.lastVisibleColumn ; i++ )
+    {
+        NSInteger selRow = [self.browser selectedRowInColumn: i];
+        if( selRow != NSNotFound ) [self.browser scrollRowToVisible: selRow inColumn: i];
+    }
+}
+
+- (BOOL)foundInstanceInMoreThanLocalDomain
+{
+    return( [_bonjour foundInstanceInMoreThanLocalDomain] );
+}
+
+
 #pragma mark - Notifications
 
 - (void)browser:(NSBrowser *)sender selectionDidChange:(NSArray *)pathArray
 {
-    if (_delegate && [_delegate respondsToSelector: @selector(bonjourBrowserDomainSelected:)] &&
+    if (_delegate && [_delegate respondsToSelector: @selector(domainBrowserDomainSelected:)] &&
         sender == self.browser)
     {
-        [_delegate bonjourBrowserDomainSelected: pathArray ? DomainPathToDNSDomain(pathArray) : nil];
+        [_delegate domainBrowserDomainSelected: pathArray ? DomainPathToDNSDomain(pathArray) : nil];
     }
 }
 
 {
        (void)defaultDomainPath;
     [self.browser loadColumnZero];
-    [self setDomainSelectionToPathArray: self.bonjour.defaultDomainPath];
+#if INITIAL_LEGACYBROWSE
+    if( !_initialPathSet )
+    {
+        _initialPathSet = YES;
+        [_delegate domainBrowserDomainUpdate: [NSString string]];
+    }
+    else
+#endif
+    {
+        [self setDomainSelectionToPathArray: self.bonjour.defaultDomainPath];
+        if (_delegate && [_delegate respondsToSelector: @selector(domainBrowserDomainUpdate:)])
+        {
+            [_delegate domainBrowserDomainUpdate: defaultDomainPath ? DomainPathToDNSDomain(defaultDomainPath) : [NSString string]];
+        }
+    }
 }
 
 #pragma mark - Commands
 {
        (void)sender;
        NSArray * pathArray = [self.browser pathArrayToColumn: self.browser.selectedColumn includeSelectedRow: YES];
-    if (!pathArray.count) pathArray = self.bonjour.defaultDomainPath;
+    if (!pathArray.count && (([NSEvent modifierFlags] & NSEventModifierFlagOption ) != NSEventModifierFlagOption)) pathArray = self.bonjour.defaultDomainPath;
     [self setDomainSelectionToPathArray: pathArray];
     [self browser: self.browser selectionDidChange: pathArray];
 }
index 7de031c4f0c3ae304e77918da2d9cdf078739b34..1da4059e080bad4f3b47af9811989d3611e2e2e2 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2004-2019 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.
@@ -81,13 +80,15 @@ mDNSlocal mStatus SendPortMapRequest(mDNS *m, NATTraversalInfo *n);
 // Note that this function assumes src is already NULL terminated
 mDNSlocal void AllocAndCopy(char **const dst, const char *const src)
 {
+    size_t srcLen;
     if (src == mDNSNULL) return;
-    if ((strlen((char*)src)) >= UINT32_MAX || (*dst = mDNSPlatformMemAllocate((mDNSu32)strlen((char*)src) + 1)) == mDNSNULL)
+    srcLen = strlen(src) + 1;
+    if ((srcLen > UINT32_MAX) || ((*dst = mDNSPlatformMemAllocate((mDNSu32)srcLen)) == mDNSNULL))
     {
         LogMsg("AllocAndCopy: can't allocate string");
         return;
     }
-    strcpy((char*)*dst, (char*)src);
+    memcpy(*dst, src, srcLen);
 }
 
 // This function does a simple parse of an HTTP URL that may include a hostname, port, and path
@@ -411,7 +412,7 @@ mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool Co
     mDNSBool closed  = mDNSfalse;
     long n       = 0;
     long nsent   = 0;
-    static int LNTERRORcount = 0;
+    static mDNSu32 LNTERRORcount = 0;
 
     if (tcpInfo->sock != sock)
     {
@@ -459,10 +460,18 @@ mDNSlocal void tcpConnectionCallback(TCPSocket *sock, void *context, mDNSBool Co
 exit:
     if (err || status)
     {
-        mDNS   *m = tcpInfo->m;
+        mDNS *const m = tcpInfo->m;
+        static mDNSs32 lastErrorTime = 0;
+
+        if ((LNTERRORcount > 0) && (((mDNSu32)(m->timenow - lastErrorTime)) >= ((mDNSu32)mDNSPlatformOneSecond)))
+        {
+            LNTERRORcount = 0;
+        }
+        lastErrorTime = m->timenow;
         if ((++LNTERRORcount % 1000) == 0)
         {   
-            LogMsg("ERROR: tcpconnectioncallback -> got error status %d times", LNTERRORcount);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                "ERROR: tcpconnectioncallback -> got error status %u times", LNTERRORcount);
             assert(LNTERRORcount < 1000);
             // Recovery Mechanism to bail mDNSResponder out of trouble: It has been seen that we can get into 
             // this loop: [tcpKQSocketCallback()--> doTcpSocketCallback()-->tcpconnectionCallback()-->mDNSASLLog()],
@@ -524,10 +533,10 @@ mDNSlocal mStatus MakeTCPConnection(mDNS *const m, tcpLNTInfo *info, const mDNSA
     else if ((info->Reply = mDNSPlatformMemAllocate(LNT_MAXBUFSIZE)) == mDNSNULL) { LogInfo("can't allocate reply buffer"); return (mStatus_NoMemoryErr); }
 
     if (info->sock) { LogInfo("MakeTCPConnection: closing previous open connection"); mDNSPlatformTCPCloseConnection(info->sock); info->sock = mDNSNULL; }
-    info->sock = mDNSPlatformTCPSocket(kTCPSocketFlags_Zero, &srcport, mDNSfalse);
+    info->sock = mDNSPlatformTCPSocket(kTCPSocketFlags_Zero, Addr->type, &srcport, mDNSNULL, mDNSfalse);
     if (!info->sock) { LogMsg("LNT MakeTCPConnection: unable to create TCP socket"); mDNSPlatformMemFree(info->Reply); info->Reply = mDNSNULL; return(mStatus_NoMemoryErr); }
     LogInfo("MakeTCPConnection: connecting to %#a:%d", &info->Address, mDNSVal16(info->Port));
-    err = mDNSPlatformTCPConnect(info->sock, Addr, Port, mDNSNULL, 0, tcpConnectionCallback, info);
+    err = mDNSPlatformTCPConnect(info->sock, Addr, Port, 0, tcpConnectionCallback, info);
 
     if      (err == mStatus_ConnPending) err = mStatus_NoError;
     else if (err == mStatus_ConnEstablished)
@@ -740,7 +749,7 @@ mDNSexport mStatus LNT_UnmapPort(mDNS *m, NATTraversalInfo *const n)
     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)
+    if ((info = (tcpLNTInfo *) mDNSPlatformMemAllocate(sizeof(*info))) == mDNSNULL)
     { LogInfo("LNT_UnmapPort: can't allocate tcpInfo"); return(mStatus_NoMemoryErr); }
     *info = n->tcpInfo;
 
diff --git a/mDNSMacOSX/LoggingProfiles/liblog_mdnsresponder.m b/mDNSMacOSX/LoggingProfiles/liblog_mdnsresponder.m
new file mode 100644 (file)
index 0000000..3d27ef1
--- /dev/null
@@ -0,0 +1,152 @@
+//
+//  liblog_mdnsresponder.m
+//  liblog_mdnsresponder
+//
+
+#import <Foundation/Foundation.h>
+#import <arpa/inet.h>
+#import <os/log_private.h>
+#import "DNSCommon.h"
+#undef DomainNameLength // undefines DomainNameLength since we need to use DomainNameLength that is also defined in DNSMessage.h
+#import "DNSMessage.h"
+
+// MDNS Mutable Attribute String
+#define MDNSAS(str) [[NSAttributedString alloc] initWithString:(str)]
+#define MDNSASWithFormat(format, ...) MDNSAS(([[NSString alloc] initWithFormat:format, ##__VA_ARGS__]))
+#define MAX_MDNS_ADDR_STRING_LENGTH 45
+
+// os_log(OS_LOG_DEFAULT, "IP Address(IPv4/IPv6): %{mdnsresponder:ip_addr}.20P", <the address of mDNSAddr structure>);
+static NS_RETURNS_RETAINED NSAttributedString *
+MDNSOLCopyFormattedStringmDNSIPAddr(id value)
+{
+    const mDNSAddr *mdns_addr_p;
+    char buffer[MAX_MDNS_ADDR_STRING_LENGTH + 1];
+    buffer[MAX_MDNS_ADDR_STRING_LENGTH] = 0;
+
+    if ([(NSObject *)value isKindOfClass:[NSData class]]) {
+        NSData *data = (NSData *)value;
+        if (data.bytes == NULL || data.length == 0) {
+            return MDNSAS(@"<NULL IP ADDRESS>");
+        }
+
+        if (data.length != sizeof(mDNSAddr)) {
+            return MDNSASWithFormat(@"<fail decode - size> %zd != %zd", (size_t)data.length, sizeof(mDNSAddr));
+        }
+
+        mdns_addr_p = (const mDNSAddr *)data.bytes;
+    } else {
+        return MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]);
+    }
+
+    bool failed_conversion = false;
+    switch (mdns_addr_p->type) {
+        case mDNSAddrType_IPv4:
+        {
+            __unused char sizecheck_buffer[(sizeof(buffer) >= INET_ADDRSTRLEN) ? 1 : -1];
+            if (!inet_ntop(AF_INET, (const void *)&mdns_addr_p->ip.v4.NotAnInteger, buffer, sizeof(buffer)))
+                failed_conversion = true;
+            break;
+        }
+        case mDNSAddrType_IPv6:
+        {
+            __unused char sizecheck_buffer[(sizeof(buffer) >= INET6_ADDRSTRLEN) ? 1 : -1];
+            if (!inet_ntop(AF_INET6, (const void *)mdns_addr_p->ip.v6.b, buffer, sizeof(buffer)))
+                failed_conversion = true;
+            break;
+        }
+        default:
+            failed_conversion = true;
+            break;
+    }
+    if (failed_conversion) {
+        return MDNSAS(@"<failed conversion>");
+    }
+
+    NSString *str = @(buffer);
+    return MDNSAS(str ? str : @("<Could not create NSString>"));
+}
+
+// os_log(OS_LOG_DEFAULT, "MAC Address: %{mdnsresponder:mac_addr}.6P", <the address of 6-byte MAC address>);
+#define MAC_ADDRESS_LEN 6
+static NS_RETURNS_RETAINED NSAttributedString *
+MDNSOLCopyFormattedStringmDNSMACAddr(id value)
+{
+    const uint8_t *mac_addr = NULL;
+    char buffer[MAX_MDNS_ADDR_STRING_LENGTH + 1];
+    buffer[MAX_MDNS_ADDR_STRING_LENGTH] = 0;
+
+    if ([(NSObject *)value isKindOfClass:[NSData class]]) {
+        NSData *data = (NSData *)value;
+        if (data.bytes == NULL || data.length == 0) {
+            return MDNSAS(@"<NULL MAC ADDRESS>");
+        }
+
+        if (data.length != MAC_ADDRESS_LEN) {
+            return MDNSASWithFormat(@"<fail decode - size> %zd != %zd", (size_t)data.length, MAC_ADDRESS_LEN);
+        }
+
+        mac_addr = (const uint8_t *)data.bytes;
+    } else {
+        return MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]);
+    }
+
+    int ret_snprintf = snprintf(buffer, MAX_MDNS_ADDR_STRING_LENGTH, "%02X:%02X:%02X:%02X:%02X:%02X",
+                                mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+    if (ret_snprintf < 0) {
+        return MDNSAS(@"<failed conversion>");
+    }
+
+    NSString *str = @(buffer);
+    return MDNSAS(str ? str : @("<Could not create NSString>"));
+}
+
+// os_log(OS_LOG_DEFAULT, "Domain Name: %{mdnsresponder:domain_name}.*P", <the address of domainname structure>);
+// Leave some extra space to allow log routine to put error message when decode fails at the end of the buffer.
+static NS_RETURNS_RETAINED NSAttributedString *
+MDNSOLCopyFormattedStringmDNSLabelSequenceName(id value)
+{
+    char buffer[kDNSServiceMaxDomainName];
+    NSData *data = (NSData *)value;
+    OSStatus ret;
+
+    if ([(NSObject *)value isKindOfClass:[NSData class]]) {
+        if (data.bytes == NULL || data.length == 0) {
+            return MDNSAS(@"<NULL DOMAIN NAME>");
+        }
+    } else {
+        return MDNSASWithFormat(@"<fail decode - data type> %@", [(NSObject *)value description]);
+    }
+
+    buffer[0] = '\0';
+    ret = DomainNameToString((const uint8_t *)data.bytes, ((const uint8_t *) data.bytes) + data.length, buffer, NULL);
+    if (ret != kNoErr) {
+        snprintf(buffer, sizeof(buffer), "<Malformed Domain Name>");
+    }
+
+    NSString *str = @(buffer);
+    return MDNSAS(str ? str : @("<Could not create NSString>"));
+}
+
+struct MDNSOLFormatters {
+    const char *type;
+    NS_RETURNS_RETAINED NSAttributedString *(*function)(id);
+};
+
+NS_RETURNS_RETAINED
+NSAttributedString *
+OSLogCopyFormattedString(const char *type, id value, __unused os_log_type_info_t info)
+{
+    static const struct MDNSOLFormatters formatters[] = {
+        { .type = "ip_addr",       .function = MDNSOLCopyFormattedStringmDNSIPAddr },
+        { .type = "mac_addr",      .function = MDNSOLCopyFormattedStringmDNSMACAddr },
+        { .type = "domain_name",   .function = MDNSOLCopyFormattedStringmDNSLabelSequenceName },
+    };
+
+    for (int i = 0; i < (int)(sizeof(formatters) / sizeof(formatters[0])); i++) {
+        if (strcmp(type, formatters[i].type) == 0) {
+            return formatters[i].function(value);
+        }
+    }
+
+    return nil;
+}
index e37722998ab056b0a5908d07dff009bfbb897cfe..2594db82890603b17df088d6c4e95b3f9bac3b5c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2016-2019 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.
 #define __Metrics_h
 
 #include "mDNSEmbeddedAPI.h"
-#include <TargetConditionals.h>
 
 #ifdef  __cplusplus
 extern "C" {
 #endif
 
-#if TARGET_OS_IOS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
 mStatus MetricsInit(void);
-void    MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell);
-void    MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell);
+void    MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell);
 void    MetricsUpdateDNSQuerySize(mDNSu32 inSize);
 void    MetricsUpdateDNSResponseSize(mDNSu32 inSize);
-void    LogMetrics(void);
+void    LogMetricsToFD(int fd);
 #endif
 
 #ifdef  __cplusplus
index dd20bc27b50f548dacc29ad7e5f9f436e731a6c9..88de0882c0509c4224ae7094c62d007cf3337c0d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2016-2019 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.
 
 #import "Metrics.h"
 
-#if (TARGET_OS_IOS)
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
 #import <CoreUtils/SoftLinking.h>
 #import <WirelessDiagnostics/AWDDNSDomainStats.h>
 #import <WirelessDiagnostics/AWDMDNSResponderDNSMessageSizeStats.h>
 #import <WirelessDiagnostics/AWDMDNSResponderDNSStatistics.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStats.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDNSServer.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsDomain.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsHostname.h>
-#import <WirelessDiagnostics/AWDMDNSResponderResolveStatsResult.h>
 #import <WirelessDiagnostics/AWDMDNSResponderServicesStats.h>
 #import <WirelessDiagnostics/AWDMetricIds_MDNSResponder.h>
 #import <WirelessDiagnostics/WirelessDiagnostics.h>
@@ -54,20 +49,6 @@ SOFT_LINK_CLASS(WirelessDiagnostics, AWDDNSDomainStats)
 #define AWDMDNSResponderDNSStatisticsSoft       getAWDMDNSResponderDNSStatisticsClass()
 #define AWDDNSDomainStatsSoft                   getAWDDNSDomainStatsClass()
 
-// Classes for resolve stats
-
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStats)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDNSServer)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsDomain)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsHostname)
-SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderResolveStatsResult)
-
-#define AWDMDNSResponderResolveStatsSoft                getAWDMDNSResponderResolveStatsClass()
-#define AWDMDNSResponderResolveStatsDNSServerSoft       getAWDMDNSResponderResolveStatsDNSServerClass()
-#define AWDMDNSResponderResolveStatsDomainSoft          getAWDMDNSResponderResolveStatsDomainClass()
-#define AWDMDNSResponderResolveStatsHostnameSoft        getAWDMDNSResponderResolveStatsHostnameClass()
-#define AWDMDNSResponderResolveStatsResultSoft          getAWDMDNSResponderResolveStatsResultClass()
-
 // Classes for services stats
 
 SOFT_LINK_CLASS(WirelessDiagnostics, AWDMetricManager)
@@ -86,7 +67,6 @@ SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSMessageSizeStats)
 
 #define countof(X)                      (sizeof(X) / sizeof(X[0]))
 #define countof_field(TYPE, FIELD)      countof(((TYPE *)0)->FIELD)
-#define increment_saturate(VAR, MAX)    do {if ((VAR) < (MAX)) {++(VAR);}} while (0)
 #define ForgetMem(X)                    do {if(*(X)) {free(*(X)); *(X) = NULL;}} while(0)
 
 //===========================================================================================================================
@@ -97,7 +77,7 @@ SOFT_LINK_CLASS(WirelessDiagnostics, AWDMDNSResponderDNSMessageSizeStats)
 #define kQueryStatsSendCountBinCount        (kQueryStatsMaxQuerySendCount + 1)
 #define kQueryStatsLatencyBinCount          55
 #define kQueryStatsExpiredAnswerStateCount  (ExpiredAnswer_EnumCount)
-#define kResolveStatsMaxObjCount            2000
+#define kQueryStatsDNSOverTCPStateCount     (DNSOverTCP_EnumCount)
 
 //===========================================================================================================================
 //  Data structures
@@ -153,7 +133,8 @@ typedef struct
     uint16_t    responseLatencyBins[kQueryStatsLatencyBinCount];
     uint16_t    negAnsweredQuerySendCountBins[kQueryStatsSendCountBinCount];
     uint16_t    negResponseLatencyBins[kQueryStatsLatencyBinCount];
-    uint16_t    expiredAnswerStateBins[kQueryStatsExpiredAnswerStateCount];
+    uint32_t    expiredAnswerStateBins[kQueryStatsExpiredAnswerStateCount];
+    uint32_t    dnsOverTCPStateBins[kQueryStatsDNSOverTCPStateCount];
 
 }   DNSHist;
 
@@ -161,7 +142,8 @@ check_compile_time(sizeof(DNSHist) <= 512);
 check_compile_time(countof_field(DNSHist, unansweredQuerySendCountBins)  == (kQueryStatsMaxQuerySendCount + 1));
 check_compile_time(countof_field(DNSHist, answeredQuerySendCountBins)    == (kQueryStatsMaxQuerySendCount + 1));
 check_compile_time(countof_field(DNSHist, negAnsweredQuerySendCountBins) == (kQueryStatsMaxQuerySendCount + 1));
-check_compile_time(countof_field(DNSHist, expiredAnswerStateBins)         == (kQueryStatsExpiredAnswerStateCount));
+check_compile_time(countof_field(DNSHist, expiredAnswerStateBins)        == (kQueryStatsExpiredAnswerStateCount));
+check_compile_time(countof_field(DNSHist, dnsOverTCPStateBins)           == (kQueryStatsDNSOverTCPStateCount));
 
 // Important: Do not modify kResponseLatencyMsLimits because the code used to generate AWD reports expects the response
 // latency histogram bins to observe these time interval upper bounds.
@@ -197,120 +179,6 @@ typedef struct
 
 }   QueryStatsArgs;
 
-// Data structures for resolve stats.
-
-static const char * const       kResolveStatsDomains[] =
-{
-    "apple.com.",
-    "icloud.com.",
-    "mzstatic.com.",
-    "me.com."
-};
-
-check_compile_time(countof(kResolveStatsDomains) == 4);
-
-typedef struct ResolveStatsDomain           ResolveStatsDomain;
-typedef struct ResolveStatsHostname         ResolveStatsHostname;
-typedef struct ResolveStatsDNSServer        ResolveStatsDNSServer;
-typedef struct ResolveStatsIPv4AddrSet      ResolveStatsIPv4AddrSet;
-typedef struct ResolveStatsIPv6Addr         ResolveStatsIPv6Addr;
-typedef struct ResolveStatsNegAAAASet       ResolveStatsNegAAAASet;
-
-struct ResolveStatsDomain
-{
-    ResolveStatsDomain *        next;           // Next domain object in list.
-    const char *                domainStr;
-    uint8_t *                   domain;         // Domain for which these stats are collected.
-    int                         labelCount;     // Number of labels in domain name. Used for domain name comparisons.
-    ResolveStatsHostname *      hostnameList;   // List of hostname objects in this domain.
-};
-
-check_compile_time(sizeof(ResolveStatsDomain) <= 40);
-
-struct ResolveStatsHostname
-{
-    ResolveStatsHostname *          next;       // Next hostname object in list.
-    ResolveStatsIPv4AddrSet *       addrV4List; // List of IPv4 addresses to which this hostname resolved.
-    ResolveStatsIPv6Addr *          addrV6List; // List of IPv6 addresses to which this hostname resolved.
-    ResolveStatsNegAAAASet *        negV6List;  // List of negative AAAA response objects.
-    uint8_t                         name[1];    // Variable length storage for hostname as length-prefixed labels.
-};
-
-check_compile_time(sizeof(ResolveStatsHostname) <= 64);
-
-struct ResolveStatsDNSServer
-{
-    ResolveStatsDNSServer *     next;           // Next DNS server object in list.
-    uint8_t                     id;             // 8-bit ID assigned to this DNS server used by IP address objects.
-    mDNSBool                    isForCell;      // True if this DNS server belongs to a cellular interface.
-    mDNSBool                    isAddrV6;       // True if this DNS server has an IPv6 address instead of IPv4.
-    uint8_t                     addrBytes[1];   // Variable length storage for DNS server's IP address.
-};
-
-check_compile_time(sizeof(ResolveStatsDNSServer) <= 32);
-
-typedef struct
-{
-    uint16_t        count;          // Number of times this IPv4 address was provided as a resolution result.
-    uint8_t         serverID;       // 8-bit ID of the DNS server from which this IPv4 address came.
-    uint8_t         isNegative;
-    uint8_t         addrBytes[4];   // IPv4 address bytes.
-
-}   IPv4AddrCounter;
-
-check_compile_time(sizeof(IPv4AddrCounter) <= 8);
-
-struct ResolveStatsIPv4AddrSet
-{
-    ResolveStatsIPv4AddrSet *       next;           // Next set of IPv4 address counters in list.
-    IPv4AddrCounter                 counters[3];    // Array of IPv4 address counters.
-};
-
-check_compile_time(sizeof(ResolveStatsIPv4AddrSet) <= 32);
-
-struct ResolveStatsIPv6Addr
-{
-    ResolveStatsIPv6Addr *      next;           // Next IPv6 address object in list.
-    uint16_t                    count;          // Number of times this IPv6 address was provided as a resolution result.
-    uint8_t                     serverID;       // 8-bit ID of the DNS server from which this IPv6 address came.
-    uint8_t                     addrBytes[16];  // IPv6 address bytes.
-};
-
-check_compile_time(sizeof(ResolveStatsIPv6Addr) <= 32);
-
-typedef struct
-{
-    uint16_t        count;      // Number of times that a negative response was returned by a DNS server.
-    uint8_t         serverID;   // 8-bit ID of the DNS server that sent the negative responses.
-
-}   NegAAAACounter;
-
-check_compile_time(sizeof(NegAAAACounter) <= 4);
-
-struct ResolveStatsNegAAAASet
-{
-    ResolveStatsNegAAAASet *        next;           // Next set of negative AAAA response counters in list.
-    NegAAAACounter                  counters[6];    // Array of negative AAAA response counters.
-};
-
-check_compile_time(sizeof(ResolveStatsNegAAAASet) <= 32);
-
-typedef enum
-{
-    kResponseType_IPv4Addr  = 1,
-    kResponseType_IPv6Addr  = 2,
-    kResponseType_NegA      = 3,
-    kResponseType_NegAAAA   = 4
-
-}   ResponseType;
-
-typedef struct
-{
-    ResponseType        type;
-    const uint8_t *     data;
-
-}   Response;
-
 // Data structures for DNS message size stats.
 
 #define kQuerySizeBinWidth      16
@@ -331,12 +199,12 @@ check_compile_time((kResponseSizeBinMax % kResponseSizeBinWidth) == 0);
 
 typedef struct
 {
-    uint16_t    querySizeBins[kQuerySizeBinCount];
-    uint16_t    responseSizeBins[kResponseSizeBinCount];
+    uint32_t    querySizeBins[kQuerySizeBinCount];
+    uint32_t    responseSizeBins[kResponseSizeBinCount];
 
 }   DNSMessageSizeStats;
 
-check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
+check_compile_time(sizeof(DNSMessageSizeStats) <= 264);
 
 //===========================================================================================================================
 //  Local Prototypes
@@ -347,72 +215,70 @@ check_compile_time(sizeof(DNSMessageSizeStats) <= 132);
 mDNSlocal mStatus       QueryStatsCreate(const char *inDomainStr, const char *inAltDomainStr, QueryNameTest_f inTest, mDNSBool inTerminal, QueryStats **outStats);
 mDNSlocal void          QueryStatsFree(QueryStats *inStats);
 mDNSlocal void          QueryStatsFreeList(QueryStats *inList);
-mDNSlocal mStatus       QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell);
+mDNSlocal mStatus       QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell);
 mDNSlocal const char *  QueryStatsGetDomainString(const QueryStats *inStats);
 mDNSlocal mDNSBool      QueryStatsDomainTest(const QueryStats *inStats, const domainname *inQueryName);
 mDNSlocal mDNSBool      QueryStatsHostnameTest(const QueryStats *inStats, const domainname *inQueryName);
 mDNSlocal mDNSBool      QueryStatsContentiCloudTest(const QueryStats *inStats, const domainname *inQueryName);
 mDNSlocal mDNSBool      QueryStatsCourierPushTest(const QueryStats *inStats, const domainname *inQueryName);
 
-// Resolve stats
-
-mDNSlocal mStatus   ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain);
-mDNSlocal void      ResolveStatsDomainFree(ResolveStatsDomain *inDomain);
-mDNSlocal mStatus   ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell);
-mDNSlocal mStatus   ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain);
-
-mDNSlocal mStatus   ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname);
-mDNSlocal void      ResolveStatsHostnameFree(ResolveStatsHostname *inHostname);
-mDNSlocal mStatus   ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID);
-mDNSlocal mStatus   ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname);
-
-mDNSlocal mStatus   ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer);
-mDNSlocal void      ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer);
-mDNSlocal mStatus   ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer);
-
-mDNSlocal mStatus   ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet);
-mDNSlocal void      ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet);
-
-mDNSlocal mStatus   ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr);
-mDNSlocal void      ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr);
-
-mDNSlocal mStatus   ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet);
-mDNSlocal void      ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet);
-mDNSlocal mStatus   ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID);
-
 // DNS message size stats
 
 mDNSlocal mStatus   DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats);
 mDNSlocal void      DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats);
 
 mDNSlocal mStatus   CreateQueryStatsList(QueryStats **outList);
-mDNSlocal mStatus   CreateResolveStatsList(ResolveStatsDomain **outList);
-mDNSlocal void      FreeResolveStatsList(ResolveStatsDomain *inList);
-mDNSlocal void      FreeResolveStatsServerList(ResolveStatsDNSServer *inList);
 mDNSlocal mStatus   SubmitAWDMetric(UInt32 inMetricID);
 mDNSlocal mStatus   SubmitAWDMetricQueryStats(void);
-mDNSlocal mStatus   SubmitAWDMetricResolveStats(void);
 mDNSlocal mStatus   SubmitAWDMetricDNSMessageSizeStats(void);
 mDNSlocal mStatus   CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain, mDNSBool inForCell, AWDDNSDomainStats_RecordType inType, AWDDNSDomainStats **outStats);
-mDNSlocal void      LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
-mDNSlocal void      LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
-mDNSlocal void      LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
-mDNSlocal void      LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
-mDNSlocal void      LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth);
+mDNSlocal void      LogDNSHistSetToFD(int fd, const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
+mDNSlocal void      LogDNSHistToFD(int fd, const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType);
+mDNSlocal void      LogDNSHistSendCountsToFD(int fd, const uint16_t inSendCountBins[kQueryStatsSendCountBinCount]);
+mDNSlocal void      LogDNSHistLatenciesToFD(int fd, const uint16_t inLatencyBins[kQueryStatsLatencyBinCount]);
+mDNSlocal void      LogDNSMessageSizeStatsToFD(int fd, const uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth);
+
+//===========================================================================================================================
+//  Histogram Bin Helpers
+//===========================================================================================================================
+
+#define INCREMENT_BIN_DEFINITION(BIN_SIZE) \
+    mDNSlocal void IncrementBin ## BIN_SIZE (uint ## BIN_SIZE ## _t *inBin) \
+    { \
+        if (*inBin < UINT ## BIN_SIZE ## _MAX) ++(*inBin); \
+    } \
+    extern int _MetricsDummyVariable
+
+INCREMENT_BIN_DEFINITION(16);
+INCREMENT_BIN_DEFINITION(32);
+
+//  Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
+//  bin and all bins with non-zero values.
+
+#define COPY_BINS_DEFINITION(BIN_SIZE) \
+    mDNSlocal size_t CopyBins ## BIN_SIZE (uint32_t *inDstBins, uint ## BIN_SIZE ## _t *inSrcBins, size_t inBinCount) \
+    { \
+        if (inBinCount == 0) return (0); \
+        size_t minCount = 1; \
+        for (size_t i = 0; i < inBinCount; ++i) \
+        { \
+            inDstBins[i] = inSrcBins[i]; \
+            if (inDstBins[i] > 0) minCount = i + 1; \
+        } \
+        return (minCount); \
+    } \
+    extern int _MetricsDummyVariable
 
-mDNSlocal size_t    CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount);
+COPY_BINS_DEFINITION(16);
+COPY_BINS_DEFINITION(32);
 
 //===========================================================================================================================
 //  Globals
 //===========================================================================================================================
 
-static AWDServerConnection *        gAWDServerConnection        = nil;
-static QueryStats *                 gQueryStatsList             = NULL;
-static ResolveStatsDomain *         gResolveStatsList           = NULL;
-static ResolveStatsDNSServer *      gResolveStatsServerList     = NULL;
-static unsigned int                 gResolveStatsNextServerID   = 0;
-static int                          gResolveStatsObjCount       = 0;
-static DNSMessageSizeStats *        gDNSMessageSizeStats        = NULL;
+static AWDServerConnection *        gAWDServerConnection    = nil;
+static QueryStats *                 gQueryStatsList         = NULL;
+static DNSMessageSizeStats *        gDNSMessageSizeStats    = NULL;
 
 // Important: Do not add to this list without getting privacy approval. See <rdar://problem/24155761&26397203&34763471>.
 
@@ -454,13 +320,6 @@ mStatus MetricsInit(void)
                 }
                 forIdentifier: (UInt32)AWDMetricId_MDNSResponder_DNSStatistics];
 
-            [gAWDServerConnection
-                registerQueriableMetricCallback: ^(UInt32 inMetricID)
-                {
-                    SubmitAWDMetric(inMetricID);
-                }
-                forIdentifier: (UInt32)AWDMetricId_MDNSResponder_ResolveStats];
-
             [gAWDServerConnection
                 registerQueriableMetricCallback: ^(UInt32 inMetricID)
                 {
@@ -484,7 +343,6 @@ mStatus MetricsInit(void)
     if( gAWDServerConnection )
     {
         CreateQueryStatsList(&gQueryStatsList);
-        CreateResolveStatsList(&gResolveStatsList);
         DNSMessageSizeStatsCreate(&gDNSMessageSizeStats);
     }
 
@@ -495,7 +353,7 @@ mStatus MetricsInit(void)
 //  MetricsUpdateDNSQueryStats
 //===========================================================================================================================
 
-mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell)
+mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu16 inType, const ResourceRecord *inRR, mDNSu32 inSendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell)
 {
     QueryStats *        stats;
     mDNSBool            match;
@@ -508,7 +366,7 @@ mDNSexport void MetricsUpdateDNSQueryStats(const domainname *inQueryName, mDNSu1
         match = stats->test(stats, inQueryName);
         if (match)
         {
-            QueryStatsUpdate(stats, inType, inRR, inSendCount, inExpiredAnswerState, inLatencyMs, inForCell);
+            QueryStatsUpdate(stats, inType, inRR, inSendCount, inExpiredAnswerState, inDNSOverTCPState, inLatencyMs, inForCell);
             if (stats->terminal) break;
         }
     }
@@ -517,71 +375,11 @@ exit:
     return;
 }
 
-//===========================================================================================================================
-//  MetricsUpdateDNSResolveStats
-//===========================================================================================================================
-
-mDNSexport void MetricsUpdateDNSResolveStats(const domainname *inQueryName, const ResourceRecord *inRR, mDNSBool inForCell)
-{
-    ResolveStatsDomain *        domainStats;
-    domainname                  hostname;
-    size_t                      hostnameLen;
-    mDNSBool                    isQueryInDomain;
-    int                         skipCount;
-    int                         skipCountLast = -1;
-    int                         queryLabelCount;
-    const domainname *          queryParentDomain;
-    Response                    response;
-
-    require_quiet(gAWDServerConnection, exit);
-    require_quiet((inRR->rrtype == kDNSType_A) || (inRR->rrtype == kDNSType_AAAA), exit);
-    require_quiet(inRR->rDNSServer, exit);
-
-    queryLabelCount = CountLabels(inQueryName);
-
-    for (domainStats = gResolveStatsList; domainStats; domainStats = domainStats->next)
-    {
-        isQueryInDomain = mDNSfalse;
-        skipCount = queryLabelCount - domainStats->labelCount;
-        if (skipCount >= 0)
-        {
-            if (skipCount != skipCountLast)
-            {
-                queryParentDomain = SkipLeadingLabels(inQueryName, skipCount);
-                skipCountLast = skipCount;
-            }
-            isQueryInDomain = SameDomainName(queryParentDomain, (const domainname *)domainStats->domain);
-        }
-        if (!isQueryInDomain) continue;
-
-        hostnameLen = (size_t)(queryParentDomain->c - inQueryName->c);
-        if (hostnameLen >= sizeof(hostname.c)) continue;
-
-        memcpy(hostname.c, inQueryName->c, hostnameLen);
-        hostname.c[hostnameLen] = 0;
-
-        if (inRR->RecordType == kDNSRecordTypePacketNegative)
-        {
-            response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_NegA : kResponseType_NegAAAA;
-            response.data = NULL;
-        }
-        else
-        {
-            response.type = (inRR->rrtype == kDNSType_A) ? kResponseType_IPv4Addr : kResponseType_IPv6Addr;
-            response.data = (inRR->rrtype == kDNSType_A) ? inRR->rdata->u.ipv4.b : inRR->rdata->u.ipv6.b;
-        }
-        ResolveStatsDomainUpdate(domainStats, &hostname, &response, &inRR->rDNSServer->addr, inForCell);
-    }
-
-exit:
-    return;
-}
-
 //===========================================================================================================================
 //  MetricsUpdateDNSQuerySize
 //===========================================================================================================================
 
-mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
+mDNSlocal void UpdateMessageSizeCounts(uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize);
 
 mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
 {
@@ -589,14 +387,14 @@ mDNSexport void MetricsUpdateDNSQuerySize(mDNSu32 inSize)
     UpdateMessageSizeCounts(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth, inSize);
 }
 
-mDNSlocal void UpdateMessageSizeCounts(uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
+mDNSlocal void UpdateMessageSizeCounts(uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth, uint32_t inSize)
 {
     size_t      i;
 
     if (inSize == 0) return;
     i = (inSize - 1) / inBinWidth;
     if (i >= inBinCount) i = inBinCount - 1;
-    increment_saturate(inBins[i], UINT16_MAX);
+    IncrementBin32(&inBins[i]);
 }
 
 //===========================================================================================================================
@@ -613,125 +411,39 @@ mDNSexport void MetricsUpdateDNSResponseSize(mDNSu32 inSize)
 //  LogMetrics
 //===========================================================================================================================
 
-mDNSexport void LogMetrics(void)
+mDNSexport void LogMetricsToFD(int fd)
 {
-    QueryStats *                        stats;
-    const ResolveStatsDomain *          domain;
-    const ResolveStatsHostname *        hostname;
-    const ResolveStatsDNSServer *       server;
-    const ResolveStatsIPv4AddrSet *     addrV4;
-    const ResolveStatsIPv6Addr *        addrV6;
-    const ResolveStatsNegAAAASet *      negV6;
-    int                                 hostnameCount;
-    int                                 i;
-    unsigned int                        serverID;
-    int                                 serverObjCount   = 0;
-    int                                 hostnameObjCount = 0;
-    int                                 addrObjCount     = 0;
-
-    LogMsgNoIdent("gAWDServerConnection %p", gAWDServerConnection);
-    LogMsgNoIdent("---- DNS query stats by domain -----");
+    QueryStats *        stats;
+
+    LogToFD(fd, "gAWDServerConnection %p", gAWDServerConnection);
+    LogToFD(fd, "---- DNS query stats by domain -----");
 
     for (stats = gQueryStatsList; stats; stats = stats->next)
     {
         if (!stats->nonCellular && !stats->cellular)
         {
-            LogMsgNoIdent("No data for %s", QueryStatsGetDomainString(stats));
+            LogToFD(fd, "No data for %s", QueryStatsGetDomainString(stats));
             continue;
         }
-        if (stats->nonCellular) LogDNSHistSet(stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
-        if (stats->cellular)    LogDNSHistSet(stats->cellular,    QueryStatsGetDomainString(stats), mDNStrue);
-    }
-
-    LogMsgNoIdent("---- DNS resolve stats by domain -----");
-
-    LogMsgNoIdent("Servers:");
-    for (server = gResolveStatsServerList; server; server = server->next)
-    {
-        serverObjCount++;
-        LogMsgNoIdent(server->isAddrV6 ? "%2u: %s %.16a" : "%2u: %s %.4a",
-            server->id, server->isForCell ? " C" : "NC", server->addrBytes);
-    }
-
-    for (domain = gResolveStatsList; domain; domain = domain->next)
-    {
-        hostnameCount = 0;
-        for (hostname = domain->hostnameList; hostname; hostname = hostname->next) { hostnameCount++; }
-        hostnameObjCount += hostnameCount;
-
-        LogMsgNoIdent("%s (%d hostname%s)", domain->domainStr, hostnameCount, (hostnameCount == 1) ? "" : "s");
-
-        for (hostname = domain->hostnameList; hostname; hostname = hostname->next)
-        {
-            LogMsgNoIdent("    %##s", hostname->name);
-            for (serverID = 0; serverID < gResolveStatsNextServerID; ++serverID)
-            {
-                for (addrV4 = hostname->addrV4List; addrV4; addrV4 = addrV4->next)
-                {
-                    if (serverID == 0) addrObjCount++;
-                    for (i = 0; i < (int)countof(addrV4->counters); ++i)
-                    {
-                        const IPv4AddrCounter *      counter;
-
-                        counter = &addrV4->counters[i];
-                        if (counter->count == 0) break;
-                        if (counter->serverID == serverID)
-                        {
-                            if (counter->isNegative)
-                            {
-                                LogMsgNoIdent("%10u: %3u negative A", counter->serverID, counter->count);
-                            }
-                            else
-                            {
-                                LogMsgNoIdent("%10u: %3u %.4a", counter->serverID, counter->count, counter->addrBytes);
-                            }
-                        }
-                    }
-                }
-                for (addrV6 = hostname->addrV6List; addrV6; addrV6 = addrV6->next)
-                {
-                    if (serverID == 0) addrObjCount++;
-                    if (addrV6->serverID == serverID)
-                    {
-                        LogMsgNoIdent("%10u: %3u %.16a", addrV6->serverID, addrV6->count, addrV6->addrBytes);
-                    }
-                }
-                for (negV6 = hostname->negV6List; negV6; negV6 = negV6->next)
-                {
-                    if (serverID == 0) addrObjCount++;
-                    for (i = 0; i < (int)countof(negV6->counters); ++i)
-                    {
-                        const NegAAAACounter *      counter;
-
-                        counter = &negV6->counters[i];
-                        if (counter->count == 0) break;
-                        if (counter->serverID == serverID)
-                        {
-                            LogMsgNoIdent("%10u: %3u negative AAAA", counter->serverID, counter->count);
-                        }
-                    }
-                }
-            }
-        }
+        if (stats->nonCellular) LogDNSHistSetToFD(fd, stats->nonCellular, QueryStatsGetDomainString(stats), mDNSfalse);
+        if (stats->cellular)    LogDNSHistSetToFD(fd, stats->cellular,    QueryStatsGetDomainString(stats), mDNStrue);
     }
-    LogMsgNoIdent("Total object count: %3d (server %d hostname %d address %d)",
-        serverObjCount + hostnameObjCount + addrObjCount, serverObjCount, hostnameObjCount, addrObjCount);
 
-    LogMsgNoIdent("---- Num of Services Registered -----");
-    LogMsgNoIdent("Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
-                  curr_num_regservices, max_num_regservices);
+    LogToFD(fd, "---- Num of Services Registered -----");
+    LogToFD(fd, "Current_number_of_services_registered :[%d], Max_number_of_services_registered :[%d]",
+              curr_num_regservices, max_num_regservices);
 
     if (gDNSMessageSizeStats)
     {
-        LogMsgNoIdent("---- DNS query size stats ---");
-        LogDNSMessageSizeStats(gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
+        LogToFD(fd, "---- DNS query size stats ---");
+        LogDNSMessageSizeStatsToFD(fd, gDNSMessageSizeStats->querySizeBins, kQuerySizeBinCount, kQuerySizeBinWidth);
 
-        LogMsgNoIdent("-- DNS response size stats --");
-        LogDNSMessageSizeStats(gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
+        LogToFD(fd, "-- DNS response size stats --");
+        LogDNSMessageSizeStatsToFD(fd, gDNSMessageSizeStats->responseSizeBins, kResponseSizeBinCount, kResponseSizeBinWidth);
     }
     else
     {
-        LogMsgNoIdent("No DNS message size stats.");
+        LogToFD(fd, "No DNS message size stats.");
     }
 }
 
@@ -842,7 +554,7 @@ mDNSlocal void QueryStatsFreeList(QueryStats *inList)
 //  QueryStatsUpdate
 //===========================================================================================================================
 
-mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, mDNSu32 inLatencyMs, mDNSBool inForCell)
+mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const ResourceRecord *inRR, mDNSu32 inQuerySendCount, ExpiredAnswerMetric inExpiredAnswerState, DNSOverTCPMetric inDNSOverTCPState, mDNSu32 inLatencyMs, mDNSBool inForCell)
 {
     mStatus             err;
     DNSHistSet *        set;
@@ -878,24 +590,25 @@ mDNSlocal mStatus QueryStatsUpdate(QueryStats *inStats, int inType, const Resour
         i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
 
         sendCountBins = isNegative ? hist->negAnsweredQuerySendCountBins : hist->answeredQuerySendCountBins;
-        increment_saturate(sendCountBins[i], UINT16_MAX);
+        IncrementBin16(&sendCountBins[i]);
 
         if (inQuerySendCount > 0)
         {
             for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
             latencyBins = isNegative ? hist->negResponseLatencyBins : hist->responseLatencyBins;
-            increment_saturate(latencyBins[i], UINT16_MAX);
+            IncrementBin16(&latencyBins[i]);
         }
     }
     else
     {
         i = Min(inQuerySendCount, kQueryStatsMaxQuerySendCount);
-        increment_saturate(hist->unansweredQuerySendCountBins[i], UINT16_MAX);
+        IncrementBin16(&hist->unansweredQuerySendCountBins[i]);
 
         for (i = 0; (i < (int)countof(kResponseLatencyMsLimits)) && (inLatencyMs >= kResponseLatencyMsLimits[i]); ++i) {}
-        increment_saturate(hist->unansweredQueryDurationBins[i], UINT16_MAX);
+        IncrementBin16(&hist->unansweredQueryDurationBins[i]);
     }
-    increment_saturate(hist->expiredAnswerStateBins[Min(inExpiredAnswerState, (kQueryStatsExpiredAnswerStateCount-1))], UINT16_MAX);
+    IncrementBin32(&hist->expiredAnswerStateBins[Min(inExpiredAnswerState, (kQueryStatsExpiredAnswerStateCount - 1))]);
+    IncrementBin32(&hist->dnsOverTCPStateBins[Min(inDNSOverTCPState, (kQueryStatsDNSOverTCPStateCount - 1))]);
     err = mStatus_NoError;
 
 exit:
@@ -1034,882 +747,182 @@ mDNSlocal mDNSBool QueryStatsCourierPushTest(const QueryStats *inStats, const do
 }
 
 //===========================================================================================================================
-//  ResolveStatsDomainCreate
+//  DNSMessageSizeStatsCreate
 //===========================================================================================================================
 
-mDNSlocal mStatus ResolveStatsDomainCreate(const char *inDomainStr, ResolveStatsDomain **outDomain)
+mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
 {
     mStatus                     err;
-    ResolveStatsDomain *        obj;
-
-    obj = (ResolveStatsDomain *)calloc(1, sizeof(*obj));
-    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
-    obj->domainStr = inDomainStr;
-    err = StringToDomainName(obj->domainStr, &obj->domain);
-    require_noerr_quiet(err, exit);
+    DNSMessageSizeStats *       stats;
 
-    obj->labelCount = CountLabels((const domainname *)obj->domain);
+    stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
+    require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
 
-    *outDomain = obj;
-    obj = NULL;
+    *outStats = stats;
     err = mStatus_NoError;
 
 exit:
-    if (obj) ResolveStatsDomainFree(obj);
     return (err);
 }
 
 //===========================================================================================================================
-//  ResolveStatsDomainFree
+//  DNSMessageSizeStatsFree
 //===========================================================================================================================
 
-mDNSlocal void ResolveStatsDomainFree(ResolveStatsDomain *inDomain)
+mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
 {
-    ResolveStatsHostname *      hostname;
-
-    ForgetMem(&inDomain->domain);
-    while ((hostname = inDomain->hostnameList) != NULL)
-    {
-        inDomain->hostnameList = hostname->next;
-        ResolveStatsHostnameFree(hostname);
-    }
-    free(inDomain);
+    free(inStats);
 }
 
 //===========================================================================================================================
-//  ResolveStatsDomainUpdate
+//  CreateQueryStatsList
 //===========================================================================================================================
 
-mDNSlocal mStatus ResolveStatsDomainUpdate(ResolveStatsDomain *inDomain, const domainname *inHostname, const Response *inResp, const mDNSAddr *inDNSAddr, mDNSBool inForCell)
+mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
 {
-    mStatus                     err;
-    ResolveStatsHostname **     p;
-    ResolveStatsHostname *      hostname;
-    uint8_t                     serverID;
-
-    for (p = &inDomain->hostnameList; (hostname = *p) != NULL; p = &hostname->next)
-    {
-        if (SameDomainName((domainname *)hostname->name, inHostname)) break;
-    }
+    mStatus                             err;
+    QueryStats **                       p;
+    QueryStats *                        stats;
+    const QueryStatsArgs *              args;
+    const QueryStatsArgs * const        end     = kQueryStatsArgs + countof(kQueryStatsArgs);
+    QueryStats *                        list    = NULL;
 
-    if (!hostname)
+    p = &list;
+    for (args = kQueryStatsArgs; args < end; ++args)
     {
-        require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
-        err = ResolveStatsHostnameCreate(inHostname, &hostname);
+        err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
         require_noerr_quiet(err, exit);
-        gResolveStatsObjCount++;
-        *p = hostname;
-    }
 
-    err = ResolveStatsGetServerID(inDNSAddr, inForCell, &serverID);
-    require_noerr_quiet(err, exit);
+        *p = stats;
+        p = &stats->next;
+    }
 
-    err = ResolveStatsHostnameUpdate(hostname, inResp, serverID);
-    require_noerr_quiet(err, exit);
+    *outList = list;
+    list = NULL;
+    err = mStatus_NoError;
 
 exit:
+    QueryStatsFreeList(list);
     return (err);
 }
 
 //===========================================================================================================================
-//  ResolveStatsHostnameCreate
+//  SubmitAWDMetric
 //===========================================================================================================================
 
-mDNSlocal mStatus ResolveStatsHostnameCreate(const domainname *inName, ResolveStatsHostname **outHostname)
+mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
 {
-    mStatus                     err;
-    ResolveStatsHostname *      obj;
-    size_t                      nameLen;
+    mStatus     err;
 
-    nameLen = DomainNameLength(inName);
-    require_action_quiet(nameLen > 0, exit, err = mStatus_Invalid);
+    switch (inMetricID)
+    {
+        case AWDMetricId_MDNSResponder_DNSStatistics:
+            err = SubmitAWDMetricQueryStats();
+            break;
 
-    obj = (ResolveStatsHostname *)calloc(1, sizeof(*obj) - 1 + nameLen);
-    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
+        case AWDMetricId_MDNSResponder_ServicesStats:
+            [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
+            KQueueLock();
+            // reset the no of max services since we want to collect the max no of services registered per AWD submission period
+            max_num_regservices = curr_num_regservices;
+            KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
+            err = mStatus_NoError;
+            break;
 
-    memcpy(obj->name, inName, nameLen);
+        case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
+            err = SubmitAWDMetricDNSMessageSizeStats();
+            break;
 
-    *outHostname = obj;
-    err = mStatus_NoError;
+        default:
+            err = mStatus_UnsupportedErr;
+            break;
+    }
 
-exit:
+    if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
     return (err);
 }
 
 //===========================================================================================================================
-//  ResolveStatsDomainCreateAWDVersion
+//  SubmitAWDMetricQueryStats
 //===========================================================================================================================
 
-mDNSlocal mStatus ResolveStatsDomainCreateAWDVersion(const ResolveStatsDomain *inDomain, AWDMDNSResponderResolveStatsDomain **outDomain)
+mDNSlocal mStatus   AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
+mDNSlocal mStatus   AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
+
+mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
 {
-    mStatus                                     err;
-    AWDMDNSResponderResolveStatsDomain *        domain;
-    ResolveStatsHostname *                      hostname;
-    AWDMDNSResponderResolveStatsHostname *      awdHostname;
-    NSString *                                  name;
+    mStatus                             err;
+    BOOL                                success;
+    QueryStats *                        stats;
+    QueryStats *                        statsList;
+    QueryStats *                        newStatsList;
+    AWDMetricContainer *                container   = nil;
+    AWDMDNSResponderDNSStatistics *     metric      = nil;
 
-    domain = [[AWDMDNSResponderResolveStatsDomainSoft alloc] init];
-    require_action_quiet(domain, exit, err = mStatus_UnknownErr);
+    newStatsList = NULL;
+    CreateQueryStatsList(&newStatsList);
+
+    KQueueLock();
+    statsList       = gQueryStatsList;
+    gQueryStatsList = newStatsList;
+    KQueueUnlock("SubmitAWDMetricQueryStats");
 
-    name = [[NSString alloc] initWithUTF8String:inDomain->domainStr];
-    require_action_quiet(name, exit, err = mStatus_UnknownErr);
+    container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
+    require_action_quiet(container, exit, err = mStatus_UnknownErr);
 
-    domain.name = name;
-    [name release];
-    name = nil;
+    metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
+    require_action_quiet(metric, exit, err = mStatus_UnknownErr);
 
-    for (hostname = inDomain->hostnameList; hostname; hostname = hostname->next)
+    while ((stats = statsList) != NULL)
     {
-        err = ResolveStatsHostnameCreateAWDVersion(hostname, &awdHostname);
+        err = AddQueryStats(metric, stats);
         require_noerr_quiet(err, exit);
 
-        [domain addHostname:awdHostname];
-        [awdHostname release];
-        awdHostname = nil;
+        statsList = stats->next;
+        QueryStatsFree(stats);
     }
 
-    *outDomain = domain;
-    domain = nil;
-    err = mStatus_NoError;
+    container.metric = metric;
+    success = [gAWDServerConnection submitMetric:container];
+    LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
+    err = success ? mStatus_NoError : mStatus_UnknownErr;
 
 exit:
-    [domain release];
+    QueryStatsFreeList(statsList);
     return (err);
 }
 
-//===========================================================================================================================
-//  ResolveStatsHostnameFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsHostnameFree(ResolveStatsHostname *inHostname)
+mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
 {
-    ResolveStatsIPv4AddrSet *       addrV4;
-    ResolveStatsIPv6Addr *          addrV6;
-    ResolveStatsNegAAAASet *        negV6;
+    mStatus     err;
 
-    while ((addrV4 = inHostname->addrV4List) != NULL)
-    {
-        inHostname->addrV4List = addrV4->next;
-        ResolveStatsIPv4AddrSetFree(addrV4);
-    }
-    while ((addrV6 = inHostname->addrV6List) != NULL)
+    if (inStats->nonCellular)
     {
-        inHostname->addrV6List = addrV6->next;
-        ResolveStatsIPv6AddressFree(addrV6);
+        err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
+        require_noerr_quiet(err, exit);
     }
-    while ((negV6 = inHostname->negV6List) != NULL)
+    if (inStats->cellular)
     {
-        inHostname->negV6List = negV6->next;
-        ResolveStatsNegAAAASetFree(negV6);
+        err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
+        require_noerr_quiet(err, exit);
     }
-    free(inHostname);
-}
+    err = mStatus_NoError;
 
-//===========================================================================================================================
-//  ResolveStatsHostnameUpdate
-//===========================================================================================================================
+exit:
+    return (err);
+}
 
-mDNSlocal mStatus ResolveStatsHostnameUpdate(ResolveStatsHostname *inHostname, const Response *inResp, uint8_t inServerID)
+mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
 {
-    mStatus     err;
+    mStatus                 err;
+    AWDDNSDomainStats *     awdStats;
 
-    if ((inResp->type == kResponseType_IPv4Addr) || (inResp->type == kResponseType_NegA))
+    if (inSet->histA)
     {
-        ResolveStatsIPv4AddrSet **      p;
-        ResolveStatsIPv4AddrSet *       addrV4;
-        int                             i;
-        IPv4AddrCounter *               counter;
-
-        for (p = &inHostname->addrV4List; (addrV4 = *p) != NULL; p = &addrV4->next)
-        {
-            for (i = 0; i < (int)countof(addrV4->counters); ++i)
-            {
-                counter = &addrV4->counters[i];
-                if (counter->count == 0) break;
-                if (counter->serverID != inServerID) continue;
-                if (inResp->type == kResponseType_NegA)
-                {
-                    if (counter->isNegative) break;
-                }
-                else
-                {
-                    if (memcmp(counter->addrBytes, inResp->data, 4) == 0) break;
-                }
-            }
-            if (i < (int)countof(addrV4->counters)) break;
-        }
-        if (!addrV4)
-        {
-            require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
-            err = ResolveStatsIPv4AddrSetCreate(&addrV4);
-            require_noerr_quiet(err, exit);
-            gResolveStatsObjCount++;
-
-            *p = addrV4;
-            counter = &addrV4->counters[0];
-        }
-        if (counter->count == 0)
-        {
-            counter->serverID = inServerID;
-            if (inResp->type == kResponseType_NegA)
-            {
-                counter->isNegative = 1;
-            }
-            else
-            {
-                counter->isNegative = 0;
-                memcpy(counter->addrBytes, inResp->data, 4);
-            }
-        }
-        increment_saturate(counter->count, UINT16_MAX);
-        err = mStatus_NoError;
-    }
-    else if (inResp->type == kResponseType_IPv6Addr)
-    {
-        ResolveStatsIPv6Addr **     p;
-        ResolveStatsIPv6Addr *      addrV6;
-
-        for (p = &inHostname->addrV6List; (addrV6 = *p) != NULL; p = &addrV6->next)
-        {
-            if ((addrV6->serverID == inServerID) && (memcmp(addrV6->addrBytes, inResp->data, 16) == 0)) break;
-        }
-        if (!addrV6)
-        {
-            require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
-            err = ResolveStatsIPv6AddressCreate(inServerID, inResp->data, &addrV6);
-            require_noerr_quiet(err, exit);
-            gResolveStatsObjCount++;
-
-            *p = addrV6;
-        }
-        increment_saturate(addrV6->count, UINT16_MAX);
-        err = mStatus_NoError;
-    }
-    else if (inResp->type == kResponseType_NegAAAA)
-    {
-        ResolveStatsNegAAAASet **       p;
-        ResolveStatsNegAAAASet *        negV6;
-        int                             i;
-        NegAAAACounter *                counter;
-
-        for (p = &inHostname->negV6List; (negV6 = *p) != NULL; p = &negV6->next)
-        {
-            for (i = 0; i < (int)countof(negV6->counters); ++i)
-            {
-                counter = &negV6->counters[i];
-                if ((counter->count == 0) || (counter->serverID == inServerID)) break;
-            }
-            if (i < (int)countof(negV6->counters)) break;
-        }
-        if (!negV6)
-        {
-            require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
-            err = ResolveStatsNegAAAASetCreate(&negV6);
-            require_noerr_quiet(err, exit);
-            gResolveStatsObjCount++;
-
-            *p = negV6;
-            counter = &negV6->counters[0];
-        }
-        if (counter->count == 0) counter->serverID = inServerID;
-        increment_saturate(counter->count, UINT16_MAX);
-        err = mStatus_NoError;
-    }
-    else
-    {
-        err = mStatus_Invalid;
-    }
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
-//  ResolveStatsHostnameCreateAWDVersion
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsHostnameCreateAWDVersion(const ResolveStatsHostname *inHostname, AWDMDNSResponderResolveStatsHostname **outHostname)
-{
-    mStatus                                     err;
-    AWDMDNSResponderResolveStatsHostname *      hostname;
-    NSString *                                  name;
-    char                                        nameBuf[MAX_ESCAPED_DOMAIN_NAME];
-    const char *                                ptr;
-    ResolveStatsIPv4AddrSet *                   addrV4;
-    ResolveStatsIPv6Addr *                      addrV6;
-    ResolveStatsNegAAAASet *                    negV6;
-    AWDMDNSResponderResolveStatsResult *        result = nil;
-    int                                         i;
-
-    hostname = [[AWDMDNSResponderResolveStatsHostnameSoft alloc] init];
-    require_action_quiet(hostname, exit, err = mStatus_UnknownErr);
-
-    ptr = ConvertDomainNameToCString((domainname *)inHostname->name, nameBuf);
-    require_action_quiet(ptr, exit, err = mStatus_UnknownErr);
-
-    name = [[NSString alloc] initWithUTF8String:nameBuf];
-    require_action_quiet(name, exit, err = mStatus_UnknownErr);
-
-    hostname.name = name;
-    [name release];
-    name = nil;
-
-    for (addrV4 = inHostname->addrV4List; addrV4; addrV4 = addrV4->next)
-    {
-        for (i = 0; i < (int)countof(addrV4->counters); ++i)
-        {
-            const IPv4AddrCounter *     counter;
-            NSData *                    addrBytes;
-
-            counter = &addrV4->counters[i];
-            if (counter->count == 0) break;
-
-            result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
-            require_action_quiet(result, exit, err = mStatus_UnknownErr);
-
-            if (counter->isNegative)
-            {
-                result.type = AWDMDNSResponderResolveStatsResult_ResultType_NegA;
-            }
-            else
-            {
-                addrBytes = [[NSData alloc] initWithBytes:counter->addrBytes length:4];
-                require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
-
-                result.type = AWDMDNSResponderResolveStatsResult_ResultType_IPv4Addr;
-                result.data = addrBytes;
-                [addrBytes release];
-            }
-            result.count    = counter->count;
-            result.serverID = counter->serverID;
-
-            [hostname addResult:result];
-            [result release];
-            result = nil;
-        }
-    }
-
-    for (addrV6 = inHostname->addrV6List; addrV6; addrV6 = addrV6->next)
-    {
-        NSData *        addrBytes;
-
-        result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
-        require_action_quiet(result, exit, err = mStatus_UnknownErr);
-
-        addrBytes = [[NSData alloc] initWithBytes:addrV6->addrBytes length:16];
-        require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
-
-        result.type     = AWDMDNSResponderResolveStatsResult_ResultType_IPv6Addr;
-        result.count    = addrV6->count;
-        result.serverID = addrV6->serverID;
-        result.data     = addrBytes;
-
-        [addrBytes release];
-
-        [hostname addResult:result];
-        [result release];
-        result = nil;
-    }
-
-    for (negV6 = inHostname->negV6List; negV6; negV6 = negV6->next)
-    {
-        for (i = 0; i < (int)countof(negV6->counters); ++i)
-        {
-            const NegAAAACounter *      counter;
-
-            counter = &negV6->counters[i];
-            if (counter->count == 0) break;
-
-            result = [[AWDMDNSResponderResolveStatsResultSoft alloc] init];
-            require_action_quiet(result, exit, err = mStatus_UnknownErr);
-
-            result.type     = AWDMDNSResponderResolveStatsResult_ResultType_NegAAAA;
-            result.count    = counter->count;
-            result.serverID = counter->serverID;
-
-            [hostname addResult:result];
-            [result release];
-            result = nil;
-        }
-    }
-
-    *outHostname = hostname;
-    hostname = nil;
-    err = mStatus_NoError;
-
-exit:
-    [result release];
-    [hostname release];
-    return (err);
-}
-
-//===========================================================================================================================
-//  ResolveStatsDNSServerCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsDNSServerCreate(const mDNSAddr *inAddr, mDNSBool inForCell, ResolveStatsDNSServer **outServer)
-{
-    mStatus                     err;
-    ResolveStatsDNSServer *     obj;
-    size_t                      addrLen;
-
-    require_action_quiet((inAddr->type == mDNSAddrType_IPv4) || (inAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
-
-    addrLen = (inAddr->type == mDNSAddrType_IPv4) ? 4 : 16;
-    obj = (ResolveStatsDNSServer *)calloc(1, sizeof(*obj) - 1 + addrLen);
-    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
-    obj->isForCell = inForCell;
-    if (inAddr->type == mDNSAddrType_IPv4)
-    {
-        obj->isAddrV6 = mDNSfalse;
-        memcpy(obj->addrBytes, inAddr->ip.v4.b, addrLen);
-    }
-    else
-    {
-        obj->isAddrV6 = mDNStrue;
-        memcpy(obj->addrBytes, inAddr->ip.v6.b, addrLen);
-    }
-
-    *outServer = obj;
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
-//  ResolveStatsDNSServerFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsDNSServerFree(ResolveStatsDNSServer *inServer)
-{
-    free(inServer);
-}
-
-//===========================================================================================================================
-//  ResolveStatsDNSServerCreateAWDVersion
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsDNSServerCreateAWDVersion(const ResolveStatsDNSServer *inServer, AWDMDNSResponderResolveStatsDNSServer **outServer)
-{
-    mStatus                                     err;
-    AWDMDNSResponderResolveStatsDNSServer *     server;
-    NSData *                                    addrBytes = nil;
-
-    server = [[AWDMDNSResponderResolveStatsDNSServerSoft alloc] init];
-    require_action_quiet(server, exit, err = mStatus_UnknownErr);
-
-    addrBytes = [[NSData alloc] initWithBytes:inServer->addrBytes length:(inServer->isAddrV6 ? 16 : 4)];
-    require_action_quiet(addrBytes, exit, err = mStatus_UnknownErr);
-
-    server.serverID = inServer->id;
-    server.address  = addrBytes;
-    if (inServer->isForCell)
-    {
-        server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_Cellular;
-    }
-    else
-    {
-        server.networkType = AWDMDNSResponderResolveStatsDNSServer_NetworkType_NonCellular;
-    }
-
-    *outServer = server;
-    server = nil;
-    err = mStatus_NoError;
-
-exit:
-    [addrBytes release];
-    [server release];
-    return (err);
-}
-
-//===========================================================================================================================
-//  ResolveStatsIPv4AddrSetCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsIPv4AddrSetCreate(ResolveStatsIPv4AddrSet **outSet)
-{
-    mStatus                         err;
-    ResolveStatsIPv4AddrSet *       obj;
-
-    obj = (ResolveStatsIPv4AddrSet *)calloc(1, sizeof(*obj));
-    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
-    *outSet = obj;
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
-//  ResolveStatsIPv4AddrSetFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsIPv4AddrSetFree(ResolveStatsIPv4AddrSet *inSet)
-{
-    free(inSet);
-}
-
-//===========================================================================================================================
-//  ResolveStatsIPv6AddressCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsIPv6AddressCreate(uint8_t inServerID, const uint8_t inAddrBytes[16], ResolveStatsIPv6Addr **outAddr)
-{
-    mStatus                     err;
-    ResolveStatsIPv6Addr *      obj;
-
-    obj = (ResolveStatsIPv6Addr *)calloc(1, sizeof(*obj));
-    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
-    obj->serverID = inServerID;
-    memcpy(obj->addrBytes, inAddrBytes, 16);
-
-    *outAddr = obj;
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
-//  ResolveStatsIPv6AddressFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsIPv6AddressFree(ResolveStatsIPv6Addr *inAddr)
-{
-    free(inAddr);
-}
-
-//===========================================================================================================================
-//  ResolveStatsNegAAAASetCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsNegAAAASetCreate(ResolveStatsNegAAAASet **outSet)
-{
-    mStatus                         err;
-    ResolveStatsNegAAAASet *        obj;
-
-    obj = (ResolveStatsNegAAAASet *)calloc(1, sizeof(*obj));
-    require_action_quiet(obj, exit, err = mStatus_NoMemoryErr);
-
-    *outSet = obj;
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
-//  ResolveStatsNegAAAASetFree
-//===========================================================================================================================
-
-mDNSlocal void ResolveStatsNegAAAASetFree(ResolveStatsNegAAAASet *inSet)
-{
-    free(inSet);
-}
-
-//===========================================================================================================================
-//  ResolveStatsGetServerID
-//===========================================================================================================================
-
-mDNSlocal mStatus ResolveStatsGetServerID(const mDNSAddr *inServerAddr, mDNSBool inForCell, uint8_t *outServerID)
-{
-    mStatus                         err;
-    ResolveStatsDNSServer **        p;
-    ResolveStatsDNSServer *         server;
-
-    require_action_quiet((inServerAddr->type == mDNSAddrType_IPv4) || (inServerAddr->type == mDNSAddrType_IPv6), exit, err = mStatus_Invalid);
-
-    for (p = &gResolveStatsServerList; (server = *p) != NULL; p = &server->next)
-    {
-        if ((inForCell && server->isForCell) || (!inForCell && !server->isForCell))
-        {
-            if (inServerAddr->type == mDNSAddrType_IPv4)
-            {
-                if (!server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v4.b, 4) == 0)) break;
-            }
-            else
-            {
-                if (server->isAddrV6 && (memcmp(server->addrBytes, inServerAddr->ip.v6.b, 16) == 0)) break;
-            }
-        }
-    }
-
-    if (!server)
-    {
-        require_action_quiet(gResolveStatsNextServerID <= UINT8_MAX, exit, err = mStatus_Refused);
-        require_action_quiet(gResolveStatsObjCount < kResolveStatsMaxObjCount, exit, err = mStatus_Refused);
-        err = ResolveStatsDNSServerCreate(inServerAddr, inForCell, &server);
-        require_noerr_quiet(err, exit);
-        gResolveStatsObjCount++;
-
-        server->id   = (uint8_t)gResolveStatsNextServerID++;
-        server->next = gResolveStatsServerList;
-        gResolveStatsServerList = server;
-    }
-    else if (gResolveStatsServerList != server)
-    {
-        *p = server->next;
-        server->next = gResolveStatsServerList;
-        gResolveStatsServerList = server;
-    }
-
-    *outServerID = server->id;
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
-//  DNSMessageSizeStatsCreate
-//===========================================================================================================================
-
-mDNSlocal mStatus DNSMessageSizeStatsCreate(DNSMessageSizeStats **outStats)
-{
-    mStatus                     err;
-    DNSMessageSizeStats *       stats;
-
-    stats = (DNSMessageSizeStats *)calloc(1, sizeof(*stats));
-    require_action_quiet(stats, exit, err = mStatus_NoMemoryErr);
-
-    *outStats = stats;
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-//===========================================================================================================================
-//  DNSMessageSizeStatsFree
-//===========================================================================================================================
-
-mDNSlocal void DNSMessageSizeStatsFree(DNSMessageSizeStats *inStats)
-{
-    free(inStats);
-}
-
-//===========================================================================================================================
-//  CreateQueryStatsList
-//===========================================================================================================================
-
-mDNSlocal mStatus CreateQueryStatsList(QueryStats **outList)
-{
-    mStatus                             err;
-    QueryStats **                       p;
-    QueryStats *                        stats;
-    const QueryStatsArgs *              args;
-    const QueryStatsArgs * const        end     = kQueryStatsArgs + countof(kQueryStatsArgs);
-    QueryStats *                        list    = NULL;
-
-    p = &list;
-    for (args = kQueryStatsArgs; args < end; ++args)
-    {
-        err = QueryStatsCreate(args->domainStr, args->altDomainStr, args->test, args->terminal, &stats);
-        require_noerr_quiet(err, exit);
-
-        *p = stats;
-        p = &stats->next;
-    }
-
-    *outList = list;
-    list = NULL;
-    err = mStatus_NoError;
-
-exit:
-    QueryStatsFreeList(list);
-    return (err);
-}
-
-//===========================================================================================================================
-//  CreateResolveStatsList
-//===========================================================================================================================
-
-mDNSlocal mStatus CreateResolveStatsList(ResolveStatsDomain **outList)
-{
-    mStatus                     err;
-    unsigned int                i;
-    ResolveStatsDomain *        domain;
-    ResolveStatsDomain **       p;
-    ResolveStatsDomain *        list = NULL;
-
-    p = &list;
-    for (i = 0; i < (unsigned int)countof(kResolveStatsDomains); ++i)
-    {
-        err = ResolveStatsDomainCreate(kResolveStatsDomains[i], &domain);
-        require_noerr_quiet(err, exit);
-
-        *p = domain;
-        p = &domain->next;
-    }
-
-    *outList = list;
-    list = NULL;
-    err = mStatus_NoError;
-
-exit:
-    FreeResolveStatsList(list);
-    return (err);
-}
-
-//===========================================================================================================================
-//  FreeResolveStatsList
-//===========================================================================================================================
-
-mDNSlocal void FreeResolveStatsList(ResolveStatsDomain *inList)
-{
-    ResolveStatsDomain *        domain;
-
-    while ((domain = inList) != NULL)
-    {
-        inList = domain->next;
-        ResolveStatsDomainFree(domain);
-    }
-}
-
-//===========================================================================================================================
-//  FreeResolveStatsServerList
-//===========================================================================================================================
-
-mDNSlocal void FreeResolveStatsServerList(ResolveStatsDNSServer *inList)
-{
-    ResolveStatsDNSServer *     server;
-
-    while ((server = inList) != NULL)
-    {
-        inList = server->next;
-        ResolveStatsDNSServerFree(server);
-    }
-}
-
-//===========================================================================================================================
-//  SubmitAWDMetric
-//===========================================================================================================================
-
-mDNSlocal mStatus SubmitAWDMetric(UInt32 inMetricID)
-{
-    mStatus     err;
-
-    switch (inMetricID)
-    {
-        case AWDMetricId_MDNSResponder_DNSStatistics:
-            err = SubmitAWDMetricQueryStats();
-            break;
-
-        case AWDMetricId_MDNSResponder_ResolveStats:
-            err = SubmitAWDMetricResolveStats();
-            break;
-
-        case AWDMetricId_MDNSResponder_ServicesStats:
-            [AWDMetricManagerSoft postMetricWithId:AWDMetricId_MDNSResponder_ServicesStats unsignedIntegerValue:max_num_regservices];
-            KQueueLock();
-            // reset the no of max services since we want to collect the max no of services registered per AWD submission period
-            max_num_regservices = curr_num_regservices;
-            KQueueUnlock("SubmitAWDSimpleMetricServiceStats");
-            err = mStatus_NoError;
-            break;
-
-        case AWDMetricId_MDNSResponder_DNSMessageSizeStats:
-            err = SubmitAWDMetricDNSMessageSizeStats();
-            break;
-
-        default:
-            err = mStatus_UnsupportedErr;
-            break;
-    }
-
-    if (err) LogMsg("SubmitAWDMetric for metric ID 0x%08X failed with error %d", inMetricID, err);
-    return (err);
-}
-
-//===========================================================================================================================
-//  SubmitAWDMetricQueryStats
-//===========================================================================================================================
-
-mDNSlocal mStatus   AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats);
-mDNSlocal mStatus   AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell);
-
-mDNSlocal mStatus SubmitAWDMetricQueryStats(void)
-{
-    mStatus                             err;
-    BOOL                                success;
-    QueryStats *                        stats;
-    QueryStats *                        statsList;
-    QueryStats *                        newStatsList;
-    AWDMetricContainer *                container   = nil;
-    AWDMDNSResponderDNSStatistics *     metric      = nil;
-
-    newStatsList = NULL;
-    CreateQueryStatsList(&newStatsList);
-
-    KQueueLock();
-    statsList       = gQueryStatsList;
-    gQueryStatsList = newStatsList;
-    KQueueUnlock("SubmitAWDMetricQueryStats");
-
-    container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_DNSStatistics];
-    require_action_quiet(container, exit, err = mStatus_UnknownErr);
-
-    metric = [[AWDMDNSResponderDNSStatisticsSoft alloc] init];
-    require_action_quiet(metric, exit, err = mStatus_UnknownErr);
-
-    while ((stats = statsList) != NULL)
-    {
-        err = AddQueryStats(metric, stats);
-        require_noerr_quiet(err, exit);
-
-        statsList = stats->next;
-        QueryStatsFree(stats);
-    }
-
-    container.metric = metric;
-    success = [gAWDServerConnection submitMetric:container];
-    LogMsg("SubmitAWDMetricQueryStats: metric submission %s.", success ? "succeeded" : "failed");
-    err = success ? mStatus_NoError : mStatus_UnknownErr;
-
-exit:
-    [metric release];
-    [container release];
-    QueryStatsFreeList(statsList);
-    return (err);
-}
-
-mDNSlocal mStatus AddQueryStats(AWDMDNSResponderDNSStatistics *inMetric, const QueryStats *inStats)
-{
-    mStatus     err;
-
-    if (inStats->nonCellular)
-    {
-        err = AddDNSHistSet(inMetric, inStats->nonCellular, QueryStatsGetDomainString(inStats), mDNSfalse);
-        require_noerr_quiet(err, exit);
-    }
-    if (inStats->cellular)
-    {
-        err = AddDNSHistSet(inMetric, inStats->cellular, QueryStatsGetDomainString(inStats), mDNStrue);
-        require_noerr_quiet(err, exit);
-    }
-    err = mStatus_NoError;
-
-exit:
-    return (err);
-}
-
-mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
-{
-    mStatus                 err;
-    AWDDNSDomainStats *     awdStats;
-
-    if (inSet->histA)
-    {
-        err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
-        require_noerr_quiet(err, exit);
+        err = CreateAWDDNSDomainStats(inSet->histA, inDomain, inForCell, AWDDNSDomainStats_RecordType_A, &awdStats);
+        require_noerr_quiet(err, exit);
 
         [inMetric addStats:awdStats];
-        [awdStats release];
     }
     if (inSet->histAAAA)
     {
@@ -1917,7 +930,6 @@ mDNSlocal mStatus AddDNSHistSet(AWDMDNSResponderDNSStatistics *inMetric, DNSHist
         require_noerr_quiet(err, exit);
 
         [inMetric addStats:awdStats];
-        [awdStats release];
     }
     err = mStatus_NoError;
 
@@ -1925,79 +937,6 @@ exit:
     return (err);
 }
 
-//===========================================================================================================================
-//  SubmitAWDMetricResolveStats
-//===========================================================================================================================
-
-mDNSlocal mStatus SubmitAWDMetricResolveStats(void)
-{
-    mStatus                             err;
-    ResolveStatsDomain *                newResolveStatsList;
-    ResolveStatsDomain *                domainList  = NULL;
-    ResolveStatsDNSServer *             serverList  = NULL;
-    AWDMetricContainer *                container   = nil;
-    AWDMDNSResponderResolveStats *      metric      = nil;
-    ResolveStatsDNSServer *             server;
-    ResolveStatsDomain *                domain;
-    BOOL                                success;
-
-    err = CreateResolveStatsList(&newResolveStatsList);
-    require_noerr_quiet(err, exit);
-
-    KQueueLock();
-    domainList = gResolveStatsList;
-    serverList = gResolveStatsServerList;
-    gResolveStatsList           = newResolveStatsList;
-    gResolveStatsServerList     = NULL;
-    gResolveStatsNextServerID   = 0;
-    gResolveStatsObjCount       = 0;
-    KQueueUnlock("SubmitAWDMetricResolveStats");
-
-    container = [gAWDServerConnection newMetricContainerWithIdentifier:AWDMetricId_MDNSResponder_ResolveStats];
-    require_action_quiet(container, exit, err = mStatus_UnknownErr);
-
-    metric = [[AWDMDNSResponderResolveStatsSoft alloc] init];
-    require_action_quiet(metric, exit, err = mStatus_UnknownErr);
-
-    while ((server = serverList) != NULL)
-    {
-        AWDMDNSResponderResolveStatsDNSServer *     awdServer;
-
-        serverList = server->next;
-        err = ResolveStatsDNSServerCreateAWDVersion(server, &awdServer);
-        ResolveStatsDNSServerFree(server);
-        require_noerr_quiet(err, exit);
-
-        [metric addServer:awdServer];
-        [awdServer release];
-    }
-
-    while ((domain = domainList) != NULL)
-    {
-        AWDMDNSResponderResolveStatsDomain *        awdDomain;
-
-        domainList = domain->next;
-        err = ResolveStatsDomainCreateAWDVersion(domain, &awdDomain);
-        ResolveStatsDomainFree(domain);
-        require_noerr_quiet(err, exit);
-
-        [metric addDomain:awdDomain];
-        [awdDomain release];
-    }
-
-    container.metric = metric;
-    success = [gAWDServerConnection submitMetric:container];
-    LogMsg("SubmitAWDMetricResolveStats: metric submission %s.", success ? "succeeded" : "failed");
-    err = success ? mStatus_NoError : mStatus_UnknownErr;
-
-exit:
-    [metric release];
-    [container release];
-    FreeResolveStatsList(domainList);
-    FreeResolveStatsServerList(serverList);
-    return (err);
-}
-
 //===========================================================================================================================
 //  SubmitAWDMetricDNSMessageSizeStats
 //===========================================================================================================================
@@ -2032,12 +971,12 @@ mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void)
 
         // Set query size counts.
 
-        binCount = CopyHistogramBins(bins, stats->querySizeBins, kQuerySizeBinCount);
+        binCount = CopyBins32(bins, stats->querySizeBins, kQuerySizeBinCount);
         [metric setQuerySizeCounts:bins count:(NSUInteger)binCount];
 
         // Set response size counts.
 
-        binCount = CopyHistogramBins(bins, stats->responseSizeBins, kResponseSizeBinCount);
+        binCount = CopyBins32(bins, stats->responseSizeBins, kResponseSizeBinCount);
         [metric setResponseSizeCounts:bins count:(NSUInteger)binCount];
     }
 
@@ -2047,8 +986,6 @@ mDNSlocal mStatus SubmitAWDMetricDNSMessageSizeStats(void)
     err = success ? mStatus_NoError : mStatus_UnknownErr;
 
 exit:
-    [metric release];
-    [container release];
     if (stats) DNSMessageSizeStatsFree(stats);
     return (err);
 }
@@ -2066,6 +1003,7 @@ mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain,
     uint32_t                sendCountBins[kQueryStatsSendCountBinCount];
     uint32_t                latencyBins[kQueryStatsLatencyBinCount];
     uint32_t                expiredAnswerBins[kQueryStatsExpiredAnswerStateCount];
+    uint32_t                dnsOverTCPBins[kQueryStatsDNSOverTCPStateCount];
 
     awdStats = [[AWDDNSDomainStatsSoft alloc] init];
     require_action_quiet(awdStats, exit, err = mStatus_UnknownErr);
@@ -2079,7 +1017,7 @@ mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain,
 
     // Positively answered query send counts
 
-    binCount = CopyHistogramBins(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
+    binCount = CopyBins16(sendCountBins, inHist->answeredQuerySendCountBins, kQueryStatsSendCountBinCount);
     [awdStats setAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
 
     // binCount > 1 means that at least one of the non-zero send count bins had a non-zero count, i.e., at least one query
@@ -2087,67 +1025,69 @@ mDNSlocal mStatus CreateAWDDNSDomainStats(DNSHist *inHist, const char *inDomain,
 
     if (binCount > 1)
     {
-        binCount = CopyHistogramBins(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
+        binCount = CopyBins16(latencyBins, inHist->responseLatencyBins, kQueryStatsLatencyBinCount);
         [awdStats setResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
     }
 
     // Negatively answered query send counts
 
-    binCount = CopyHistogramBins(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
+    binCount = CopyBins16(sendCountBins, inHist->negAnsweredQuerySendCountBins, kQueryStatsSendCountBinCount);
     [awdStats setNegAnsweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
 
     if (binCount > 1)
     {
-        binCount = CopyHistogramBins(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
+        binCount = CopyBins16(latencyBins, inHist->negResponseLatencyBins, kQueryStatsLatencyBinCount);
         [awdStats setNegResponseLatencyMs:latencyBins count:(NSUInteger)binCount];
     }
 
     // Unanswered query send counts
 
-    binCount = CopyHistogramBins(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
+    binCount = CopyBins16(sendCountBins, inHist->unansweredQuerySendCountBins, kQueryStatsSendCountBinCount);
     [awdStats setUnansweredQuerySendCounts:sendCountBins count:(NSUInteger)binCount];
 
     if (binCount > 1)
     {
-        binCount = CopyHistogramBins(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
+        binCount = CopyBins16(latencyBins, inHist->unansweredQueryDurationBins, kQueryStatsLatencyBinCount);
         [awdStats setUnansweredQueryDurationMs:latencyBins count:(NSUInteger)binCount];
     }
     
     // Expired answers states
     
-    binCount = CopyHistogramBins(expiredAnswerBins, inHist->expiredAnswerStateBins, kQueryStatsExpiredAnswerStateCount);
+    binCount = CopyBins32(expiredAnswerBins, inHist->expiredAnswerStateBins, kQueryStatsExpiredAnswerStateCount);
     [awdStats setExpiredAnswerStates:expiredAnswerBins count:(NSUInteger)binCount];
 
-    *outStats = awdStats;
-    awdStats = nil;
+    // DNS Over TCP states
+
+    binCount = CopyBins32(dnsOverTCPBins, inHist->dnsOverTCPStateBins, kQueryStatsDNSOverTCPStateCount);
+    [awdStats setDnsOverTCPStates:dnsOverTCPBins count:(NSUInteger)binCount];
+
+   *outStats = awdStats;
     err = mStatus_NoError;
 
 exit:
-    [domain release];
-    [awdStats release];
     return (err);
 }
 
 //===========================================================================================================================
-//  LogDNSHistSet
+//  LogDNSHistSetToFD
 //===========================================================================================================================
 
-mDNSlocal void LogDNSHistSet(const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
+mDNSlocal void LogDNSHistSetToFD(int fd, const DNSHistSet *inSet, const char *inDomain, mDNSBool inForCell)
 {
-    if (inSet->histA)       LogDNSHist(inSet->histA,    inDomain, inForCell, "A");
-    if (inSet->histAAAA)    LogDNSHist(inSet->histAAAA, inDomain, inForCell, "AAAA");
+    if (inSet->histA)       LogDNSHistToFD(fd, inSet->histA,    inDomain, inForCell, "A");
+    if (inSet->histAAAA)    LogDNSHistToFD(fd, inSet->histAAAA, inDomain, inForCell, "AAAA");
 }
 
 //===========================================================================================================================
-//  LogDNSHist
+//  LogDNSHistToFD
 //===========================================================================================================================
 
 #define Percent(N, D)       (((N) * 100) / (D)), ((((N) * 10000) / (D)) % 100)
 #define PercentFmt          "%3u.%02u"
-#define LogStat(LABEL, COUNT, ACCUMULATOR, TOTAL) \
-    LogMsgNoIdent("%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
+#define LogStatToFD(FILE_DESCRIPTOR, LABEL, COUNT, ACCUMULATOR, TOTAL) \
+    LogToFD((FILE_DESCRIPTOR), "%s %5u " PercentFmt " " PercentFmt, (LABEL), (COUNT), Percent(COUNT, TOTAL), Percent(ACCUMULATOR, TOTAL))
 
-mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
+mDNSlocal void LogDNSHistToFD(int fd, const DNSHist *inHist, const char *inDomain, mDNSBool inForCell, const char *inType)
 {
     unsigned int        totalAnswered;
     unsigned int        totalNegAnswered;
@@ -2172,42 +1112,46 @@ mDNSlocal void LogDNSHist(const DNSHist *inHist, const char *inDomain, mDNSBool
         totalUnanswered += inHist->unansweredQuerySendCountBins[i];
     }
 
-    LogMsgNoIdent("Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
-    LogMsgNoIdent("Answered questions            %4u", totalAnswered);
-    LogMsgNoIdent("Negatively answered questions %4u", totalNegAnswered);
-    LogMsgNoIdent("Unanswered questions          %4u", totalUnanswered);
-    LogMsgNoIdent("Expired - no cached answer    %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_Allowed]);
-    LogMsgNoIdent("Expired - answered from cache %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_AnsweredWithExpired]);
-    LogMsgNoIdent("Expired - cache changed       %4u", inHist->expiredAnswerStateBins[ExpiredAnswer_ExpiredAnswerChanged]);
-    LogMsgNoIdent("-- Query send counts ---------");
-    LogDNSHistSendCounts(inHist->answeredQuerySendCountBins);
-    LogMsgNoIdent("-- Query send counts (NAQs) --");
-    LogDNSHistSendCounts(inHist->negAnsweredQuerySendCountBins);
+    LogToFD(fd, "Domain: %s (%s, %s)", inDomain, inForCell ? "C" : "NC", inType);
+    LogToFD(fd, "Answered questions            %10u", totalAnswered);
+    LogToFD(fd, "Negatively answered questions %10u", totalNegAnswered);
+    LogToFD(fd, "Unanswered questions          %10u", totalUnanswered);
+    LogToFD(fd, "Expired - no cached answer    %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_Allowed]);
+    LogToFD(fd, "Expired - answered from cache %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_AnsweredWithCache]);
+    LogToFD(fd, "Expired - answered expired    %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_AnsweredWithExpired]);
+    LogToFD(fd, "Expired - cache changed       %10u", inHist->expiredAnswerStateBins[ExpiredAnswer_ExpiredAnswerChanged]);
+    LogToFD(fd, "DNSoTCP - truncated           %10u", inHist->dnsOverTCPStateBins[DNSOverTCP_Truncated]);
+    LogToFD(fd, "DNSoTCP - suspicious          %10u", inHist->dnsOverTCPStateBins[DNSOverTCP_Suspicious]);
+    LogToFD(fd, "DNSoTCP - suspicious defense  %10u", inHist->dnsOverTCPStateBins[DNSOverTCP_SuspiciousDefense]);
+    LogToFD(fd, "-- Query send counts ---------");
+    LogDNSHistSendCountsToFD(fd, inHist->answeredQuerySendCountBins);
+    LogToFD(fd, "-- Query send counts (NAQs) --");
+    LogDNSHistSendCountsToFD(fd, inHist->negAnsweredQuerySendCountBins);
 
     if (totalAnswered > inHist->answeredQuerySendCountBins[0])
     {
-        LogMsgNoIdent("--- Response times -----------");
-        LogDNSHistLatencies(inHist->responseLatencyBins);
+        LogToFD(fd, "--- Response times -----------");
+        LogDNSHistLatenciesToFD(fd, inHist->responseLatencyBins);
     }
 
     if (totalNegAnswered > inHist->negAnsweredQuerySendCountBins[0])
     {
-        LogMsgNoIdent("--- Response times (NAQs) ----");
-        LogDNSHistLatencies(inHist->negResponseLatencyBins);
+        LogToFD(fd, "--- Response times (NAQs) ----");
+        LogDNSHistLatenciesToFD(fd, inHist->negResponseLatencyBins);
     }
 
     if (totalUnanswered > 0)
     {
-        LogMsgNoIdent("--- Unanswered query times ---");
-        LogDNSHistLatencies(inHist->unansweredQueryDurationBins);
+        LogToFD(fd, "--- Unanswered query times ---");
+        LogDNSHistLatenciesToFD(fd, inHist->unansweredQueryDurationBins);
     }
 }
 
 //===========================================================================================================================
-//  LogDNSHistSendCounts
+//  LogDNSHistSendCountsToFD
 //===========================================================================================================================
 
-mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
+mDNSlocal void LogDNSHistSendCountsToFD(int fd, const uint16_t inSendCountBins[kQueryStatsSendCountBinCount])
 {
     uint32_t        total;
     char            label[16];
@@ -2234,21 +1178,22 @@ mDNSlocal void LogDNSHistSendCounts(const uint16_t inSendCountBins[kQueryStatsSe
             {
                 snprintf(label, sizeof(label), "%2d+", i);
             }
-            LogStat(label, inSendCountBins[i], accumulator, total);
+            LogStatToFD(fd, label, inSendCountBins[i], accumulator, total);
             if (accumulator == total) break;
         }
     }
     else
     {
-        LogMsgNoIdent("No data.");
+        LogToFD(fd, "No data.");
     }
 }
 
 //===========================================================================================================================
-//  LogDNSHistLatencies
+//  LogDNSHistLatenciesToFD
 //===========================================================================================================================
 
-mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
+mDNSlocal void LogDNSHistLatenciesToFD(int fd,
+                                         const uint16_t inLatencyBins[kQueryStatsLatencyBinCount])
 {
     uint32_t        total;
     int             i;
@@ -2275,21 +1220,21 @@ mDNSlocal void LogDNSHistLatencies(const uint16_t inLatencyBins[kQueryStatsLaten
             {
                 snprintf(label, sizeof(label), "<     ∞ ms");
             }
-            LogStat(label, inLatencyBins[i], accumulator, total);
+            LogStatToFD(fd, label, inLatencyBins[i], accumulator, total);
             if (accumulator == total) break;
         }
     }
     else
     {
-        LogMsgNoIdent("No data.");
+        LogToFD(fd, "No data.");
     }
 }
 
 //===========================================================================================================================
-//  LogDNSMessageSizeStats
+//  LogDNSMessageSizeStatsToFD
 //===========================================================================================================================
 
-mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount, unsigned int inBinWidth)
+mDNSlocal void LogDNSMessageSizeStatsToFD(int fd, const uint32_t *inBins, size_t inBinCount, unsigned int inBinWidth)
 {
     size_t          i;
     uint32_t        total;
@@ -2321,37 +1266,14 @@ mDNSlocal void LogDNSMessageSizeStats(const uint16_t *inBins, size_t inBinCount,
             {
                 snprintf(label, sizeof(label), "%3u+     ", lower);
             }
-            LogStat(label, inBins[i], accumulator, total);
+            LogStatToFD(fd, label, inBins[i], accumulator, total);
             if (accumulator == total) break;
         }
     }
     else
     {
-        LogMsgNoIdent("No data.");
+        LogToFD(fd, "No data.");
     }
 }
 
-//===========================================================================================================================
-//  CopyHistogramBins
-//
-//  Note: The return value is the size (in number of elements) of the smallest contiguous sub-array that contains the first
-//  bin and all bins with non-zero values.
-//===========================================================================================================================
-
-mDNSlocal size_t CopyHistogramBins(uint32_t *inDstBins, uint16_t *inSrcBins, size_t inBinCount)
-{
-    size_t      i;
-    size_t      minCount;
-
-    if (inBinCount == 0) return (0);
-
-    minCount = 1;
-    for (i = 0; i < inBinCount; ++i)
-    {
-        inDstBins[i] = inSrcBins[i];
-        if (inDstBins[i] > 0) minCount = i + 1;
-    }
-
-    return (minCount);
-}
-#endif // TARGET_OS_IOS
+#endif  // MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
diff --git a/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/designable.nib b/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/designable.nib
deleted file mode 100644 (file)
index 187ac38..0000000
+++ /dev/null
@@ -1,821 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="12118" systemVersion="17A210a" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
-    <dependencies>
-        <deployment identifier="macosx"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="12118"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <objects>
-        <customObject id="-2" userLabel="File's Owner" customClass="DNSServiceDiscoveryPref">
-            <connections>
-                <outlet property="_initialKeyView" destination="107" id="235"/>
-                <outlet property="_lastKeyView" destination="107" id="183"/>
-                <outlet property="_window" destination="12" id="142"/>
-                <outlet property="addBrowseDomainButton" destination="381" id="384"/>
-                <outlet property="addBrowseDomainManualWindow" destination="NFb-eI-atL" id="0AN-Mr-e84"/>
-                <outlet property="addBrowseDomainWindow" destination="333" id="363"/>
-                <outlet property="applyButton" destination="208" id="238"/>
-                <outlet property="bonjourBrowserView" destination="200327" id="200328"/>
-                <outlet property="browseCancelButton" destination="341" id="375"/>
-                <outlet property="browseDomainList" destination="327" id="349"/>
-                <outlet property="browseDomainTextField" destination="W2d-Us-Cpm" id="kOZ-wG-OPp"/>
-                <outlet property="browseOKButton" destination="340" id="376"/>
-                <outlet property="comboAuthButton" destination="137" id="201"/>
-                <outlet property="hostName" destination="107" id="224"/>
-                <outlet property="hostNameSharedSecretButton" destination="263" id="270"/>
-                <outlet property="regDomainTextField" destination="OEh-fL-Ol6" id="Dv0-aj-gah"/>
-                <outlet property="regDomainView" destination="Reu-VC-MNz" id="4I2-zS-sdq"/>
-                <outlet property="registrationBrowserView" destination="agb-WV-smo" id="j7U-ZK-LIb"/>
-                <outlet property="registrationSelectButton" destination="KqE-pc-8z0" id="CJS-ml-2CA"/>
-                <outlet property="registrationSharedSecretButton" destination="267" id="268"/>
-                <outlet property="removeBrowseDomainButton" destination="383" id="385"/>
-                <outlet property="revertButton" destination="290" id="292"/>
-                <outlet property="secretCancelButton" destination="341" id="373"/>
-                <outlet property="secretOKButton" destination="260" id="377"/>
-                <outlet property="selectRegistrationDomainManualWindow" destination="he2-0K-CWy" id="eXD-7o-XQU"/>
-                <outlet property="selectRegistrationDomainWindow" destination="ail-If-2Xp" id="34V-c7-D3b"/>
-                <outlet property="sharedSecretName" destination="256" id="275"/>
-                <outlet property="sharedSecretValue" destination="257" id="276"/>
-                <outlet property="sharedSecretWindow" destination="255" id="274"/>
-                <outlet property="statusImageView" destination="320" id="321"/>
-                <outlet property="tabView" destination="100" id="380"/>
-                <outlet property="wideAreaCheckBox" destination="179" id="240"/>
-            </connections>
-        </customObject>
-        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
-        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
-        <window title="Bonjour" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" deferred="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="12" userLabel="PrefPane">
-            <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
-            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
-            <rect key="contentRect" x="51" y="335" width="596" height="343"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
-            <value key="minSize" type="size" width="213.66399999999999" height="10"/>
-            <view key="contentView" id="6">
-                <rect key="frame" x="0.0" y="0.0" width="596" height="343"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <tabView translatesAutoresizingMaskIntoConstraints="NO" id="100">
-                        <rect key="frame" x="13" y="52" width="570" height="285"/>
-                        <font key="font" metaFont="system"/>
-                        <tabViewItems>
-                            <tabViewItem label="Hostname" identifier="1" id="102">
-                                <view key="view" id="101">
-                                    <rect key="frame" x="10" y="33" width="550" height="239"/>
-                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                                    <subviews>
-                                        <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="107">
-                                            <rect key="frame" x="119" y="155" width="383" height="22"/>
-                                            <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" placeholderString="steve.example.com" drawsBackground="YES" id="100107">
-                                                <font key="font" metaFont="system"/>
-                                                <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                                                <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                                            </textFieldCell>
-                                            <connections>
-                                                <outlet property="delegate" destination="-2" id="227"/>
-                                            </connections>
-                                        </textField>
-                                        <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="108">
-                                            <rect key="frame" x="43" y="158" width="70" height="17"/>
-                                            <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Hostname:" id="100108">
-                                                <font key="font" metaFont="system"/>
-                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                                            </textFieldCell>
-                                        </textField>
-                                        <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="117">
-                                            <rect key="frame" x="18" y="185" width="514" height="34"/>
-                                            <constraints>
-                                                <constraint firstAttribute="width" priority="499" constant="510" id="TMz-kS-KCv"/>
-                                            </constraints>
-                                            <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a hostname for this computer.  Other computers on the Internet will be able to reach your computer using this hostname." id="100117">
-                                                <font key="font" metaFont="systemBold"/>
-                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                                            </textFieldCell>
-                                        </textField>
-                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="263">
-                                            <rect key="frame" x="113" y="119" width="109" height="32"/>
-                                            <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100263">
-                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                                                <font key="font" metaFont="system"/>
-                                            </buttonCell>
-                                            <connections>
-                                                <action selector="changeButtonPressed:" target="-2" id="272"/>
-                                            </connections>
-                                        </button>
-                                        <imageView translatesAutoresizingMaskIntoConstraints="NO" id="320">
-                                            <rect key="frame" x="510" y="156" width="20" height="20"/>
-                                            <constraints>
-                                                <constraint firstAttribute="width" constant="20" id="7Qf-g0-5SV"/>
-                                                <constraint firstAttribute="height" constant="20" id="bfL-QJ-KFw"/>
-                                            </constraints>
-                                            <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageAlignment="left" imageScaling="proportionallyDown" id="100320"/>
-                                        </imageView>
-                                    </subviews>
-                                    <constraints>
-                                        <constraint firstItem="263" firstAttribute="leading" secondItem="107" secondAttribute="leading" id="4Dv-gf-Cjr"/>
-                                        <constraint firstAttribute="trailing" secondItem="117" secondAttribute="trailing" constant="20" symbolic="YES" id="5zc-LQ-OC8"/>
-                                        <constraint firstItem="320" firstAttribute="leading" secondItem="107" secondAttribute="trailing" constant="8" symbolic="YES" id="BIu-YL-Fr2"/>
-                                        <constraint firstItem="263" firstAttribute="top" secondItem="107" secondAttribute="bottom" constant="8" symbolic="YES" id="K1w-WG-3KW"/>
-                                        <constraint firstItem="107" firstAttribute="centerY" secondItem="320" secondAttribute="centerY" id="LlU-Oy-3va"/>
-                                        <constraint firstItem="107" firstAttribute="top" secondItem="117" secondAttribute="bottom" constant="8" symbolic="YES" id="V8c-G1-gsR"/>
-                                        <constraint firstItem="117" firstAttribute="top" secondItem="101" secondAttribute="top" constant="20" symbolic="YES" id="Xnz-bz-ahU"/>
-                                        <constraint firstItem="117" firstAttribute="leading" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="ZIG-S4-cst"/>
-                                        <constraint firstItem="107" firstAttribute="leading" secondItem="108" secondAttribute="trailing" constant="8" symbolic="YES" id="cQG-zv-Ozo"/>
-                                        <constraint firstItem="108" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="foH-DQ-yvJ"/>
-                                        <constraint firstItem="107" firstAttribute="leading" secondItem="101" secondAttribute="leading" priority="499" constant="119" id="qGZ-fm-Wgf"/>
-                                        <constraint firstAttribute="trailing" secondItem="320" secondAttribute="trailing" constant="20" symbolic="YES" id="w2R-Kc-Tj3"/>
-                                        <constraint firstItem="108" firstAttribute="baseline" secondItem="107" secondAttribute="baseline" id="xcr-32-mbs"/>
-                                    </constraints>
-                                </view>
-                            </tabViewItem>
-                            <tabViewItem label="Registration" identifier="2" id="98">
-                                <view key="view" id="99">
-                                    <rect key="frame" x="10" y="33" width="550" height="239"/>
-                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                                    <subviews>
-                                        <button translatesAutoresizingMaskIntoConstraints="NO" id="179">
-                                            <rect key="frame" x="41" y="157" width="72" height="18"/>
-                                            <buttonCell key="cell" type="check" title="Domain:" bezelStyle="regularSquare" imagePosition="left" alignment="right" inset="2" id="100179">
-                                                <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
-                                                <font key="font" metaFont="system"/>
-                                            </buttonCell>
-                                            <connections>
-                                                <action selector="wideAreaCheckBoxChanged:" target="-2" id="317"/>
-                                            </connections>
-                                        </button>
-                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="267">
-                                            <rect key="frame" x="222" y="119" width="109" height="32"/>
-                                            <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100267">
-                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                                                <font key="font" metaFont="system"/>
-                                            </buttonCell>
-                                            <connections>
-                                                <action selector="changeButtonPressed:" target="-2" id="273"/>
-                                            </connections>
-                                        </button>
-                                        <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="348">
-                                            <rect key="frame" x="18" y="185" width="514" height="34"/>
-                                            <constraints>
-                                                <constraint firstAttribute="width" priority="499" constant="510" id="lUQ-CZ-AzC"/>
-                                            </constraints>
-                                            <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Check the box and select a registration domain to enable Bonjour advertising beyond the local subnet." id="100348">
-                                                <font key="font" metaFont="systemBold"/>
-                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                                            </textFieldCell>
-                                        </textField>
-                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KqE-pc-8z0">
-                                            <rect key="frame" x="113" y="119" width="109" height="32"/>
-                                            <buttonCell key="cell" type="push" title="Select…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="TjV-QO-BW7">
-                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                                                <font key="font" metaFont="system"/>
-                                            </buttonCell>
-                                            <connections>
-                                                <action selector="selectWideAreaDomainButtonPressed:" target="-2" id="d4S-la-iyw"/>
-                                            </connections>
-                                        </button>
-                                        <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cxI-8W-6HI">
-                                            <rect key="frame" x="119" y="155" width="411" height="22"/>
-                                            <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="Oao-6x-0X9">
-                                                <font key="font" metaFont="system"/>
-                                                <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                                                <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                                            </textFieldCell>
-                                        </textField>
-                                        <customView translatesAutoresizingMaskIntoConstraints="NO" id="Reu-VC-MNz" customClass="CNBonjourDomainView">
-                                            <rect key="frame" x="119" y="155" width="411" height="22"/>
-                                            <constraints>
-                                                <constraint firstAttribute="height" constant="22" id="l7c-m9-GcE"/>
-                                            </constraints>
-                                        </customView>
-                                    </subviews>
-                                    <constraints>
-                                        <constraint firstItem="267" firstAttribute="leading" secondItem="KqE-pc-8z0" secondAttribute="trailing" constant="12" symbolic="YES" id="2kZ-P9-l60"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="centerY" secondItem="cxI-8W-6HI" secondAttribute="centerY" id="984-4H-aIz"/>
-                                        <constraint firstItem="179" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="D3d-wd-QYX"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="top" secondItem="348" secondAttribute="bottom" constant="8" symbolic="YES" id="GcL-zf-7HQ"/>
-                                        <constraint firstItem="348" firstAttribute="top" secondItem="99" secondAttribute="top" constant="20" symbolic="YES" id="HDQ-fd-PwR"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="height" secondItem="cxI-8W-6HI" secondAttribute="height" id="HUo-M5-tyi"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="width" secondItem="cxI-8W-6HI" secondAttribute="width" id="JML-71-xrY"/>
-                                        <constraint firstItem="cxI-8W-6HI" firstAttribute="baseline" secondItem="179" secondAttribute="baseline" id="NX1-5X-UZI"/>
-                                        <constraint firstItem="348" firstAttribute="leading" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="P0u-7u-LJv"/>
-                                        <constraint firstItem="KqE-pc-8z0" firstAttribute="leading" secondItem="cxI-8W-6HI" secondAttribute="leading" id="RDS-Bc-KYd"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="d8L-Kb-W49"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="centerX" secondItem="cxI-8W-6HI" secondAttribute="centerX" id="dfu-qB-Ezj"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="179" secondAttribute="trailing" constant="8" symbolic="YES" id="rUC-3C-r32"/>
-                                        <constraint firstItem="KqE-pc-8z0" firstAttribute="top" secondItem="cxI-8W-6HI" secondAttribute="bottom" constant="8" symbolic="YES" id="skb-cf-d2E"/>
-                                        <constraint firstAttribute="trailing" secondItem="Reu-VC-MNz" secondAttribute="trailing" constant="20" symbolic="YES" id="ta5-1S-y3v"/>
-                                        <constraint firstAttribute="trailing" secondItem="348" secondAttribute="trailing" constant="20" symbolic="YES" id="tr3-Ed-I8w"/>
-                                        <constraint firstItem="267" firstAttribute="baseline" secondItem="KqE-pc-8z0" secondAttribute="baseline" id="vt0-3i-y05"/>
-                                        <constraint firstItem="267" firstAttribute="width" secondItem="KqE-pc-8z0" secondAttribute="width" id="vxX-jt-NDx"/>
-                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="99" secondAttribute="leading" priority="499" constant="119" id="xdT-xB-bam"/>
-                                    </constraints>
-                                </view>
-                            </tabViewItem>
-                            <tabViewItem label="Browsing" identifier="" id="322">
-                                <view key="view" id="323">
-                                    <rect key="frame" x="10" y="33" width="550" height="239"/>
-                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                                    <subviews>
-                                        <scrollView horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="326">
-                                            <rect key="frame" x="20" y="82" width="510" height="112"/>
-                                            <clipView key="contentView" id="r8V-oO-qTS">
-                                                <rect key="frame" x="1" y="1" width="508" height="110"/>
-                                                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                                                <subviews>
-                                                    <tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="22" id="327">
-                                                        <rect key="frame" x="0.0" y="0.0" width="508" height="110"/>
-                                                        <autoresizingMask key="autoresizingMask"/>
-                                                        <size key="intercellSpacing" width="3" height="2"/>
-                                                        <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
-                                                        <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
-                                                        <tableColumns>
-                                                            <tableColumn identifier="Enabled" width="35" minWidth="30" maxWidth="1000" id="328">
-                                                                <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
-                                                                    <font key="font" metaFont="smallSystem"/>
-                                                                    <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
-                                                                    <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
-                                                                </tableHeaderCell>
-                                                                <buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="above" alignment="center" inset="2" id="358">
-                                                                    <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
-                                                                    <font key="font" metaFont="cellTitle"/>
-                                                                    <connections>
-                                                                        <action selector="enableBrowseDomainClicked:" target="-2" id="360"/>
-                                                                    </connections>
-                                                                </buttonCell>
-                                                            </tableColumn>
-                                                            <tableColumn identifier="Domain" editable="NO" width="451.9541015625" minWidth="49.3466796875" maxWidth="1000" id="329">
-                                                                <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Domain">
-                                                                    <font key="font" metaFont="smallSystem"/>
-                                                                    <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
-                                                                    <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
-                                                                </tableHeaderCell>
-                                                                <customCell key="dataCell" alignment="left" id="LhH-Yh-n33" customClass="CNBonjourDomainCell"/>
-                                                            </tableColumn>
-                                                        </tableColumns>
-                                                        <connections>
-                                                            <outlet property="dataSource" destination="-2" id="350"/>
-                                                            <outlet property="delegate" destination="-2" id="351"/>
-                                                        </connections>
-                                                    </tableView>
-                                                </subviews>
-                                            </clipView>
-                                            <constraints>
-                                                <constraint firstAttribute="height" constant="112" id="Pf1-34-QXp"/>
-                                            </constraints>
-                                            <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="100326">
-                                                <rect key="frame" x="-100" y="-100" width="493" height="15"/>
-                                                <autoresizingMask key="autoresizingMask"/>
-                                            </scroller>
-                                            <scroller key="verticalScroller" verticalHuggingPriority="750" horizontal="NO" id="200326">
-                                                <rect key="frame" x="493" y="1" width="16" height="110"/>
-                                                <autoresizingMask key="autoresizingMask"/>
-                                            </scroller>
-                                        </scrollView>
-                                        <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="330">
-                                            <rect key="frame" x="18" y="202" width="514" height="17"/>
-                                            <constraints>
-                                                <constraint firstAttribute="width" priority="499" constant="510" id="xXz-Xx-cVE"/>
-                                            </constraints>
-                                            <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Choose which domains to browse using Wide-Area Bonjour." id="100330">
-                                                <font key="font" metaFont="systemBold"/>
-                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                                            </textFieldCell>
-                                        </textField>
-                                        <button toolTip="Click to define shortcuts within applications." verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="381">
-                                            <rect key="frame" x="20" y="49" width="24" height="26"/>
-                                            <constraints>
-                                                <constraint firstAttribute="width" constant="24" id="llU-4M-pcI"/>
-                                                <constraint firstAttribute="height" constant="24" id="qD8-y4-ZkW"/>
-                                            </constraints>
-                                            <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" id="100381">
-                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                                                <font key="font" metaFont="system"/>
-                                            </buttonCell>
-                                            <connections>
-                                                <action selector="addBrowseDomainClicked:" target="-2" id="386"/>
-                                            </connections>
-                                        </button>
-                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="383">
-                                            <rect key="frame" x="43" y="49" width="24" height="26"/>
-                                            <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" controlSize="small" state="on" borderStyle="border" id="100383">
-                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                                                <font key="font" metaFont="smallSystem"/>
-                                                <string key="keyEquivalent">\7f</string>
-                                            </buttonCell>
-                                            <connections>
-                                                <action selector="removeBrowseDomainClicked:" target="-2" id="387"/>
-                                            </connections>
-                                        </button>
-                                    </subviews>
-                                    <constraints>
-                                        <constraint firstItem="326" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="BHw-zP-zzH"/>
-                                        <constraint firstItem="381" firstAttribute="centerY" secondItem="383" secondAttribute="centerY" id="Cae-WW-gYH"/>
-                                        <constraint firstItem="326" firstAttribute="leading" secondItem="381" secondAttribute="leading" id="GCR-nb-Kbp"/>
-                                        <constraint firstItem="381" firstAttribute="height" secondItem="383" secondAttribute="height" id="GYW-Vr-6c8"/>
-                                        <constraint firstAttribute="trailing" secondItem="326" secondAttribute="trailing" constant="20" symbolic="YES" id="HGK-Ej-oKA"/>
-                                        <constraint firstItem="383" firstAttribute="leading" secondItem="381" secondAttribute="trailing" constant="-1" id="KYa-XM-Qrh"/>
-                                        <constraint firstAttribute="trailing" secondItem="330" secondAttribute="trailing" constant="20" symbolic="YES" id="Lkk-cy-gcf"/>
-                                        <constraint firstItem="326" firstAttribute="top" secondItem="330" secondAttribute="bottom" constant="8" symbolic="YES" id="Pna-sQ-Iom"/>
-                                        <constraint firstItem="381" firstAttribute="top" secondItem="326" secondAttribute="bottom" constant="8" symbolic="YES" id="YmF-BH-VOk"/>
-                                        <constraint firstItem="381" firstAttribute="width" secondItem="383" secondAttribute="width" id="kJf-PK-P0M"/>
-                                        <constraint firstItem="330" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="luC-Nv-ec5"/>
-                                        <constraint firstItem="330" firstAttribute="top" secondItem="323" secondAttribute="top" constant="20" symbolic="YES" id="yVJ-PT-T31"/>
-                                    </constraints>
-                                </view>
-                            </tabViewItem>
-                        </tabViewItems>
-                    </tabView>
-                    <customView translatesAutoresizingMaskIntoConstraints="NO" id="137" customClass="SFAuthorizationView">
-                        <rect key="frame" x="20" y="20" width="356" height="34"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="34" id="T24-JY-FUW"/>
-                            <constraint firstAttribute="width" constant="356" id="hHs-jB-Xz8"/>
-                        </constraints>
-                    </customView>
-                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="208">
-                        <rect key="frame" x="502" y="13" width="80" height="32"/>
-                        <buttonCell key="cell" type="push" title="Apply" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100208">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                        </buttonCell>
-                        <connections>
-                            <action selector="applyClicked:" target="-2" id="209"/>
-                        </connections>
-                    </button>
-                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="290">
-                        <rect key="frame" x="422" y="13" width="80" height="32"/>
-                        <buttonCell key="cell" type="push" title="Revert" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100290">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                        </buttonCell>
-                        <connections>
-                            <action selector="revertClicked:" target="-2" id="293"/>
-                        </connections>
-                    </button>
-                </subviews>
-                <constraints>
-                    <constraint firstAttribute="trailing" secondItem="100" secondAttribute="trailing" constant="20" symbolic="YES" id="DEs-Vk-n3D"/>
-                    <constraint firstItem="208" firstAttribute="width" secondItem="290" secondAttribute="width" id="GMB-MK-qPS"/>
-                    <constraint firstAttribute="bottom" secondItem="137" secondAttribute="bottom" constant="20" symbolic="YES" id="M0C-li-Dr1"/>
-                    <constraint firstItem="100" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="Ozi-Cv-NdV"/>
-                    <constraint firstAttribute="bottom" secondItem="208" secondAttribute="bottom" constant="20" symbolic="YES" id="PGr-uI-dUi"/>
-                    <constraint firstItem="290" firstAttribute="baseline" secondItem="208" secondAttribute="baseline" id="Rcf-kj-OQp"/>
-                    <constraint firstItem="137" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="dWc-kl-h8o"/>
-                    <constraint firstItem="208" firstAttribute="leading" secondItem="290" secondAttribute="trailing" constant="12" symbolic="YES" id="g3l-gL-wIw"/>
-                    <constraint firstItem="137" firstAttribute="top" secondItem="100" secondAttribute="bottom" constant="8" symbolic="YES" id="jDb-sm-pFt"/>
-                    <constraint firstItem="100" firstAttribute="top" secondItem="6" secondAttribute="top" constant="12" symbolic="YES" id="nWn-mH-iEl"/>
-                    <constraint firstAttribute="trailing" secondItem="208" secondAttribute="trailing" constant="20" symbolic="YES" id="xIc-XH-CzB"/>
-                </constraints>
-            </view>
-            <point key="canvasLocation" x="6" y="454"/>
-        </window>
-        <window title="Shared Secret" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="255" userLabel="SharedSecret">
-            <windowStyleMask key="styleMask" titled="YES"/>
-            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
-            <rect key="contentRect" x="591" y="108" width="496" height="148"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
-            <value key="minSize" type="size" width="213" height="107"/>
-            <view key="contentView" id="254">
-                <rect key="frame" x="0.0" y="0.0" width="496" height="148"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="256">
-                        <rect key="frame" x="96" y="81" width="380" height="22"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100256">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                        <connections>
-                            <outlet property="delegate" destination="-2" id="283"/>
-                            <outlet property="nextKeyView" destination="257" id="288"/>
-                        </connections>
-                    </textField>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="257" customClass="NSSecureTextField">
-                        <rect key="frame" x="96" y="49" width="380" height="22"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100257">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                        <connections>
-                            <outlet property="delegate" destination="-2" id="284"/>
-                            <outlet property="nextKeyView" destination="256" id="289"/>
-                        </connections>
-                    </textField>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="258">
-                        <rect key="frame" x="46" y="84" width="44" height="17"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Name:" id="100258">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="259">
-                        <rect key="frame" x="24" y="52" width="66" height="17"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Password:" id="100259">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="260">
-                        <rect key="frame" x="400" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100260">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="279"/>
-                        </connections>
-                    </button>
-                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="261">
-                        <rect key="frame" x="318" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100261">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="280"/>
-                        </connections>
-                    </button>
-                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="262">
-                        <rect key="frame" x="18" y="111" width="460" height="17"/>
-                        <constraints>
-                            <constraint firstAttribute="width" priority="499" constant="456" id="Mua-9c-7eO"/>
-                        </constraints>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a password if your DNS server requires authentication." id="100262">
-                            <font key="font" metaFont="systemBold"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                </subviews>
-                <constraints>
-                    <constraint firstAttribute="trailing" secondItem="256" secondAttribute="trailing" constant="20" symbolic="YES" id="3mf-gO-3d5"/>
-                    <constraint firstAttribute="trailing" secondItem="262" secondAttribute="trailing" constant="20" symbolic="YES" id="7wb-gt-2py"/>
-                    <constraint firstItem="261" firstAttribute="baseline" secondItem="260" secondAttribute="baseline" id="9Qx-ne-W5G"/>
-                    <constraint firstItem="258" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="9jU-dY-JqX"/>
-                    <constraint firstItem="260" firstAttribute="top" secondItem="257" secondAttribute="bottom" constant="8" symbolic="YES" id="Dt1-uv-H2r"/>
-                    <constraint firstItem="262" firstAttribute="leading" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="El6-is-b6l"/>
-                    <constraint firstItem="256" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="IAp-Sj-ojh"/>
-                    <constraint firstItem="262" firstAttribute="top" secondItem="254" secondAttribute="top" constant="20" symbolic="YES" id="IKv-MA-MaG"/>
-                    <constraint firstItem="260" firstAttribute="leading" secondItem="261" secondAttribute="trailing" constant="12" symbolic="YES" id="Jih-R5-3WX"/>
-                    <constraint firstAttribute="trailing" secondItem="260" secondAttribute="trailing" constant="20" symbolic="YES" id="L7K-Si-lMS"/>
-                    <constraint firstItem="256" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="MGe-DK-IsJ"/>
-                    <constraint firstItem="257" firstAttribute="leading" secondItem="256" secondAttribute="leading" id="XiH-SB-ew9"/>
-                    <constraint firstItem="261" firstAttribute="width" secondItem="260" secondAttribute="width" id="ZBv-82-oHI"/>
-                    <constraint firstItem="257" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="ZSQ-Eu-kfv"/>
-                    <constraint firstItem="257" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="awk-Ih-h6t"/>
-                    <constraint firstAttribute="trailing" secondItem="257" secondAttribute="trailing" constant="20" symbolic="YES" id="b4B-N1-Kkw"/>
-                    <constraint firstItem="256" firstAttribute="top" secondItem="262" secondAttribute="bottom" constant="8" symbolic="YES" id="bMU-Gr-KAT"/>
-                    <constraint firstItem="259" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="djz-PT-u6u"/>
-                    <constraint firstItem="259" firstAttribute="baseline" secondItem="257" secondAttribute="baseline" id="eqD-gu-QY7"/>
-                    <constraint firstItem="256" firstAttribute="leading" secondItem="258" secondAttribute="trailing" constant="8" symbolic="YES" id="g6K-nY-Pnf"/>
-                    <constraint firstAttribute="bottom" secondItem="260" secondAttribute="bottom" constant="20" symbolic="YES" id="qad-Pr-uFC"/>
-                    <constraint firstItem="257" firstAttribute="top" secondItem="256" secondAttribute="bottom" constant="10" symbolic="YES" id="qyJ-gm-15K"/>
-                    <constraint firstItem="257" firstAttribute="leading" secondItem="259" secondAttribute="trailing" constant="8" symbolic="YES" id="sAe-2s-bxV"/>
-                    <constraint firstItem="258" firstAttribute="baseline" secondItem="256" secondAttribute="baseline" id="xZU-Nd-Q5f"/>
-                </constraints>
-            </view>
-            <point key="canvasLocation" x="148" y="69"/>
-        </window>
-        <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="333" userLabel="AddDomain">
-            <windowStyleMask key="styleMask" titled="YES"/>
-            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
-            <rect key="contentRect" x="634" y="377" width="496" height="220"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
-            <value key="minSize" type="size" width="213" height="107"/>
-            <view key="contentView" id="334">
-                <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="336">
-                        <rect key="frame" x="18" y="183" width="460" height="17"/>
-                        <constraints>
-                            <constraint firstAttribute="width" priority="499" constant="456" id="qTJ-tL-p1s"/>
-                        </constraints>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to add to your list of Bonjour browse domains." id="100336">
-                            <font key="font" metaFont="systemBold"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <customView translatesAutoresizingMaskIntoConstraints="NO" id="200327" customClass="CNDomainBrowserView">
-                        <rect key="frame" x="20" y="61" width="456" height="114"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="114" id="ey8-36-A8G"/>
-                        </constraints>
-                        <userDefinedRuntimeAttributes>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="NO"/>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="NO"/>
-                        </userDefinedRuntimeAttributes>
-                    </customView>
-                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="340">
-                        <rect key="frame" x="400" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100340">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="365"/>
-                        </connections>
-                    </button>
-                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="341">
-                        <rect key="frame" x="318" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100341">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="364"/>
-                        </connections>
-                    </button>
-                </subviews>
-                <constraints>
-                    <constraint firstItem="341" firstAttribute="width" secondItem="340" secondAttribute="width" id="1kP-hH-4fg"/>
-                    <constraint firstItem="336" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="6p2-FN-dgI"/>
-                    <constraint firstItem="200327" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="BFf-ab-vji"/>
-                    <constraint firstItem="341" firstAttribute="baseline" secondItem="340" secondAttribute="baseline" id="DdL-N2-sRf"/>
-                    <constraint firstItem="336" firstAttribute="top" secondItem="334" secondAttribute="top" constant="20" symbolic="YES" id="Iei-fi-sMQ"/>
-                    <constraint firstItem="340" firstAttribute="top" secondItem="200327" secondAttribute="bottom" constant="20" symbolic="YES" id="Ouj-CX-0R3"/>
-                    <constraint firstAttribute="trailing" secondItem="200327" secondAttribute="trailing" constant="20" symbolic="YES" id="QWi-nn-fZb"/>
-                    <constraint firstItem="200327" firstAttribute="top" secondItem="336" secondAttribute="bottom" constant="8" symbolic="YES" id="f1Y-2w-Xl7"/>
-                    <constraint firstAttribute="trailing" secondItem="336" secondAttribute="trailing" constant="20" symbolic="YES" id="gOk-i6-e6u"/>
-                    <constraint firstAttribute="trailing" secondItem="340" secondAttribute="trailing" constant="20" symbolic="YES" id="gvy-DL-dCw"/>
-                    <constraint firstAttribute="bottom" secondItem="340" secondAttribute="bottom" constant="20" symbolic="YES" id="i1j-hc-gtt"/>
-                    <constraint firstItem="340" firstAttribute="leading" secondItem="341" secondAttribute="trailing" constant="12" symbolic="YES" id="yRJ-0k-a3r"/>
-                </constraints>
-            </view>
-            <point key="canvasLocation" x="-27" y="-234"/>
-        </window>
-        <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NFb-eI-atL" userLabel="AddDomainManual">
-            <windowStyleMask key="styleMask" titled="YES"/>
-            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
-            <rect key="contentRect" x="634" y="377" width="496" height="133"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
-            <value key="minSize" type="size" width="213" height="107"/>
-            <view key="contentView" id="gUJ-3k-BQQ">
-                <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="aoV-3v-A7q">
-                        <rect key="frame" x="400" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Jo3-6e-vxc">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="hMi-BR-qQY"/>
-                        </connections>
-                    </button>
-                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a0y-0s-TTY">
-                        <rect key="frame" x="318" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="qne-aW-QHl">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="eUl-Y1-c5S"/>
-                        </connections>
-                    </button>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Sfp-nO-NP2">
-                        <rect key="frame" x="36" y="52" width="54" height="17"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="b6L-KA-Dqu">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Myg-XJ-ngM">
-                        <rect key="frame" x="18" y="79" width="460" height="34"/>
-                        <constraints>
-                            <constraint firstAttribute="width" priority="499" constant="456" id="nwj-Vn-nBx"/>
-                        </constraints>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following domain will be added to your list of Bonjour browse domains." id="m5w-3d-gfR">
-                            <font key="font" metaFont="systemBold"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="W2d-Us-Cpm">
-                        <rect key="frame" x="96" y="49" width="380" height="22"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="kJz-0i-YUX">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                </subviews>
-                <constraints>
-                    <constraint firstAttribute="trailing" secondItem="W2d-Us-Cpm" secondAttribute="trailing" constant="20" symbolic="YES" id="08z-5S-y1p"/>
-                    <constraint firstAttribute="trailing" secondItem="Myg-XJ-ngM" secondAttribute="trailing" constant="20" symbolic="YES" id="2qd-6o-hRs"/>
-                    <constraint firstAttribute="trailing" secondItem="aoV-3v-A7q" secondAttribute="trailing" constant="20" symbolic="YES" id="5WH-eg-Ibw"/>
-                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" priority="499" constant="96" id="KBy-nt-u24"/>
-                    <constraint firstItem="aoV-3v-A7q" firstAttribute="baseline" secondItem="a0y-0s-TTY" secondAttribute="baseline" id="L8X-K0-cNZ"/>
-                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="Sfp-nO-NP2" secondAttribute="trailing" constant="8" symbolic="YES" id="Pw7-gK-pJO"/>
-                    <constraint firstItem="Myg-XJ-ngM" firstAttribute="top" secondItem="gUJ-3k-BQQ" secondAttribute="top" constant="20" symbolic="YES" id="Vkn-zN-QmY"/>
-                    <constraint firstAttribute="bottom" secondItem="aoV-3v-A7q" secondAttribute="bottom" constant="20" symbolic="YES" id="aJb-Dk-Ofa"/>
-                    <constraint firstItem="aoV-3v-A7q" firstAttribute="top" secondItem="W2d-Us-Cpm" secondAttribute="bottom" constant="8" symbolic="YES" id="bbw-LB-NG3"/>
-                    <constraint firstItem="Myg-XJ-ngM" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="cab-6m-9M7"/>
-                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="top" secondItem="Myg-XJ-ngM" secondAttribute="bottom" constant="8" symbolic="YES" id="ewM-hb-zj3"/>
-                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="jsT-pp-iwi"/>
-                    <constraint firstItem="Sfp-nO-NP2" firstAttribute="baseline" secondItem="W2d-Us-Cpm" secondAttribute="baseline" id="qPo-ba-jjr"/>
-                    <constraint firstItem="aoV-3v-A7q" firstAttribute="leading" secondItem="a0y-0s-TTY" secondAttribute="trailing" constant="12" symbolic="YES" id="tzd-P2-c6b"/>
-                    <constraint firstItem="Sfp-nO-NP2" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="vVs-34-dSS"/>
-                    <constraint firstItem="aoV-3v-A7q" firstAttribute="width" secondItem="a0y-0s-TTY" secondAttribute="width" id="xg1-eb-4Pj"/>
-                </constraints>
-            </view>
-            <point key="canvasLocation" x="-27" y="-524"/>
-        </window>
-        <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="ail-If-2Xp" userLabel="SelectRegDomain">
-            <windowStyleMask key="styleMask" titled="YES"/>
-            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
-            <rect key="contentRect" x="634" y="377" width="496" height="220"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
-            <value key="minSize" type="size" width="213" height="107"/>
-            <view key="contentView" id="W37-VK-yC5">
-                <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="q4Y-tT-1h7">
-                        <rect key="frame" x="18" y="183" width="460" height="17"/>
-                        <constraints>
-                            <constraint firstAttribute="width" priority="499" constant="456" id="zF0-CN-3xD"/>
-                        </constraints>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to use as your Bonjour registration domain." id="EDB-Ul-M1P">
-                            <font key="font" metaFont="systemBold"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <customView translatesAutoresizingMaskIntoConstraints="NO" id="agb-WV-smo" customClass="CNDomainBrowserView">
-                        <rect key="frame" x="20" y="61" width="456" height="114"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="114" id="3JN-68-aTf"/>
-                        </constraints>
-                        <userDefinedRuntimeAttributes>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="YES"/>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
-                            <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="YES"/>
-                        </userDefinedRuntimeAttributes>
-                    </customView>
-                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="8fZ-4V-xd6">
-                        <rect key="frame" x="400" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="eLF-AD-BgY">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="HFg-iF-1qy"/>
-                        </connections>
-                    </button>
-                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I6S-g0-R0G">
-                        <rect key="frame" x="318" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="a1o-he-Kv7">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="SQP-5g-qGG"/>
-                        </connections>
-                    </button>
-                </subviews>
-                <constraints>
-                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="top" secondItem="agb-WV-smo" secondAttribute="bottom" constant="20" symbolic="YES" id="4cD-Af-ApJ"/>
-                    <constraint firstItem="q4Y-tT-1h7" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="8fj-II-NeF"/>
-                    <constraint firstItem="q4Y-tT-1h7" firstAttribute="top" secondItem="W37-VK-yC5" secondAttribute="top" constant="20" symbolic="YES" id="Bq5-8Z-4eY"/>
-                    <constraint firstItem="agb-WV-smo" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="Kex-pV-3tR"/>
-                    <constraint firstAttribute="trailing" secondItem="q4Y-tT-1h7" secondAttribute="trailing" constant="20" symbolic="YES" id="Piu-PE-SEc"/>
-                    <constraint firstItem="agb-WV-smo" firstAttribute="top" secondItem="q4Y-tT-1h7" secondAttribute="bottom" constant="8" symbolic="YES" id="Spl-BU-U7l"/>
-                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="width" secondItem="I6S-g0-R0G" secondAttribute="width" id="Xx2-3v-4H5"/>
-                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="leading" secondItem="I6S-g0-R0G" secondAttribute="trailing" constant="12" symbolic="YES" id="aly-0r-bvb"/>
-                    <constraint firstAttribute="bottom" secondItem="8fZ-4V-xd6" secondAttribute="bottom" constant="20" symbolic="YES" id="eqT-TT-gxE"/>
-                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="baseline" secondItem="I6S-g0-R0G" secondAttribute="baseline" id="h1B-xs-zFp"/>
-                    <constraint firstAttribute="trailing" secondItem="agb-WV-smo" secondAttribute="trailing" constant="20" symbolic="YES" id="xLH-br-4Uh"/>
-                    <constraint firstAttribute="trailing" secondItem="8fZ-4V-xd6" secondAttribute="trailing" constant="20" symbolic="YES" id="xiF-Cr-13M"/>
-                </constraints>
-            </view>
-            <point key="canvasLocation" x="538" y="-234"/>
-        </window>
-        <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="he2-0K-CWy" userLabel="SelectRegDomainManual">
-            <windowStyleMask key="styleMask" titled="YES"/>
-            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
-            <rect key="contentRect" x="634" y="377" width="496" height="133"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
-            <value key="minSize" type="size" width="213" height="107"/>
-            <view key="contentView" id="FYv-ly-yOd">
-                <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="sau-gD-LVt">
-                        <rect key="frame" x="400" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="jAh-nT-Qwg">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="ySI-9p-3tZ"/>
-                        </connections>
-                    </button>
-                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ypd-8h-xfJ">
-                        <rect key="frame" x="318" y="13" width="82" height="32"/>
-                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Nd2-rR-DtX">
-                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                            <font key="font" metaFont="system"/>
-                            <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
-                        </buttonCell>
-                        <connections>
-                            <action selector="closeMyCustomSheet:" target="-2" id="YM3-jW-TNM"/>
-                        </connections>
-                    </button>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="die-Uf-Bn9">
-                        <rect key="frame" x="36" y="52" width="54" height="17"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="ZIy-WQ-OIZ">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="06e-WM-3MP">
-                        <rect key="frame" x="18" y="79" width="460" height="34"/>
-                        <constraints>
-                            <constraint firstAttribute="width" priority="499" constant="456" id="ilh-EM-DG1"/>
-                        </constraints>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following registration domain will be used by Bonjour to advertise beyond the local subnet." id="SLP-nX-Q2C">
-                            <font key="font" metaFont="systemBold"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="NO" translatesAutoresizingMaskIntoConstraints="NO" id="OEh-fL-Ol6">
-                        <rect key="frame" x="96" y="49" width="380" height="22"/>
-                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="aIe-CQ-mQ3">
-                            <font key="font" metaFont="system"/>
-                            <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                </subviews>
-                <constraints>
-                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" priority="499" constant="96" id="1Nc-CQ-lXd"/>
-                    <constraint firstItem="06e-WM-3MP" firstAttribute="top" secondItem="FYv-ly-yOd" secondAttribute="top" constant="20" symbolic="YES" id="5wy-Ji-7tZ"/>
-                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="top" secondItem="06e-WM-3MP" secondAttribute="bottom" constant="8" symbolic="YES" id="7BD-rk-RTl"/>
-                    <constraint firstItem="sau-gD-LVt" firstAttribute="leading" secondItem="Ypd-8h-xfJ" secondAttribute="trailing" constant="12" symbolic="YES" id="7oo-eg-nGA"/>
-                    <constraint firstItem="die-Uf-Bn9" firstAttribute="baseline" secondItem="OEh-fL-Ol6" secondAttribute="baseline" id="DbC-UI-YFz"/>
-                    <constraint firstItem="die-Uf-Bn9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="Ip2-Q3-r3l"/>
-                    <constraint firstAttribute="trailing" secondItem="sau-gD-LVt" secondAttribute="trailing" constant="20" symbolic="YES" id="Jce-ky-wTf"/>
-                    <constraint firstItem="sau-gD-LVt" firstAttribute="width" secondItem="Ypd-8h-xfJ" secondAttribute="width" id="NkV-L2-e4p"/>
-                    <constraint firstItem="sau-gD-LVt" firstAttribute="top" secondItem="OEh-fL-Ol6" secondAttribute="bottom" constant="8" symbolic="YES" id="Omq-c5-SZQ"/>
-                    <constraint firstAttribute="trailing" secondItem="06e-WM-3MP" secondAttribute="trailing" constant="20" symbolic="YES" id="U0T-5s-Jip"/>
-                    <constraint firstAttribute="bottom" secondItem="sau-gD-LVt" secondAttribute="bottom" constant="20" symbolic="YES" id="cWG-NL-TzC"/>
-                    <constraint firstAttribute="trailing" secondItem="OEh-fL-Ol6" secondAttribute="trailing" constant="20" symbolic="YES" id="igv-0W-kuw"/>
-                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="die-Uf-Bn9" secondAttribute="trailing" constant="8" symbolic="YES" id="j71-MK-aiv"/>
-                    <constraint firstItem="sau-gD-LVt" firstAttribute="baseline" secondItem="Ypd-8h-xfJ" secondAttribute="baseline" id="t9l-JC-Ab2"/>
-                    <constraint firstItem="06e-WM-3MP" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wIW-Ja-ih6"/>
-                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wia-Av-Bte"/>
-                </constraints>
-            </view>
-            <point key="canvasLocation" x="538" y="-525"/>
-        </window>
-    </objects>
-    <resources>
-        <image name="NSAddTemplate" width="11" height="11"/>
-        <image name="NSRemoveTemplate" width="11" height="11"/>
-    </resources>
-</document>
diff --git a/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib b/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib
deleted file mode 100644 (file)
index 33cf8f8..0000000
Binary files a/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.nib/keyedobjects.nib and /dev/null differ
diff --git a/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.xib b/mDNSMacOSX/PreferencePane/Base.lproj/DNSServiceDiscoveryPref.xib
new file mode 100644 (file)
index 0000000..540ece5
--- /dev/null
@@ -0,0 +1,816 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14724.4" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
+    <dependencies>
+        <deployment identifier="macosx"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14724.4"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <customObject id="-2" userLabel="File's Owner" customClass="DNSServiceDiscoveryPref">
+            <connections>
+                <outlet property="_initialKeyView" destination="107" id="235"/>
+                <outlet property="_lastKeyView" destination="107" id="183"/>
+                <outlet property="_window" destination="12" id="142"/>
+                <outlet property="addBrowseDomainButton" destination="381" id="384"/>
+                <outlet property="addBrowseDomainManualWindow" destination="NFb-eI-atL" id="0AN-Mr-e84"/>
+                <outlet property="addBrowseDomainWindow" destination="333" id="363"/>
+                <outlet property="applyButton" destination="208" id="238"/>
+                <outlet property="bonjourBrowserView" destination="200327" id="200328"/>
+                <outlet property="browseCancelButton" destination="341" id="375"/>
+                <outlet property="browseDomainList" destination="327" id="349"/>
+                <outlet property="browseDomainTextField" destination="W2d-Us-Cpm" id="kOZ-wG-OPp"/>
+                <outlet property="browseOKButton" destination="340" id="376"/>
+                <outlet property="comboAuthButton" destination="137" id="201"/>
+                <outlet property="hostName" destination="107" id="224"/>
+                <outlet property="hostNameSharedSecretButton" destination="263" id="270"/>
+                <outlet property="regDomainTextField" destination="OEh-fL-Ol6" id="Dv0-aj-gah"/>
+                <outlet property="regDomainView" destination="Reu-VC-MNz" id="4I2-zS-sdq"/>
+                <outlet property="registrationBrowserView" destination="agb-WV-smo" id="j7U-ZK-LIb"/>
+                <outlet property="registrationSelectButton" destination="KqE-pc-8z0" id="CJS-ml-2CA"/>
+                <outlet property="registrationSharedSecretButton" destination="267" id="268"/>
+                <outlet property="removeBrowseDomainButton" destination="383" id="385"/>
+                <outlet property="revertButton" destination="290" id="292"/>
+                <outlet property="secretCancelButton" destination="341" id="373"/>
+                <outlet property="secretOKButton" destination="260" id="377"/>
+                <outlet property="selectRegistrationDomainManualWindow" destination="he2-0K-CWy" id="eXD-7o-XQU"/>
+                <outlet property="selectRegistrationDomainWindow" destination="ail-If-2Xp" id="34V-c7-D3b"/>
+                <outlet property="sharedSecretName" destination="256" id="275"/>
+                <outlet property="sharedSecretValue" destination="257" id="276"/>
+                <outlet property="sharedSecretWindow" destination="255" id="274"/>
+                <outlet property="statusImageView" destination="320" id="321"/>
+                <outlet property="tabView" destination="100" id="380"/>
+                <outlet property="wideAreaCheckBox" destination="179" id="240"/>
+            </connections>
+        </customObject>
+        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+        <customObject id="-3" userLabel="Application" customClass="NSObject"/>
+        <window title="Bonjour" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" deferred="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="12" userLabel="PrefPane">
+            <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
+            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+            <rect key="contentRect" x="51" y="335" width="596" height="343"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+            <value key="minSize" type="size" width="213.66399999999999" height="10"/>
+            <view key="contentView" id="6">
+                <rect key="frame" x="0.0" y="0.0" width="596" height="343"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <tabView translatesAutoresizingMaskIntoConstraints="NO" id="100">
+                        <rect key="frame" x="13" y="52" width="570" height="285"/>
+                        <font key="font" metaFont="system"/>
+                        <tabViewItems>
+                            <tabViewItem label="Hostname" identifier="1" id="102">
+                                <view key="view" id="101">
+                                    <rect key="frame" x="10" y="33" width="550" height="239"/>
+                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                    <subviews>
+                                        <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="107">
+                                            <rect key="frame" x="119" y="155" width="383" height="22"/>
+                                            <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" placeholderString="steve.example.com" drawsBackground="YES" id="100107">
+                                                <font key="font" metaFont="system"/>
+                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                            </textFieldCell>
+                                            <connections>
+                                                <outlet property="delegate" destination="-2" id="227"/>
+                                            </connections>
+                                        </textField>
+                                        <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="108">
+                                            <rect key="frame" x="43" y="158" width="70" height="17"/>
+                                            <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Hostname:" id="100108">
+                                                <font key="font" metaFont="system"/>
+                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                                            </textFieldCell>
+                                        </textField>
+                                        <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="117">
+                                            <rect key="frame" x="18" y="185" width="514" height="34"/>
+                                            <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a hostname for this computer.  Other computers on the Internet will be able to reach your computer using this hostname." id="100117">
+                                                <font key="font" metaFont="systemBold"/>
+                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                                            </textFieldCell>
+                                        </textField>
+                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="263">
+                                            <rect key="frame" x="113" y="119" width="109" height="32"/>
+                                            <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100263">
+                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                                <font key="font" metaFont="system"/>
+                                            </buttonCell>
+                                            <connections>
+                                                <action selector="changeButtonPressed:" target="-2" id="272"/>
+                                            </connections>
+                                        </button>
+                                        <imageView translatesAutoresizingMaskIntoConstraints="NO" id="320">
+                                            <rect key="frame" x="510" y="156" width="20" height="20"/>
+                                            <constraints>
+                                                <constraint firstAttribute="width" constant="20" id="7Qf-g0-5SV"/>
+                                                <constraint firstAttribute="height" constant="20" id="bfL-QJ-KFw"/>
+                                            </constraints>
+                                            <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageAlignment="left" imageScaling="proportionallyDown" id="100320"/>
+                                        </imageView>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="263" firstAttribute="leading" secondItem="107" secondAttribute="leading" id="4Dv-gf-Cjr"/>
+                                        <constraint firstAttribute="trailing" secondItem="117" secondAttribute="trailing" constant="20" symbolic="YES" id="5zc-LQ-OC8"/>
+                                        <constraint firstItem="320" firstAttribute="leading" secondItem="107" secondAttribute="trailing" constant="8" symbolic="YES" id="BIu-YL-Fr2"/>
+                                        <constraint firstItem="263" firstAttribute="top" secondItem="107" secondAttribute="bottom" constant="8" symbolic="YES" id="K1w-WG-3KW"/>
+                                        <constraint firstItem="107" firstAttribute="centerY" secondItem="320" secondAttribute="centerY" id="LlU-Oy-3va"/>
+                                        <constraint firstItem="107" firstAttribute="top" secondItem="117" secondAttribute="bottom" constant="8" symbolic="YES" id="V8c-G1-gsR"/>
+                                        <constraint firstItem="117" firstAttribute="top" secondItem="101" secondAttribute="top" constant="20" symbolic="YES" id="Xnz-bz-ahU"/>
+                                        <constraint firstItem="117" firstAttribute="leading" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="ZIG-S4-cst"/>
+                                        <constraint firstItem="107" firstAttribute="leading" secondItem="108" secondAttribute="trailing" constant="8" symbolic="YES" id="cQG-zv-Ozo"/>
+                                        <constraint firstItem="108" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="101" secondAttribute="leading" constant="20" symbolic="YES" id="foH-DQ-yvJ"/>
+                                        <constraint firstItem="107" firstAttribute="leading" secondItem="101" secondAttribute="leading" priority="499" constant="119" id="qGZ-fm-Wgf"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="263" secondAttribute="trailing" constant="20" symbolic="YES" id="vFp-zd-1ea"/>
+                                        <constraint firstAttribute="trailing" secondItem="320" secondAttribute="trailing" constant="20" symbolic="YES" id="w2R-Kc-Tj3"/>
+                                        <constraint firstItem="108" firstAttribute="baseline" secondItem="107" secondAttribute="baseline" id="xcr-32-mbs"/>
+                                    </constraints>
+                                </view>
+                            </tabViewItem>
+                            <tabViewItem label="Registration" identifier="2" id="98">
+                                <view key="view" id="99">
+                                    <rect key="frame" x="10" y="33" width="550" height="239"/>
+                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                    <subviews>
+                                        <button translatesAutoresizingMaskIntoConstraints="NO" id="179">
+                                            <rect key="frame" x="41" y="157" width="72" height="18"/>
+                                            <buttonCell key="cell" type="check" title="Domain:" bezelStyle="regularSquare" imagePosition="left" alignment="right" inset="2" id="100179">
+                                                <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+                                                <font key="font" metaFont="system"/>
+                                            </buttonCell>
+                                            <connections>
+                                                <action selector="wideAreaCheckBoxChanged:" target="-2" id="317"/>
+                                            </connections>
+                                        </button>
+                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="267">
+                                            <rect key="frame" x="222" y="119" width="109" height="32"/>
+                                            <buttonCell key="cell" type="push" title="Password…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100267">
+                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                                <font key="font" metaFont="system"/>
+                                            </buttonCell>
+                                            <connections>
+                                                <action selector="changeButtonPressed:" target="-2" id="273"/>
+                                            </connections>
+                                        </button>
+                                        <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="348">
+                                            <rect key="frame" x="18" y="185" width="514" height="34"/>
+                                            <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Check the box and select a registration domain to enable Bonjour advertising beyond the local subnet." id="100348">
+                                                <font key="font" metaFont="systemBold"/>
+                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                                            </textFieldCell>
+                                        </textField>
+                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="KqE-pc-8z0">
+                                            <rect key="frame" x="113" y="119" width="109" height="32"/>
+                                            <buttonCell key="cell" type="push" title="Select…" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="TjV-QO-BW7">
+                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                                <font key="font" metaFont="system"/>
+                                            </buttonCell>
+                                            <connections>
+                                                <action selector="selectWideAreaDomainButtonPressed:" target="-2" id="d4S-la-iyw"/>
+                                            </connections>
+                                        </button>
+                                        <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="cxI-8W-6HI">
+                                            <rect key="frame" x="119" y="155" width="411" height="22"/>
+                                            <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" enabled="NO" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="Oao-6x-0X9">
+                                                <font key="font" metaFont="system"/>
+                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                            </textFieldCell>
+                                        </textField>
+                                        <customView translatesAutoresizingMaskIntoConstraints="NO" id="Reu-VC-MNz" customClass="CNBonjourDomainView">
+                                            <rect key="frame" x="119" y="155" width="411" height="22"/>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="22" id="l7c-m9-GcE"/>
+                                            </constraints>
+                                        </customView>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="267" firstAttribute="leading" secondItem="KqE-pc-8z0" secondAttribute="trailing" constant="12" symbolic="YES" id="2kZ-P9-l60"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="centerY" secondItem="cxI-8W-6HI" secondAttribute="centerY" id="984-4H-aIz"/>
+                                        <constraint firstItem="179" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="D3d-wd-QYX"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="top" secondItem="348" secondAttribute="bottom" constant="8" symbolic="YES" id="GcL-zf-7HQ"/>
+                                        <constraint firstItem="348" firstAttribute="top" secondItem="99" secondAttribute="top" constant="20" symbolic="YES" id="HDQ-fd-PwR"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="height" secondItem="cxI-8W-6HI" secondAttribute="height" id="HUo-M5-tyi"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="width" secondItem="cxI-8W-6HI" secondAttribute="width" id="JML-71-xrY"/>
+                                        <constraint firstItem="cxI-8W-6HI" firstAttribute="baseline" secondItem="179" secondAttribute="baseline" id="NX1-5X-UZI"/>
+                                        <constraint firstItem="348" firstAttribute="leading" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="P0u-7u-LJv"/>
+                                        <constraint firstItem="KqE-pc-8z0" firstAttribute="leading" secondItem="cxI-8W-6HI" secondAttribute="leading" id="RDS-Bc-KYd"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="99" secondAttribute="leading" constant="20" symbolic="YES" id="d8L-Kb-W49"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="centerX" secondItem="cxI-8W-6HI" secondAttribute="centerX" id="dfu-qB-Ezj"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="179" secondAttribute="trailing" constant="8" symbolic="YES" id="rUC-3C-r32"/>
+                                        <constraint firstItem="KqE-pc-8z0" firstAttribute="top" secondItem="cxI-8W-6HI" secondAttribute="bottom" constant="8" symbolic="YES" id="skb-cf-d2E"/>
+                                        <constraint firstAttribute="trailing" secondItem="Reu-VC-MNz" secondAttribute="trailing" constant="20" symbolic="YES" id="ta5-1S-y3v"/>
+                                        <constraint firstAttribute="trailing" secondItem="348" secondAttribute="trailing" constant="20" symbolic="YES" id="tr3-Ed-I8w"/>
+                                        <constraint firstItem="267" firstAttribute="baseline" secondItem="KqE-pc-8z0" secondAttribute="baseline" id="vt0-3i-y05"/>
+                                        <constraint firstItem="267" firstAttribute="width" secondItem="KqE-pc-8z0" secondAttribute="width" id="vxX-jt-NDx"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="267" secondAttribute="trailing" constant="20" symbolic="YES" id="w1s-Ah-Gmw"/>
+                                        <constraint firstItem="Reu-VC-MNz" firstAttribute="leading" secondItem="99" secondAttribute="leading" priority="499" constant="119" id="xdT-xB-bam"/>
+                                    </constraints>
+                                </view>
+                            </tabViewItem>
+                            <tabViewItem label="Browsing" identifier="" id="322">
+                                <view key="view" id="323">
+                                    <rect key="frame" x="10" y="33" width="550" height="239"/>
+                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                    <subviews>
+                                        <scrollView horizontalLineScroll="24" horizontalPageScroll="10" verticalLineScroll="24" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="326">
+                                            <rect key="frame" x="20" y="82" width="510" height="112"/>
+                                            <clipView key="contentView" id="r8V-oO-qTS">
+                                                <rect key="frame" x="1" y="1" width="508" height="110"/>
+                                                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                                <subviews>
+                                                    <tableView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="22" id="327">
+                                                        <rect key="frame" x="0.0" y="0.0" width="508" height="110"/>
+                                                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                                                        <size key="intercellSpacing" width="3" height="2"/>
+                                                        <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                                        <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+                                                        <tableColumns>
+                                                            <tableColumn identifier="Enabled" width="35" minWidth="30" maxWidth="1000" id="328">
+                                                                <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+                                                                    <font key="font" metaFont="smallSystem"/>
+                                                                    <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                                                    <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
+                                                                </tableHeaderCell>
+                                                                <buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="above" alignment="center" inset="2" id="358">
+                                                                    <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+                                                                    <font key="font" metaFont="cellTitle"/>
+                                                                    <connections>
+                                                                        <action selector="enableBrowseDomainClicked:" target="-2" id="360"/>
+                                                                    </connections>
+                                                                </buttonCell>
+                                                            </tableColumn>
+                                                            <tableColumn identifier="Domain" editable="NO" width="451.9541015625" minWidth="49.3466796875" maxWidth="1000" id="329">
+                                                                <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Domain">
+                                                                    <font key="font" metaFont="smallSystem"/>
+                                                                    <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                                                    <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
+                                                                </tableHeaderCell>
+                                                                <customCell key="dataCell" alignment="left" id="LhH-Yh-n33" customClass="CNBonjourDomainCell"/>
+                                                            </tableColumn>
+                                                        </tableColumns>
+                                                        <connections>
+                                                            <outlet property="dataSource" destination="-2" id="350"/>
+                                                            <outlet property="delegate" destination="-2" id="351"/>
+                                                        </connections>
+                                                    </tableView>
+                                                </subviews>
+                                            </clipView>
+                                            <constraints>
+                                                <constraint firstAttribute="height" constant="112" id="Pf1-34-QXp"/>
+                                            </constraints>
+                                            <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="100326">
+                                                <rect key="frame" x="-100" y="-100" width="493" height="15"/>
+                                                <autoresizingMask key="autoresizingMask"/>
+                                            </scroller>
+                                            <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="200326">
+                                                <rect key="frame" x="493" y="1" width="16" height="110"/>
+                                                <autoresizingMask key="autoresizingMask"/>
+                                            </scroller>
+                                        </scrollView>
+                                        <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="330">
+                                            <rect key="frame" x="18" y="202" width="514" height="17"/>
+                                            <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Choose which domains to browse using Wide-Area Bonjour." id="100330">
+                                                <font key="font" metaFont="systemBold"/>
+                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                                            </textFieldCell>
+                                        </textField>
+                                        <button toolTip="Click to define shortcuts within applications." verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="381">
+                                            <rect key="frame" x="20" y="49" width="24" height="26"/>
+                                            <constraints>
+                                                <constraint firstAttribute="width" relation="greaterThanOrEqual" constant="24" id="llU-4M-pcI"/>
+                                                <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="24" id="qD8-y4-ZkW"/>
+                                            </constraints>
+                                            <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="overlaps" alignment="center" state="on" borderStyle="border" id="100381">
+                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                                <font key="font" metaFont="system"/>
+                                            </buttonCell>
+                                            <connections>
+                                                <action selector="addBrowseDomainClicked:" target="-2" id="386"/>
+                                            </connections>
+                                        </button>
+                                        <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="383">
+                                            <rect key="frame" x="43" y="49" width="24" height="26"/>
+                                            <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="overlaps" alignment="center" controlSize="small" state="on" borderStyle="border" id="100383">
+                                                <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                                <font key="font" metaFont="smallSystem"/>
+                                                <string key="keyEquivalent">\7f</string>
+                                            </buttonCell>
+                                            <connections>
+                                                <action selector="removeBrowseDomainClicked:" target="-2" id="387"/>
+                                            </connections>
+                                        </button>
+                                    </subviews>
+                                    <constraints>
+                                        <constraint firstItem="326" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="BHw-zP-zzH"/>
+                                        <constraint firstItem="381" firstAttribute="centerY" secondItem="383" secondAttribute="centerY" id="Cae-WW-gYH"/>
+                                        <constraint firstItem="326" firstAttribute="leading" secondItem="381" secondAttribute="leading" id="GCR-nb-Kbp"/>
+                                        <constraint firstItem="381" firstAttribute="height" secondItem="383" secondAttribute="height" id="GYW-Vr-6c8"/>
+                                        <constraint firstAttribute="trailing" secondItem="326" secondAttribute="trailing" constant="20" symbolic="YES" id="HGK-Ej-oKA"/>
+                                        <constraint firstItem="383" firstAttribute="leading" secondItem="381" secondAttribute="trailing" constant="-1" id="KYa-XM-Qrh"/>
+                                        <constraint firstAttribute="trailing" secondItem="330" secondAttribute="trailing" constant="20" symbolic="YES" id="Lkk-cy-gcf"/>
+                                        <constraint firstItem="326" firstAttribute="top" secondItem="330" secondAttribute="bottom" constant="8" symbolic="YES" id="Pna-sQ-Iom"/>
+                                        <constraint firstItem="381" firstAttribute="top" secondItem="326" secondAttribute="bottom" constant="8" symbolic="YES" id="YmF-BH-VOk"/>
+                                        <constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="383" secondAttribute="trailing" constant="20" symbolic="YES" id="aY5-XO-vJN"/>
+                                        <constraint firstItem="381" firstAttribute="width" secondItem="383" secondAttribute="width" id="kJf-PK-P0M"/>
+                                        <constraint firstItem="330" firstAttribute="leading" secondItem="323" secondAttribute="leading" constant="20" symbolic="YES" id="luC-Nv-ec5"/>
+                                        <constraint firstItem="330" firstAttribute="top" secondItem="323" secondAttribute="top" constant="20" symbolic="YES" id="yVJ-PT-T31"/>
+                                    </constraints>
+                                </view>
+                            </tabViewItem>
+                        </tabViewItems>
+                    </tabView>
+                    <customView translatesAutoresizingMaskIntoConstraints="NO" id="137" customClass="SFAuthorizationView">
+                        <rect key="frame" x="20" y="20" width="356" height="34"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="34" id="T24-JY-FUW"/>
+                            <constraint firstAttribute="width" constant="356" id="hHs-jB-Xz8"/>
+                        </constraints>
+                    </customView>
+                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="208">
+                        <rect key="frame" x="502" y="13" width="80" height="32"/>
+                        <buttonCell key="cell" type="push" title="Apply" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100208">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                        </buttonCell>
+                        <connections>
+                            <action selector="applyClicked:" target="-2" id="209"/>
+                        </connections>
+                    </button>
+                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="290">
+                        <rect key="frame" x="422" y="13" width="80" height="32"/>
+                        <buttonCell key="cell" type="push" title="Revert" bezelStyle="rounded" alignment="center" enabled="NO" borderStyle="border" inset="2" id="100290">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                        </buttonCell>
+                        <connections>
+                            <action selector="revertClicked:" target="-2" id="293"/>
+                        </connections>
+                    </button>
+                </subviews>
+                <constraints>
+                    <constraint firstItem="290" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="0rt-dY-Rii"/>
+                    <constraint firstAttribute="trailing" secondItem="100" secondAttribute="trailing" constant="20" symbolic="YES" id="DEs-Vk-n3D"/>
+                    <constraint firstItem="208" firstAttribute="width" secondItem="290" secondAttribute="width" id="GMB-MK-qPS"/>
+                    <constraint firstAttribute="bottom" secondItem="137" secondAttribute="bottom" constant="20" symbolic="YES" id="M0C-li-Dr1"/>
+                    <constraint firstItem="100" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="Ozi-Cv-NdV"/>
+                    <constraint firstAttribute="bottom" secondItem="208" secondAttribute="bottom" constant="20" symbolic="YES" id="PGr-uI-dUi"/>
+                    <constraint firstItem="290" firstAttribute="baseline" secondItem="208" secondAttribute="baseline" id="Rcf-kj-OQp"/>
+                    <constraint firstItem="137" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="dWc-kl-h8o"/>
+                    <constraint firstItem="208" firstAttribute="leading" secondItem="290" secondAttribute="trailing" constant="12" symbolic="YES" id="g3l-gL-wIw"/>
+                    <constraint firstItem="137" firstAttribute="top" secondItem="100" secondAttribute="bottom" constant="8" symbolic="YES" id="jDb-sm-pFt"/>
+                    <constraint firstItem="100" firstAttribute="top" secondItem="6" secondAttribute="top" constant="12" symbolic="YES" id="nWn-mH-iEl"/>
+                    <constraint firstAttribute="trailing" secondItem="208" secondAttribute="trailing" constant="20" symbolic="YES" id="xIc-XH-CzB"/>
+                </constraints>
+            </view>
+            <point key="canvasLocation" x="6" y="454"/>
+        </window>
+        <window title="Shared Secret" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="255" userLabel="SharedSecret">
+            <windowStyleMask key="styleMask" titled="YES"/>
+            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+            <rect key="contentRect" x="591" y="108" width="496" height="148"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+            <value key="minSize" type="size" width="213" height="107"/>
+            <view key="contentView" id="254">
+                <rect key="frame" x="0.0" y="0.0" width="496" height="148"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="256">
+                        <rect key="frame" x="96" y="81" width="380" height="22"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100256">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                        <connections>
+                            <outlet property="delegate" destination="-2" id="283"/>
+                            <outlet property="nextKeyView" destination="257" id="288"/>
+                        </connections>
+                    </textField>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="257" customClass="NSSecureTextField">
+                        <rect key="frame" x="96" y="49" width="380" height="22"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" alignment="left" drawsBackground="YES" id="100257">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                        <connections>
+                            <outlet property="delegate" destination="-2" id="284"/>
+                            <outlet property="nextKeyView" destination="256" id="289"/>
+                        </connections>
+                    </textField>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="258">
+                        <rect key="frame" x="46" y="84" width="44" height="17"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Name:" id="100258">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="259">
+                        <rect key="frame" x="24" y="52" width="66" height="17"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Password:" id="100259">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="260">
+                        <rect key="frame" x="400" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100260">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="279"/>
+                        </connections>
+                    </button>
+                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="261">
+                        <rect key="frame" x="318" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100261">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="280"/>
+                        </connections>
+                    </button>
+                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="262">
+                        <rect key="frame" x="18" y="111" width="460" height="17"/>
+                        <constraints>
+                            <constraint firstAttribute="width" priority="499" constant="456" id="Mua-9c-7eO"/>
+                        </constraints>
+                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Enter a password if your DNS server requires authentication." id="100262">
+                            <font key="font" metaFont="systemBold"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="trailing" secondItem="256" secondAttribute="trailing" constant="20" symbolic="YES" id="3mf-gO-3d5"/>
+                    <constraint firstAttribute="trailing" secondItem="262" secondAttribute="trailing" constant="20" symbolic="YES" id="7wb-gt-2py"/>
+                    <constraint firstItem="261" firstAttribute="baseline" secondItem="260" secondAttribute="baseline" id="9Qx-ne-W5G"/>
+                    <constraint firstItem="258" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="9jU-dY-JqX"/>
+                    <constraint firstItem="260" firstAttribute="top" secondItem="257" secondAttribute="bottom" constant="8" symbolic="YES" id="Dt1-uv-H2r"/>
+                    <constraint firstItem="262" firstAttribute="leading" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="El6-is-b6l"/>
+                    <constraint firstItem="256" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="IAp-Sj-ojh"/>
+                    <constraint firstItem="262" firstAttribute="top" secondItem="254" secondAttribute="top" constant="20" symbolic="YES" id="IKv-MA-MaG"/>
+                    <constraint firstItem="260" firstAttribute="leading" secondItem="261" secondAttribute="trailing" constant="12" symbolic="YES" id="Jih-R5-3WX"/>
+                    <constraint firstAttribute="trailing" secondItem="260" secondAttribute="trailing" constant="20" symbolic="YES" id="L7K-Si-lMS"/>
+                    <constraint firstItem="256" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="MGe-DK-IsJ"/>
+                    <constraint firstItem="257" firstAttribute="leading" secondItem="256" secondAttribute="leading" id="XiH-SB-ew9"/>
+                    <constraint firstItem="261" firstAttribute="width" secondItem="260" secondAttribute="width" id="ZBv-82-oHI"/>
+                    <constraint firstItem="257" firstAttribute="leading" secondItem="254" secondAttribute="leading" priority="499" constant="96" id="ZSQ-Eu-kfv"/>
+                    <constraint firstItem="257" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="awk-Ih-h6t"/>
+                    <constraint firstAttribute="trailing" secondItem="257" secondAttribute="trailing" constant="20" symbolic="YES" id="b4B-N1-Kkw"/>
+                    <constraint firstItem="256" firstAttribute="top" secondItem="262" secondAttribute="bottom" constant="8" symbolic="YES" id="bMU-Gr-KAT"/>
+                    <constraint firstItem="259" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="254" secondAttribute="leading" constant="20" symbolic="YES" id="djz-PT-u6u"/>
+                    <constraint firstItem="259" firstAttribute="baseline" secondItem="257" secondAttribute="baseline" id="eqD-gu-QY7"/>
+                    <constraint firstItem="256" firstAttribute="leading" secondItem="258" secondAttribute="trailing" constant="8" symbolic="YES" id="g6K-nY-Pnf"/>
+                    <constraint firstAttribute="bottom" secondItem="260" secondAttribute="bottom" constant="20" symbolic="YES" id="qad-Pr-uFC"/>
+                    <constraint firstItem="257" firstAttribute="top" secondItem="256" secondAttribute="bottom" constant="10" symbolic="YES" id="qyJ-gm-15K"/>
+                    <constraint firstItem="257" firstAttribute="leading" secondItem="259" secondAttribute="trailing" constant="8" symbolic="YES" id="sAe-2s-bxV"/>
+                    <constraint firstItem="258" firstAttribute="baseline" secondItem="256" secondAttribute="baseline" id="xZU-Nd-Q5f"/>
+                </constraints>
+            </view>
+            <point key="canvasLocation" x="148" y="69"/>
+        </window>
+        <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="333" userLabel="AddDomain">
+            <windowStyleMask key="styleMask" titled="YES"/>
+            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+            <rect key="contentRect" x="634" y="377" width="496" height="220"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+            <value key="minSize" type="size" width="213" height="107"/>
+            <view key="contentView" id="334">
+                <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="336">
+                        <rect key="frame" x="18" y="183" width="460" height="17"/>
+                        <constraints>
+                            <constraint firstAttribute="width" priority="499" constant="456" id="qTJ-tL-p1s"/>
+                        </constraints>
+                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to add to your list of Bonjour browse domains." id="100336">
+                            <font key="font" metaFont="systemBold"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <customView translatesAutoresizingMaskIntoConstraints="NO" id="200327" customClass="CNDomainBrowserView">
+                        <rect key="frame" x="20" y="61" width="456" height="114"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="114" id="ey8-36-A8G"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="NO"/>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="NO"/>
+                        </userDefinedRuntimeAttributes>
+                    </customView>
+                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="340">
+                        <rect key="frame" x="400" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100340">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="365"/>
+                        </connections>
+                    </button>
+                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="341">
+                        <rect key="frame" x="318" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="100341">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="364"/>
+                        </connections>
+                    </button>
+                </subviews>
+                <constraints>
+                    <constraint firstItem="341" firstAttribute="width" secondItem="340" secondAttribute="width" id="1kP-hH-4fg"/>
+                    <constraint firstItem="336" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="6p2-FN-dgI"/>
+                    <constraint firstItem="200327" firstAttribute="leading" secondItem="334" secondAttribute="leading" constant="20" symbolic="YES" id="BFf-ab-vji"/>
+                    <constraint firstItem="341" firstAttribute="baseline" secondItem="340" secondAttribute="baseline" id="DdL-N2-sRf"/>
+                    <constraint firstItem="336" firstAttribute="top" secondItem="334" secondAttribute="top" constant="20" symbolic="YES" id="Iei-fi-sMQ"/>
+                    <constraint firstItem="340" firstAttribute="top" secondItem="200327" secondAttribute="bottom" constant="20" symbolic="YES" id="Ouj-CX-0R3"/>
+                    <constraint firstAttribute="trailing" secondItem="200327" secondAttribute="trailing" constant="20" symbolic="YES" id="QWi-nn-fZb"/>
+                    <constraint firstItem="200327" firstAttribute="top" secondItem="336" secondAttribute="bottom" constant="8" symbolic="YES" id="f1Y-2w-Xl7"/>
+                    <constraint firstAttribute="trailing" secondItem="336" secondAttribute="trailing" constant="20" symbolic="YES" id="gOk-i6-e6u"/>
+                    <constraint firstAttribute="trailing" secondItem="340" secondAttribute="trailing" constant="20" symbolic="YES" id="gvy-DL-dCw"/>
+                    <constraint firstAttribute="bottom" secondItem="340" secondAttribute="bottom" constant="20" symbolic="YES" id="i1j-hc-gtt"/>
+                    <constraint firstItem="340" firstAttribute="leading" secondItem="341" secondAttribute="trailing" constant="12" symbolic="YES" id="yRJ-0k-a3r"/>
+                </constraints>
+            </view>
+            <point key="canvasLocation" x="-27" y="-234"/>
+        </window>
+        <window title="Add Browse Domains" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="NFb-eI-atL" userLabel="AddDomainManual">
+            <windowStyleMask key="styleMask" titled="YES"/>
+            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+            <rect key="contentRect" x="634" y="377" width="496" height="133"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+            <value key="minSize" type="size" width="213" height="107"/>
+            <view key="contentView" id="gUJ-3k-BQQ">
+                <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="aoV-3v-A7q">
+                        <rect key="frame" x="400" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Jo3-6e-vxc">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="hMi-BR-qQY"/>
+                        </connections>
+                    </button>
+                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="a0y-0s-TTY">
+                        <rect key="frame" x="318" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="qne-aW-QHl">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="eUl-Y1-c5S"/>
+                        </connections>
+                    </button>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Sfp-nO-NP2">
+                        <rect key="frame" x="36" y="52" width="54" height="17"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="b6L-KA-Dqu">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Myg-XJ-ngM">
+                        <rect key="frame" x="18" y="79" width="460" height="34"/>
+                        <constraints>
+                            <constraint firstAttribute="width" priority="499" constant="456" id="nwj-Vn-nBx"/>
+                        </constraints>
+                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following domain will be added to your list of Bonjour browse domains." id="m5w-3d-gfR">
+                            <font key="font" metaFont="systemBold"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="W2d-Us-Cpm">
+                        <rect key="frame" x="96" y="49" width="380" height="22"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="kJz-0i-YUX">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                </subviews>
+                <constraints>
+                    <constraint firstAttribute="trailing" secondItem="W2d-Us-Cpm" secondAttribute="trailing" constant="20" symbolic="YES" id="08z-5S-y1p"/>
+                    <constraint firstAttribute="trailing" secondItem="Myg-XJ-ngM" secondAttribute="trailing" constant="20" symbolic="YES" id="2qd-6o-hRs"/>
+                    <constraint firstAttribute="trailing" secondItem="aoV-3v-A7q" secondAttribute="trailing" constant="20" symbolic="YES" id="5WH-eg-Ibw"/>
+                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" priority="499" constant="96" id="KBy-nt-u24"/>
+                    <constraint firstItem="aoV-3v-A7q" firstAttribute="baseline" secondItem="a0y-0s-TTY" secondAttribute="baseline" id="L8X-K0-cNZ"/>
+                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" secondItem="Sfp-nO-NP2" secondAttribute="trailing" constant="8" symbolic="YES" id="Pw7-gK-pJO"/>
+                    <constraint firstItem="Myg-XJ-ngM" firstAttribute="top" secondItem="gUJ-3k-BQQ" secondAttribute="top" constant="20" symbolic="YES" id="Vkn-zN-QmY"/>
+                    <constraint firstAttribute="bottom" secondItem="aoV-3v-A7q" secondAttribute="bottom" constant="20" symbolic="YES" id="aJb-Dk-Ofa"/>
+                    <constraint firstItem="aoV-3v-A7q" firstAttribute="top" secondItem="W2d-Us-Cpm" secondAttribute="bottom" constant="8" symbolic="YES" id="bbw-LB-NG3"/>
+                    <constraint firstItem="Myg-XJ-ngM" firstAttribute="leading" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="cab-6m-9M7"/>
+                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="top" secondItem="Myg-XJ-ngM" secondAttribute="bottom" constant="8" symbolic="YES" id="ewM-hb-zj3"/>
+                    <constraint firstItem="W2d-Us-Cpm" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="jsT-pp-iwi"/>
+                    <constraint firstItem="Sfp-nO-NP2" firstAttribute="baseline" secondItem="W2d-Us-Cpm" secondAttribute="baseline" id="qPo-ba-jjr"/>
+                    <constraint firstItem="aoV-3v-A7q" firstAttribute="leading" secondItem="a0y-0s-TTY" secondAttribute="trailing" constant="12" symbolic="YES" id="tzd-P2-c6b"/>
+                    <constraint firstItem="Sfp-nO-NP2" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="gUJ-3k-BQQ" secondAttribute="leading" constant="20" symbolic="YES" id="vVs-34-dSS"/>
+                    <constraint firstItem="aoV-3v-A7q" firstAttribute="width" secondItem="a0y-0s-TTY" secondAttribute="width" id="xg1-eb-4Pj"/>
+                </constraints>
+            </view>
+            <point key="canvasLocation" x="-27" y="-524"/>
+        </window>
+        <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="ail-If-2Xp" userLabel="SelectRegDomain">
+            <windowStyleMask key="styleMask" titled="YES"/>
+            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+            <rect key="contentRect" x="634" y="377" width="496" height="220"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+            <value key="minSize" type="size" width="213" height="107"/>
+            <view key="contentView" id="W37-VK-yC5">
+                <rect key="frame" x="0.0" y="0.0" width="496" height="220"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="q4Y-tT-1h7">
+                        <rect key="frame" x="18" y="183" width="460" height="17"/>
+                        <constraints>
+                            <constraint firstAttribute="width" priority="499" constant="456" id="zF0-CN-3xD"/>
+                        </constraints>
+                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="Choose a domain to use as your Bonjour registration domain." id="EDB-Ul-M1P">
+                            <font key="font" metaFont="systemBold"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <customView translatesAutoresizingMaskIntoConstraints="NO" id="agb-WV-smo" customClass="CNDomainBrowserView">
+                        <rect key="frame" x="20" y="61" width="456" height="114"/>
+                        <constraints>
+                            <constraint firstAttribute="height" constant="114" id="3JN-68-aTf"/>
+                        </constraints>
+                        <userDefinedRuntimeAttributes>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="registrationDomains" value="YES"/>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreLocal" value="YES"/>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="ignoreBTMM" value="NO"/>
+                            <userDefinedRuntimeAttribute type="boolean" keyPath="browseRegistration" value="YES"/>
+                        </userDefinedRuntimeAttributes>
+                    </customView>
+                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="8fZ-4V-xd6">
+                        <rect key="frame" x="400" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="eLF-AD-BgY">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="HFg-iF-1qy"/>
+                        </connections>
+                    </button>
+                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="I6S-g0-R0G">
+                        <rect key="frame" x="318" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="a1o-he-Kv7">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="SQP-5g-qGG"/>
+                        </connections>
+                    </button>
+                </subviews>
+                <constraints>
+                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="top" secondItem="agb-WV-smo" secondAttribute="bottom" constant="20" symbolic="YES" id="4cD-Af-ApJ"/>
+                    <constraint firstItem="q4Y-tT-1h7" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="8fj-II-NeF"/>
+                    <constraint firstItem="q4Y-tT-1h7" firstAttribute="top" secondItem="W37-VK-yC5" secondAttribute="top" constant="20" symbolic="YES" id="Bq5-8Z-4eY"/>
+                    <constraint firstItem="agb-WV-smo" firstAttribute="leading" secondItem="W37-VK-yC5" secondAttribute="leading" constant="20" symbolic="YES" id="Kex-pV-3tR"/>
+                    <constraint firstAttribute="trailing" secondItem="q4Y-tT-1h7" secondAttribute="trailing" constant="20" symbolic="YES" id="Piu-PE-SEc"/>
+                    <constraint firstItem="agb-WV-smo" firstAttribute="top" secondItem="q4Y-tT-1h7" secondAttribute="bottom" constant="8" symbolic="YES" id="Spl-BU-U7l"/>
+                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="width" secondItem="I6S-g0-R0G" secondAttribute="width" id="Xx2-3v-4H5"/>
+                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="leading" secondItem="I6S-g0-R0G" secondAttribute="trailing" constant="12" symbolic="YES" id="aly-0r-bvb"/>
+                    <constraint firstAttribute="bottom" secondItem="8fZ-4V-xd6" secondAttribute="bottom" constant="20" symbolic="YES" id="eqT-TT-gxE"/>
+                    <constraint firstItem="8fZ-4V-xd6" firstAttribute="baseline" secondItem="I6S-g0-R0G" secondAttribute="baseline" id="h1B-xs-zFp"/>
+                    <constraint firstAttribute="trailing" secondItem="agb-WV-smo" secondAttribute="trailing" constant="20" symbolic="YES" id="xLH-br-4Uh"/>
+                    <constraint firstAttribute="trailing" secondItem="8fZ-4V-xd6" secondAttribute="trailing" constant="20" symbolic="YES" id="xiF-Cr-13M"/>
+                </constraints>
+            </view>
+            <point key="canvasLocation" x="538" y="-234"/>
+        </window>
+        <window title="Add Registration Domain" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="he2-0K-CWy" userLabel="SelectRegDomainManual">
+            <windowStyleMask key="styleMask" titled="YES"/>
+            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+            <rect key="contentRect" x="634" y="377" width="496" height="133"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/>
+            <value key="minSize" type="size" width="213" height="107"/>
+            <view key="contentView" id="FYv-ly-yOd">
+                <rect key="frame" x="0.0" y="0.0" width="496" height="133"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <button verticalHuggingPriority="750" tag="1" translatesAutoresizingMaskIntoConstraints="NO" id="sau-gD-LVt">
+                        <rect key="frame" x="400" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="OK" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="jAh-nT-Qwg">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="ySI-9p-3tZ"/>
+                        </connections>
+                    </button>
+                    <button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Ypd-8h-xfJ">
+                        <rect key="frame" x="318" y="13" width="82" height="32"/>
+                        <buttonCell key="cell" type="push" title="Cancel" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="Nd2-rR-DtX">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="system"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+Gw
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="closeMyCustomSheet:" target="-2" id="YM3-jW-TNM"/>
+                        </connections>
+                    </button>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="die-Uf-Bn9">
+                        <rect key="frame" x="36" y="52" width="54" height="17"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Domain:" id="ZIy-WQ-OIZ">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="06e-WM-3MP">
+                        <rect key="frame" x="18" y="79" width="460" height="34"/>
+                        <constraints>
+                            <constraint firstAttribute="width" priority="499" constant="456" id="ilh-EM-DG1"/>
+                        </constraints>
+                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="left" title="The following registration domain will be used by Bonjour to advertise beyond the local subnet." id="SLP-nX-Q2C">
+                            <font key="font" metaFont="systemBold"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="OEh-fL-Ol6">
+                        <rect key="frame" x="96" y="49" width="380" height="22"/>
+                        <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="aIe-CQ-mQ3">
+                            <font key="font" metaFont="system"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                </subviews>
+                <constraints>
+                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" priority="499" constant="96" id="1Nc-CQ-lXd"/>
+                    <constraint firstItem="06e-WM-3MP" firstAttribute="top" secondItem="FYv-ly-yOd" secondAttribute="top" constant="20" symbolic="YES" id="5wy-Ji-7tZ"/>
+                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="top" secondItem="06e-WM-3MP" secondAttribute="bottom" constant="8" symbolic="YES" id="7BD-rk-RTl"/>
+                    <constraint firstItem="sau-gD-LVt" firstAttribute="leading" secondItem="Ypd-8h-xfJ" secondAttribute="trailing" constant="12" symbolic="YES" id="7oo-eg-nGA"/>
+                    <constraint firstItem="die-Uf-Bn9" firstAttribute="baseline" secondItem="OEh-fL-Ol6" secondAttribute="baseline" id="DbC-UI-YFz"/>
+                    <constraint firstItem="die-Uf-Bn9" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="Ip2-Q3-r3l"/>
+                    <constraint firstAttribute="trailing" secondItem="sau-gD-LVt" secondAttribute="trailing" constant="20" symbolic="YES" id="Jce-ky-wTf"/>
+                    <constraint firstItem="sau-gD-LVt" firstAttribute="width" secondItem="Ypd-8h-xfJ" secondAttribute="width" id="NkV-L2-e4p"/>
+                    <constraint firstItem="sau-gD-LVt" firstAttribute="top" secondItem="OEh-fL-Ol6" secondAttribute="bottom" constant="8" symbolic="YES" id="Omq-c5-SZQ"/>
+                    <constraint firstAttribute="trailing" secondItem="06e-WM-3MP" secondAttribute="trailing" constant="20" symbolic="YES" id="U0T-5s-Jip"/>
+                    <constraint firstAttribute="bottom" secondItem="sau-gD-LVt" secondAttribute="bottom" constant="20" symbolic="YES" id="cWG-NL-TzC"/>
+                    <constraint firstAttribute="trailing" secondItem="OEh-fL-Ol6" secondAttribute="trailing" constant="20" symbolic="YES" id="igv-0W-kuw"/>
+                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" secondItem="die-Uf-Bn9" secondAttribute="trailing" constant="8" symbolic="YES" id="j71-MK-aiv"/>
+                    <constraint firstItem="sau-gD-LVt" firstAttribute="baseline" secondItem="Ypd-8h-xfJ" secondAttribute="baseline" id="t9l-JC-Ab2"/>
+                    <constraint firstItem="06e-WM-3MP" firstAttribute="leading" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wIW-Ja-ih6"/>
+                    <constraint firstItem="OEh-fL-Ol6" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="FYv-ly-yOd" secondAttribute="leading" constant="20" symbolic="YES" id="wia-Av-Bte"/>
+                </constraints>
+            </view>
+            <point key="canvasLocation" x="538" y="-525"/>
+        </window>
+    </objects>
+    <resources>
+        <image name="NSAddTemplate" width="11" height="11"/>
+        <image name="NSRemoveTemplate" width="11" height="11"/>
+    </resources>
+</document>
diff --git a/mDNSMacOSX/PreferencePane/ConfigurationRights.h b/mDNSMacOSX/PreferencePane/ConfigurationRights.h
deleted file mode 100644 (file)
index 44379c6..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-    File: ConfigurationRights.h
-
-    Abstract: Defines the rights we need, namely, (i) the right to write to
-    the system configuration settings for Dynamic DNS and Wide-Area DNS-SD,
-    and (ii) the right to write to the system keychain to store Dynamic DNS
-    shared secrets used to perform authorized updates to DDNS servers.
-    Right now these are both actually the same right: "system.preferences"
-
-    Copyright: (c) Copyright 2005 Apple Computer, Inc. All rights reserved.
-
-    Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
-    ("Apple") in consideration of your agreement to the following terms, and your
-    use, installation, modification or redistribution of this Apple software
-    constitutes acceptance of these terms.  If you do not agree with these terms,
-    please do not use, install, modify or redistribute this Apple software.
-
-    In consideration of your agreement to abide by the following terms, and subject
-    to these terms, Apple grants you a personal, non-exclusive license, under Apple's
-    copyrights in this original Apple software (the "Apple Software"), to use,
-    reproduce, modify and redistribute the Apple Software, with or without
-    modifications, in source and/or binary forms; provided that if you redistribute
-    the Apple Software in its entirety and without modifications, you must retain
-    this notice and the following text and disclaimers in all such redistributions of
-    the Apple Software.  Neither the name, trademarks, service marks or logos of
-    Apple Computer, Inc. may be used to endorse or promote products derived from the
-    Apple Software without specific prior written permission from Apple.  Except as
-    expressly stated in this notice, no other rights or licenses, express or implied,
-    are granted by Apple herein, including but not limited to any patent rights that
-    may be infringed by your derivative works or by other works in which the Apple
-    Software may be incorporated.
-
-    The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
-    WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
-    WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-    PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
-    COMBINATION WITH YOUR PRODUCTS.
-
-    IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
-    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
-    GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-    ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
-    OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
-    (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
-    ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define UPDATE_SC_RIGHT          "system.preferences"
-#define EDIT_SYS_KEYCHAIN_RIGHT  "system.preferences"
diff --git a/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings b/mDNSMacOSX/PreferencePane/English.lproj/InfoPlist.strings
deleted file mode 100644 (file)
index 71d52de..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/* Localized versions of Info.plist keys */
-
-CFBundleName = "Bonjour";
-CFBundleGetInfoString = "Bonjour version 1.0, Copyright (c) 2005-2015 Apple Inc.";
-NSHumanReadableCopyright = "Copyright (c) 2005-2015 Apple Inc.";
diff --git a/mDNSMacOSX/PreferencePane/en.lproj/InfoPlist.strings b/mDNSMacOSX/PreferencePane/en.lproj/InfoPlist.strings
new file mode 100644 (file)
index 0000000..aea4e1f
--- /dev/null
@@ -0,0 +1,5 @@
+/* Localized versions of Info.plist keys */
+
+CFBundleName = "Bonjour";
+CFBundleGetInfoString = "Bonjour version 1.0, Copyright (c) 2005-2019 Apple Inc.";
+NSHumanReadableCopyright = "Copyright (c) 2005-2019 Apple Inc.";
index 46e2a23a9f53bd64558bd253bae6efb134f05d13..69f2f02237c56341ce32776a7c86472d0b988839 100644 (file)
@@ -1,16 +1,15 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2012-2019 Apple Inc. All rights reserved.
  *
  * PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS--
  * Resides in /usr/lib/libdns_services.dylib
  */
 
 #include "dns_services.h"
-#include "dns_xpc.h"
 #include <xpc/xpc.h>
 #include <Block.h>
 #include <os/log.h>
+#include "xpc_clients.h"
 
 //*************************************************************************************************************
 // Globals
 
 struct _DNSXConnRef_t
 {
-    connection_t      conn_ref;      // xpc_connection between client and daemon
-    dispatch_queue_t  lib_q;         // internal queue created in library itself
-    void              *AppCallBack;  // Callback function ptr for Client
-    dispatch_queue_t  client_q;      // Queue specified by client for scheduling its Callback
+    connection_t          conn_ref;      // xpc_connection between client and daemon
+    dispatch_queue_t      lib_q;         // internal queue created in library itself
+    DNSXEnableProxyReply  AppCallBack;   // Callback function ptr for Client
+    dispatch_queue_t      client_q;      // Queue specified by client for scheduling its Callback
 };
 
 //*************************************************************************************************************
@@ -104,7 +103,7 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg)
                     case kDNSMsg_NoError:
                         dispatch_async((connRef)->client_q, ^{
                         if (connRef->AppCallBack != NULL)
-                            ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_NoError);
+                            connRef->AppCallBack(connRef, kDNSX_NoError);
                         });
                         break;
                                                              
@@ -112,7 +111,7 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg)
                         os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: DNS Proxy already in use");
                         dispatch_async((connRef)->client_q, ^{
                         if (connRef->AppCallBack != NULL)
-                            ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_Busy);
+                            connRef->AppCallBack(connRef, kDNSX_Busy);
                         });
                         break;
                                                                
@@ -120,7 +119,7 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg)
                         os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: Unknown error");
                         dispatch_async((connRef)->client_q, ^{
                         if (connRef->AppCallBack != NULL)
-                            ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_UnknownErr);
+                            connRef->AppCallBack(connRef, kDNSX_UnknownErr);
                         });
                         break;
                 }
@@ -138,7 +137,7 @@ static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg)
 }
 
 // Creates a new DNSX Connection Reference(DNSXConnRef)
-static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servname, dispatch_queue_t clientq, void *AppCallBack)
+static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servname, dispatch_queue_t clientq, DNSXEnableProxyReply AppCallBack)
 {
     if (connRefOut == NULL)
     {
@@ -183,7 +182,7 @@ static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servnam
                                  xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
             dispatch_async(connRef->client_q, ^{
             if (connRef->AppCallBack != NULL)
-                ((DNSXEnableProxyReply)connRef->AppCallBack)(connRef, kDNSX_DaemonNotRunning);
+                connRef->AppCallBack(connRef, kDNSX_DaemonNotRunning);
             });
         }
                                          
index 34c687565ec17fccc769f83b3fd67b69773c63d0..4c3544fc7fdcc2fc5c0e74b09e594e0625bf7077 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2012-2018 Apple Inc. All rights reserved.
  *
  *
  * @header      Interface to DNSX SPI
 
 #include <dispatch/dispatch.h>
 
+#if (defined(__GNUC__) && (__GNUC__ >= 4))
+#define DNS_SERVICES_EXPORT __attribute__((visibility("default")))
+#else
+#define DNS_SERVICES_EXPORT
+#endif
+
 // DNSXConnRef: Opaque internal data type
 typedef struct _DNSXConnRef_t *DNSXConnRef;
 
@@ -101,6 +107,7 @@ typedef void (*DNSXEnableProxyReply)
  *
  */
 
+DNS_SERVICES_EXPORT
 DNSXErrorType DNSXEnableProxy
 (
     DNSXConnRef              *connRef,
@@ -119,6 +126,7 @@ DNSXErrorType DNSXEnableProxy
  * connRef:        A DNSXConnRef initialized by any of the DNSX*() calls.
  *
  */
+DNS_SERVICES_EXPORT
 void DNSXRefDeAlloc(DNSXConnRef connRef);
 
 #endif
diff --git a/mDNSMacOSX/Private/dns_xpc.h b/mDNSMacOSX/Private/dns_xpc.h
deleted file mode 100644 (file)
index bda2bf9..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- * Defines the common interface between mDNSResponder and the Private ClientLibrary(libdnsprivate.dylib)
- * Uses XPC as the IPC Mechanism
- *
- */
-
-#ifndef DNS_XPC_H
-#define DNS_XPC_H
-
-#define kDNSProxyService "com.apple.mDNSResponder.dnsproxy"
-#define kDNSCTLService   "com.apple.mDNSResponder.dnsctl"
-
-#define kDNSProxyParameters     "DNSProxyParameters"
-
-#define kDNSInIfindex0          "InputArrayInterfaceIndex[0]"
-#define kDNSInIfindex1          "InputArrayInterfaceIndex[1]"
-#define kDNSInIfindex2          "InputArrayInterfaceIndex[2]"
-#define kDNSInIfindex3          "InputArrayInterfaceIndex[3]"
-#define kDNSInIfindex4          "InputArrayInterfaceIndex[4]"
-
-#define kDNSOutIfindex          "OutputInterfaceIndex"
-
-#define kDNSDaemonReply         "DaemonReplyStatusToClient"
-
-typedef enum
-{
-    kDNSMsg_NoError       =  0,
-    kDNSMsg_Busy
-} DaemonReplyStatusCodes;
-
-#define kDNSLogLevel            "DNSLoggingVerbosity"
-
-typedef enum
-{
-    log_level1 = 1, // logging off
-    log_level2,     // logging USR1
-    log_level3,     // logging USR2
-    log_level4,     // logging USR1/2
-} DNSLogLevels;
-
-#define kDNSStateInfo            "DNSStateInfoLevels"
-
-typedef enum
-{
-    full_state = 1,   // full state info of mDNSResponder (INFO)
-} DNSStateInfo;
-
-#define kmDNSResponderTests           "mDNSResponderTests"
-
-typedef enum
-{
-    test_helper_ipc = 1,   // invokes mDNSResponder to send a test msg to mDNSResponderHelper
-    test_mDNS_log,         // invokes mDNSResponder to log using different internal macros
-} mDNSTestModes;
-
-
-
-#endif // DNS_XPC_H
diff --git a/mDNSMacOSX/Private/dnsctl_server.c b/mDNSMacOSX/Private/dnsctl_server.c
deleted file mode 100644 (file)
index ad5136d..0000000
+++ /dev/null
@@ -1,224 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 Apple Inc. All rights reserved.
- *
- * dnsctl_server.c
- * mDNSResponder 
- *
- * XPC as an IPC mechanism to communicate with dnsctl. Open only to Apple OSX/iOS clients
- */
-
-#include "xpc_services.h"
-#include "dns_xpc.h"
-
-#include "mDNSMacOSX.h"      // KQueueLock/KQueueUnlock
-#include "helper.h"          // mDNSResponderHelper tests
-#include <xpc/xpc.h>
-
-// ***************************************************************************
-// Globals
-extern mDNS mDNSStorage;
-static dispatch_queue_t dnsctlserver_queue = NULL;
-// ***************************************************************************
-
-mDNSlocal void handle_logging(mDNSu32 log_level)
-{
-    KQueueLock();
-    
-    switch (log_level)
-    {
-        case log_level1:
-            mDNS_LoggingEnabled = mDNS_PacketLoggingEnabled = 0;
-            LogMsg("USR1 Logging:[%s] USR2 Logging:[%s]", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
-            break;
-            
-        case log_level2:
-            mDNS_LoggingEnabled = 1;
-            LogMsg("USR1 Logging %s", mDNS_LoggingEnabled ? "Enabled" : "Disabled");
-            break;
-            
-        case log_level3:
-            mDNS_PacketLoggingEnabled = 1;
-            LogMsg("USR2 Logging %s", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
-            break;
-            
-        case log_level4:
-            mDNS_LoggingEnabled = 1 ;
-            mDNS_PacketLoggingEnabled = 1;
-            LogMsg("USR1 Logging:%s USR2 Logging:%s", mDNS_LoggingEnabled ? "Enabled" : "Disabled", mDNS_PacketLoggingEnabled ? "Enabled" : "Disabled");
-            break;
-            
-        default:
-            mDNS_LoggingEnabled = 0 ;
-            mDNS_PacketLoggingEnabled = 0;
-            break;
-    }
-    UpdateDebugState();
-    
-    KQueueUnlock("LogLevel changed");
-}
-
-mDNSlocal void handle_stateinfo(mDNSu32 state_level)
-{
-    KQueueLock();
-    
-    switch (state_level)
-    {
-        case full_state:
-            INFOCallback();
-            break;
-            
-        default:
-            INFOCallback();
-            break;
-    }
-    
-    KQueueUnlock("StateInfo dumped");
-}
-
-
-mDNSlocal void handle_test_mode(mDNSu32 test_mode)
-{
-    KQueueLock();
-    
-    switch (test_mode)
-    {
-        case test_helper_ipc:
-            mDNSNotify("mDNSResponderHelperTest", "This is just a test message to mDNSResponderHelper. This is NOT an actual alert");
-            break;
-            
-        case test_mDNS_log:
-            LogInfo("LogInfo: Should be logged at INFO level");
-            LogOperation("LogOperation: Should be logged at INFO level");
-            LogMsg("LogMsg: Should be logged at DEFAULT level");
-            LogSPS("LogSPS: Should be logged at INFO level");
-            break;
-            
-        default:
-            LogMsg("Unidentified Test mode: Please add this test");
-            break;
-    }
-    
-    KQueueUnlock("Test Msg to mDNSResponderHelper");
-}
-
-mDNSlocal void handle_terminate()
-{
-    
-    LogInfo("handle_terminate: Client terminated connection.");
-    
-}
-
-mDNSlocal void handle_requests(xpc_object_t req)
-{
-    mDNSu32 log_level, state_level, test_mode;
-    xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
-
-    LogInfo("handle_requests: Handler for dnsctl requests");
-    xpc_object_t response = xpc_dictionary_create_reply(req);
-    
-    // Return Success Status to the client (essentially ACKing the request)
-    if (response)
-    {
-        xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
-        xpc_connection_send_message(remote_conn, response);
-        xpc_release(response);  
-    }
-    else
-    { 
-        LogMsg("handle_requests: Response Dictionary could not be created");
-        return;
-    }
-
-    // switch here based on dictionary
-    // to handle various different requests like logging, INFO snapshot, etc..
-    if ((xpc_dictionary_get_uint64(req, kDNSLogLevel)))
-    {
-        log_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSLogLevel));
-        handle_logging(log_level);
-    }
-    else if ((xpc_dictionary_get_uint64(req, kDNSStateInfo)))
-    {
-        state_level = (mDNSu32)(xpc_dictionary_get_uint64(req, kDNSStateInfo));
-        handle_stateinfo(state_level);
-    }
-    else if ((xpc_dictionary_get_uint64(req, kmDNSResponderTests)))
-    {
-        test_mode = (mDNSu32)(xpc_dictionary_get_uint64(req, kmDNSResponderTests));
-        handle_test_mode(test_mode);
-    }
-}
-
-mDNSlocal void accept_client(xpc_connection_t conn)
-{
-    uid_t c_euid;
-    int   c_pid;
-    c_euid  = xpc_connection_get_euid(conn);
-    c_pid   = xpc_connection_get_pid(conn);
-
-    if (c_euid != 0 || !IsEntitled(conn, kDNSCTLService))
-    {   
-        LogMsg("accept_client: Client PID[%d] is missing Entitlement or is NOT running as root!", c_pid);
-        xpc_connection_cancel(conn);
-        return; 
-    }
-    
-    xpc_retain(conn);
-    xpc_connection_set_target_queue(conn, dnsctlserver_queue);
-    xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
-        {
-            xpc_type_t type = xpc_get_type(req_msg);
-
-            if (type == XPC_TYPE_DICTIONARY)
-            {
-                handle_requests(req_msg);
-            }
-            else // We hit this case ONLY if Client Terminated Connection OR Crashed
-            {
-                LogInfo("accept_client: Client %p teared down the connection", (void *) conn);
-                handle_terminate();
-                xpc_release(conn);
-            }
-        });
-    
-    xpc_connection_resume(conn);
-                
-}
-
-mDNSexport void init_dnsctl_service(void)
-{
-    
-    xpc_connection_t dnsctl_listener = xpc_connection_create_mach_service(kDNSCTLService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
-    if (!dnsctl_listener || xpc_get_type(dnsctl_listener) != XPC_TYPE_CONNECTION)
-    {
-        LogMsg("init_dnsctl_service: Error Creating XPC Listener for DNSCTL Server!");
-        return;
-    }
-    
-    dnsctlserver_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsctlserver_queue", NULL);
-    
-    xpc_connection_set_event_handler(dnsctl_listener, ^(xpc_object_t eventmsg)
-        {
-            xpc_type_t type = xpc_get_type(eventmsg);
-
-            if (type == XPC_TYPE_CONNECTION)
-            {
-                LogInfo("init_dnsctl_service: New DNSCTL Client %p", eventmsg);
-                accept_client(eventmsg);
-            }
-            else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
-            {
-                LogMsg("init_dnsctl_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
-            }
-            else
-            {
-                LogMsg("init_dnsctl_service: Unknown EventMsg type");
-            }
-        });
-    
-    xpc_connection_resume(dnsctl_listener);
-}
-
-
-
diff --git a/mDNSMacOSX/Private/xpc_services.c b/mDNSMacOSX/Private/xpc_services.c
deleted file mode 100644 (file)
index 8bf45a4..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
- *
- * xpc_services.c
- * mDNSResponder 
- *
- * XPC as an IPC mechanism to communicate with Clients. Open only to Apple OSX/iOS clients
- */
-
-#include "xpc_services.h"
-#include "dns_xpc.h"
-
-#ifndef UNICAST_DISABLED
-
-#include "dnsproxy.h"        // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback
-#include "mDNSMacOSX.h"      // KQueueLock/KQueueUnlock
-#include <xpc/private.h>     // xpc_connection_copy_entitlement_value
-
-// ***************************************************************************
-// Globals
-extern mDNS mDNSStorage;
-static int dps_client_pid; // To track current active client using DNS Proxy Service
-static dispatch_queue_t dps_queue = NULL;
-// ***************************************************************************
-
-// prints current XPC Server State
-mDNSexport void xpcserver_info(mDNS *const m)
-{
-
-    LogMsg("----- Active XPC Clients -----");
-    if (dps_client_pid)
-       LogMsg("DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]", dps_client_pid, m->dp_ipintf[0],
-                m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf); 
-}
-
-
-mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off)
-{
-
-    LogInfo("ActivateDNSProxy: InterfaceIndex List by Client: Input[%d, %d, %d, %d, %d] Output[%d] ", IpIfArr[0], IpIfArr[1],
-             IpIfArr[2], IpIfArr[3], IpIfArr[4], OpIf);
-    KQueueLock();
-    DNSProxyInit(IpIfArr, OpIf);
-    if (proxy_off) // Open skts only if proxy was OFF else we may end up opening extra skts
-        mDNSPlatformInitDNSProxySkts(ProxyUDPCallback, ProxyTCPCallback);
-    KQueueUnlock("DNSProxy Activated");
-}
-
-mDNSlocal void handle_dps_terminate()
-{
-
-    LogInfo("handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy", dps_client_pid);
-    // Clear the Client's PID, so that we can now accept new DPS requests
-    dps_client_pid = 0;
-
-    KQueueLock();
-    mDNSPlatformCloseDNSProxySkts(&mDNSStorage);
-    // TBD: Close TCP Sockets
-    DNSProxyTerminate();
-    KQueueUnlock("DNSProxy Deactivated");
-}
-
-mDNSlocal void handle_dps_request(xpc_object_t req)
-{
-    int dps_tmp_client;
-    mDNSBool proxy_off = mDNSfalse;
-    xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
-    dps_tmp_client = (int) xpc_connection_get_pid(remote_conn);
-
-    LogInfo("handle_dps_request: Handler for DNS Proxy Requests");
-
-    if (dps_client_pid <= 0)
-    {
-        LogInfo("handle_dps_request: DNSProxy is not engaged (New Client)");
-        // No Active Client, save new Client's PID (also indicates DNS Proxy was OFF)
-        dps_client_pid = dps_tmp_client;
-        proxy_off = mDNStrue;        
-    }
-    else
-    {
-        // We already have an active DNS Proxy Client and until that client does not terminate the connection
-        // or crashes, a new client cannot change/override the current DNS Proxy settings.
-        if (dps_client_pid != dps_tmp_client)
-        {
-            LogMsg("handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time");
-            // Return Engaged Status to the client
-            xpc_object_t reply = xpc_dictionary_create_reply(req); 
-            if (reply)
-            {   
-                xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_Busy);
-                xpc_connection_send_message(remote_conn, reply);
-                xpc_release(reply);  
-            }   
-            else
-            {   
-                LogMsg("handle_dps_request: Reply Dictionary could not be created");
-                return;
-            }
-            // We do not really need to terminate the connection with the client
-            // as it may try again later which is fine
-            return;   
-        }
-    }
-    xpc_object_t response = xpc_dictionary_create_reply(req);
-    // Return Success Status to the client
-    if (response)
-    {
-        xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
-        xpc_connection_send_message(remote_conn, response);
-        xpc_release(response);  
-    }
-    else
-    { 
-        LogMsg("handle_dps_request: Response Dictionary could not be created");
-        return;
-    }
-
-    // Proceed to get DNS Proxy Settings from the Client
-    if (xpc_dictionary_get_uint64(req, kDNSProxyParameters))
-    {
-        mDNSu32 inIf[MaxIp], outIf;
-        
-        inIf[0]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex0);
-        inIf[1]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex1);
-        inIf[2]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex2);
-        inIf[3]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex3);
-        inIf[4]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex4);
-        outIf     = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSOutIfindex);
-        
-        ActivateDNSProxy(inIf, outIf, proxy_off);
-    }
-    
-}
-
-// Verify Client's Entitlement
-mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *password)
-{
-    mDNSBool entitled = mDNSfalse;
-    xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password);
-
-    if (ent)
-    {
-        if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent))
-        {
-            entitled = mDNStrue;
-        }
-        xpc_release(ent);
-    }
-    else
-    {
-        LogMsg("IsEntitled: Client Entitlement is NULL");
-    }
-    
-    if (!entitled)
-        LogMsg("IsEntitled: Client is missing Entitlement!");
-    
-    return entitled;
-}
-
-mDNSlocal void accept_dps_client(xpc_connection_t conn)
-{
-    uid_t c_euid;
-    int   c_pid;
-    c_euid  = xpc_connection_get_euid(conn);
-    c_pid   = xpc_connection_get_pid(conn);
-
-    if (c_euid != 0 || !IsEntitled(conn, kDNSProxyService))
-    {   
-        LogMsg("accept_dps_client: DNSProxyService Client PID[%d] is missing Entitlement or is not running as root!", c_pid);
-        xpc_connection_cancel(conn);
-        return; 
-    }
-    
-    xpc_retain(conn);
-    xpc_connection_set_target_queue(conn, dps_queue);
-    xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
-        {
-            xpc_type_t type = xpc_get_type(req_msg);
-
-            if (type == XPC_TYPE_DICTIONARY)
-            {
-                handle_dps_request(req_msg);
-            }
-            else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed
-            {
-                LogInfo("accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn);
-                // Only the Client that has activated DPS should be able to terminate it
-                if (c_pid == dps_client_pid)
-                    handle_dps_terminate(); 
-                xpc_release(conn);
-            }
-        });
-    
-    xpc_connection_resume(conn);
-                
-}
-
-mDNSlocal void init_dnsproxy_service(void)
-{
-    
-    xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
-    if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION)
-    {
-        LogMsg("init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
-        return;
-    }
-    
-    dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL);
-
-    xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg)
-        {
-            xpc_type_t type = xpc_get_type(eventmsg);
-
-            if (type == XPC_TYPE_CONNECTION)
-            {
-                LogInfo("init_dnsproxy_service: New DNSProxyService Client %p", eventmsg);
-                accept_dps_client(eventmsg);
-            }
-            else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
-            {
-                LogMsg("init_dnsproxy_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
-                return;
-            }
-            else
-            {
-                LogMsg("init_dnsproxy_service: Unknown EventMsg type");
-                return;
-            }
-        });
-    
-    xpc_connection_resume(dps_listener);
-
-}
-
-mDNSexport void xpc_server_init()
-{
-    // Add XPC Services here
-    init_dnsproxy_service();
-    init_dnsctl_service();
-}
-
-
-#else // !UNICAST_DISABLED
-
-mDNSexport void xpc_server_init()
-{
-    return;
-}
-
-mDNSexport void xpcserver_info(mDNS *const m)
-{
-    (void) m;
-    
-    return;
-}
-
-#endif // !UNICAST_DISABLED
-
diff --git a/mDNSMacOSX/Private/xpc_services.h b/mDNSMacOSX/Private/xpc_services.h
deleted file mode 100644 (file)
index 8d7c043..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2012 Apple Inc. All rights reserved.
- *
- *
- *
- *    File:       xpc_services.h
- *
- *    Contains:   Interfaces necessary to talk to xpc_services.c
- *
- */
-
-#ifndef XPC_SERVICES_H
-#define XPC_SERVICES_H
-
-#include "mDNSEmbeddedAPI.h"
-#include <xpc/xpc.h>
-
-extern void xpc_server_init(void);
-extern void xpcserver_info(mDNS *const m);
-
-extern mDNSBool IsEntitled(xpc_connection_t conn, const char *password);
-extern void init_dnsctl_service(void);
-
-extern void INFOCallback(void);
-
-#endif // XPC_SERVICES_H
index bda53ba8e8a1bb99eac9e0ca53f2bbf00ec45d22..af226760f9bd49387bc448a4c970e6b09b4ce6ca 100755 (executable)
@@ -1,13 +1,26 @@
 #! /bin/bash
 #
-#      Copyright (c) 2017-2018 Apple Inc. All rights reserved.
+#      Copyright (c) 2017-2019 Apple Inc. All rights reserved.
 #
 #      This script is currently for Apple Internal use only.
 #
 
-version=1.4
-script=${BASH_SOURCE[0]}
-dnssdutil=${dnssdutil:-dnssdutil}
+declare -r version=1.6
+declare -r script=${BASH_SOURCE[0]}
+declare -r dnssdutil=${dnssdutil:-dnssdutil}
+
+# The serviceTypesOfInterest array is initialized with commonly-debugged service types or service types whose records can
+# provide useful debugging information, e.g., _airport._tcp in case an AirPort base station is a WiFi network's access
+# point. Note: Additional service types can be added with the '-s' option.
+
+serviceTypesOfInterest=(
+       _airplay._tcp                   # AirPlay
+       _airport._tcp                   # AirPort Base Station
+       _companion-link._tcp    # Companion Link
+       _hap._tcp                               # HomeKit Accessory Protocol
+       _homekit._tcp                   # HomeKit
+       _raop._tcp                              # Remote Audio Output Protocol
+)
 
 #============================================================================================================================
 #      PrintUsage
@@ -19,6 +32,7 @@ PrintUsage()
        echo "Usage: $( basename "${script}" ) [options]"
        echo ""
        echo "Options:"
+       echo "    -s    Specifies a service type of interest, e.g., _airplay._tcp, _raop._tcp, etc. Can be used more than once."
        echo "    -V    Display version of this script and exit."
        echo ""
 }
@@ -78,6 +92,20 @@ ExitHandler()
        fi
 }
 
+#============================================================================================================================
+#      GetStateDump
+#============================================================================================================================
+
+GetStateDump()
+{
+       local suffix=''
+       if [ -n "${1}" ]; then
+               suffix="-${1//[^A-Za-z0-9._-]/_}"
+       fi
+       LogMsg "Getting mDNSResponder state dump."
+       dns-sd -O -stdout &> "${workPath}/state-dump${suffix}.txt"
+}
+
 #============================================================================================================================
 #      RunNetStat
 #============================================================================================================================
@@ -97,6 +125,8 @@ StartPacketCapture()
        LogMsg "Starting tcpdump."
        tcpdump -n -w "${workPath}/tcpdump.pcapng" &> "${workPath}/tcpdump.txt" &
        tcpdumpPID=$!
+       tcpdump -i lo0 -n -w "${workPath}/tcpdump-loopback.pcapng" &> "${workPath}/tcpdump-loopback.txt" 'udp port 5353' &
+       tcpdumpLoopbackPID=$!
 }
 
 #============================================================================================================================
@@ -109,8 +139,8 @@ SaveExistingPacketCaptures()
        mkdir "${workPath}/pcaps"
        for file in /tmp/mdns-tcpdump.pcapng*; do
                [ -e "${file}" ] || continue
-               baseName=$( sed -E 's/^mdns-tcpdump.pcapng([0-9]+)$/mdns-tcpdump-\1.pcapng/' <<< "$( basename ${file} )" )
-               gzip < ${file} > "${workPath}/pcaps/${baseName}.gz"
+               baseName=$( basename "${file}" | sed -E 's/^mdns-tcpdump.pcapng([0-9]+)$/mdns-tcpdump-\1.pcapng/' )
+               gzip < "${file}" > "${workPath}/pcaps/${baseName}.gz"
        done
 }
 
@@ -121,7 +151,8 @@ SaveExistingPacketCaptures()
 StopPacketCapture()
 {
        LogMsg "Stopping tcpdump."
-       kill -TERM ${tcpdumpPID}
+       kill -TERM "${tcpdumpPID}"
+       kill -TERM "${tcpdumpLoopbackPID}"
 }
 
 #============================================================================================================================
@@ -130,59 +161,72 @@ StopPacketCapture()
 
 RunInterfaceMulticastTests()
 {
-       local ifname="$1"
-       local allHostsV4=224.0.0.1
-       local allHostsV6=ff02::1
-       local mDNSV4=224.0.0.251
-       local mDNSV6=ff02::fb
-       local serviceList=( $( "${dnssdutil}" queryrecord -i "${ifname}" -A -t ptr -n _services._dns-sd._udp.local -l 6 | sed -E -n 's/.*(_.*_(tcp|udp)\.local\.)$/\1/p' | sort -u ) )
-       local log="${workPath}/mcast-test-log-${ifname}.txt"
+       local -r ifname=${1}
+       local -r allHostsV4=224.0.0.1
+       local -r allHostsV6=ff02::1
+       local -r mDNSV4=224.0.0.251
+       local -r mDNSV6=ff02::fb
+       local -r log="${workPath}/mcast-test-log-${ifname}.txt"
+       local serviceList=( $( "${dnssdutil}" queryrecord -i "${ifname}" -A -t ptr -n _services._dns-sd._udp.local -l 6 | sed -E -n 's/.*(_.*_(tcp|udp)\.local\.)$/\1/p' ) )
+       serviceList+=( "${serviceTypesOfInterest[@]/%/.local.}" )
+       serviceList=( $( IFS=$'\n' sort -f -u <<< "${serviceList[*]}" ) )
        
        LogOut "List of services: ${serviceList[*]}" >> "${log}"
+       
+       # Ping IPv4 broadcast address.
+       
+       local broadcastAddr=$( ifconfig "${ifname}" inet | awk '$5 == "broadcast" {print $6}' )
+       if [ -n "${broadcastAddr}" ]; then
+               LogOut "Pinging ${broadcastAddr} on interface ${ifname}." >> "${log}"
+               ping -t 5 -b "${ifname}" "${broadcastAddr}" &> "${workPath}/ping-broadcast-${ifname}.txt"
+       else
+               LogOut "No IPv4 broadcast address for ${ifname}." >> "${log}"
+       fi
+       
        # Ping All Hosts IPv4 multicast address.
        
-       local routeOutput=$( route -n get -ifscope ${ifname} "${allHostsV4}" 2> /dev/null )
+       local routeOutput=$( route -n get -ifscope "${ifname}" "${allHostsV4}" 2> /dev/null )
        if [ -n "${routeOutput}" ]; then
-               LogOut "Pinging "${allHostsV4}" on interface ${ifname}." >> "${log}"
-               ping -t 5 -b ${ifname} "${allHostsV4}" &> "${workPath}/ping-all-hosts-${ifname}.txt"
+               LogOut "Pinging ${allHostsV4} on interface ${ifname}." >> "${log}"
+               ping -t 5 -b "${ifname}" "${allHostsV4}" &> "${workPath}/ping-all-hosts-${ifname}.txt"
        else
-               LogOut "No route to "${allHostsV4}" on interface ${ifname}." >> "${log}"
+               LogOut "No route to ${allHostsV4} on interface ${ifname}." >> "${log}"
        fi
        
        # Ping mDNS IPv4 multicast address.
        
-       routeOutput=$( route -n get -ifscope ${ifname} "${mDNSV4}" 2> /dev/null )
+       routeOutput=$( route -n get -ifscope "${ifname}" "${mDNSV4}" 2> /dev/null )
        if [ -n "${routeOutput}" ]; then
-               LogOut "Pinging "${mDNSV4}" on interface ${ifname}." >> "${log}"
-               ping -t 5 -b ${ifname} "${mDNSV4}" &> "${workPath}/ping-mDNS-${ifname}.txt"
+               LogOut "Pinging ${mDNSV4} on interface ${ifname}." >> "${log}"
+               ping -t 5 -b "${ifname}" "${mDNSV4}" &> "${workPath}/ping-mDNS-${ifname}.txt"
        else
-               LogOut "No route to "${mDNSV4}" on interface ${ifname}." >> "${log}"
+               LogOut "No route to ${mDNSV4} on interface ${ifname}." >> "${log}"
        fi
        
        # Ping All Hosts IPv6 multicast address.
        
-       routeOutput=$( route -n get -ifscope ${ifname} -inet6 "${allHostsV6}" 2> /dev/null )
+       routeOutput=$( route -n get -ifscope "${ifname}" -inet6 "${allHostsV6}" 2> /dev/null )
        if [ -n "${routeOutput}" ]; then
-               LogOut "Pinging "${allHostsV6}" on interface ${ifname}." >> "${log}"
-               ping6 -c 6 -I ${ifname} "${allHostsV6}" &> "${workPath}/ping6-all-hosts-${ifname}.txt"
+               LogOut "Pinging ${allHostsV6} on interface ${ifname}." >> "${log}"
+               ping6 -c 6 -I "${ifname}" "${allHostsV6}" &> "${workPath}/ping6-all-hosts-${ifname}.txt"
        else
-               LogOut "No route to "${allHostsV6}" on interface ${ifname}." >> "${log}"
+               LogOut "No route to ${allHostsV6} on interface ${ifname}." >> "${log}"
        fi
        
        # Ping mDNS IPv6 multicast address.
        
-       routeOutput=$( route -n get -ifscope ${ifname} -inet6 "${mDNSV6}" 2> /dev/null )
+       routeOutput=$( route -n get -ifscope "${ifname}" -inet6 "${mDNSV6}" 2> /dev/null )
        if [ -n "${routeOutput}" ]; then
-               LogOut "Pinging "${mDNSV6}" on interface ${ifname}." >> "${log}"
-               ping6 -c 6 -I ${ifname} "${mDNSV6}" &> "${workPath}/ping6-mDNS-${ifname}.txt"
+               LogOut "Pinging ${mDNSV6} on interface ${ifname}." >> "${log}"
+               ping6 -c 6 -I "${ifname}" "${mDNSV6}" &> "${workPath}/ping6-mDNS-${ifname}.txt"
        else
-               LogOut "No route to "${mDNSV6}" on interface ${ifname}." >> "${log}"
+               LogOut "No route to ${mDNSV6} on interface ${ifname}." >> "${log}"
        fi
        
        # Send mDNS queries for services.
        
        for service in "${serviceList[@]}"; do
-               LogOut "Sending mDNS queries for "${service}" on interface ${ifname}." >> "${log}"
+               LogOut "Sending mDNS queries for ${service} on interface ${ifname}." >> "${log}"
                for(( i = 1; i <= 3; ++i )); do
                        printf "\n"
                        "${dnssdutil}" mdnsquery -i "${ifname}" -n "${service}" -t ptr -r 2
@@ -199,35 +243,36 @@ RunInterfaceMulticastTests()
 
 RunMulticastTests()
 {
-       local interfaces=( $( ifconfig -l -u ) )
-       local skipPrefixes=( ap awdl bridge ipsec lo p2p pdp_ip pktap UDC utun )
-       local ifname=""
-       local pid=""
-       local pids=()
+       local -r interfaces=( $( ifconfig -l -u ) )
+       local -r skipPrefixes=( ap awdl bridge ipsec llw p2p pdp_ip pktap UDC utun )
+       local -a pids
+       local ifname
+       local skip
+       local pid
        
        LogMsg "List of interfaces: ${interfaces[*]}"
        for ifname in "${interfaces[@]}"; do
-               local skip=false
-               for prefix in ${skipPrefixes[@]}; do
+               skip=false
+               for prefix in "${skipPrefixes[@]}"; do
                        if [[ ${ifname} =~ ^${prefix}[0-9]*$ ]]; then
                                skip=true
                                break
                        fi
                done
                
-               if [ "${skip}" != "true" ]; then
-                       ifconfig ${ifname} | grep -q inet
+               if ! "${skip}"; then
+                       ifconfig ${ifname} | egrep -q '\binet6?\b'
                        if [ $? -ne 0 ]; then
                                skip=true
                        fi
                fi
                
-               if [ "${skip}" == "true" ]; then
+               if "${skip}"; then
                        continue
                fi
                
                LogMsg "Starting interface multicast tests for ${ifname}."
-               RunInterfaceMulticastTests "${ifname}" & pids+=($!)
+               RunInterfaceMulticastTests "${ifname}" & pids+=( $! )
        done
        
        LogMsg "Waiting for interface multicast tests to complete..."
@@ -243,7 +288,18 @@ RunMulticastTests()
 
 RunBrowseTest()
 {
-       LogMsg "Running dnssdutil browseAll command."
+       local -a typeArgs
+       
+       if [ "${#serviceTypesOfInterest[@]}" -gt 0 ]; then
+               for serviceType in "${serviceTypesOfInterest[@]}"; do
+                       typeArgs+=( "-t" "${serviceType}" )
+               done
+               
+               LogMsg "Running dnssdutil browseAll command for service types of interest."
+               "${dnssdutil}" browseAll -A -d local -b 10 -c 10 "${typeArgs[@]}" &> "${workPath}/browseAll-STOI.txt"
+       fi
+       
+       LogMsg "Running general dnssdutil browseAll command."
        "${dnssdutil}" browseAll -A -d local -b 10 -c 10 &> "${workPath}/browseAll.txt"
 }
 
@@ -262,8 +318,14 @@ IsMacOS()
 
 ArchiveLogs()
 {
-       local workdir=$( basename "${workPath}" )
-       local archivePath="${dstPath}/${workdir}.tar.gz"
+       local -r workdir=$( basename "${workPath}" )
+       local parentDir
+       if IsMacOS; then
+               parentDir=/var/tmp
+       else
+               parentDir=/var/mobile/Library/Logs/CrashReporter
+       fi
+       local -r archivePath="${parentDir}/${workdir}.tar.gz"
        
        LogMsg "Archiving logs."
        echo "---"
@@ -273,7 +335,7 @@ ArchiveLogs()
                echo "*** Please run sysdiagnose NOW. ***"
                echo "Attach both the log archive and the sysdiagnose archive to the radar."
                if IsMacOS; then
-                       open "${dstPath}"
+                       open "${parentDir}"
                fi
        else
                echo "Failed to create archive at ${archivePath}."
@@ -287,13 +349,13 @@ ArchiveLogs()
 
 CreateWorkDirName()
 {
-       local suffix=""
-       local productName=$( sw_vers -productName )
+       local suffix=''
+       local -r productName=$( sw_vers -productName )
        if [ -n "${productName}" ]; then
                suffix+="_${productName}"
        fi
        
-       local model=""
+       local model
        if IsMacOS; then
                model=$( sysctl -n hw.model )
                model=${model//,/-}
@@ -304,7 +366,7 @@ CreateWorkDirName()
                suffix+="_${model}"
        fi
        
-       local buildVersion=$( sw_vers -buildVersion )
+       local -r buildVersion=$( sw_vers -buildVersion )
        if [ -n "${buildVersion}" ]; then
                suffix+="_${buildVersion}"
        fi
@@ -320,12 +382,20 @@ CreateWorkDirName()
 
 main()
 {
-       while getopts ":hV" option; do
+       while getopts ":s:hV" option; do
                case "${option}" in
                        h)
                                PrintUsage
                                exit 0
                                ;;
+                       s)
+                               serviceType=$( awk '{print tolower($0)}' <<< "${OPTARG}" )
+                               if [[ ${serviceType} =~ ^_[-a-z0-9]*\._(tcp|udp)$ ]]; then
+                                       serviceTypesOfInterest+=( "${serviceType}" )
+                               else
+                                       ErrQuit "Service type '${OPTARG}' is malformed."
+                               fi
+                               ;;
                        V)
                                echo "$( basename "${script}" ) version ${version}"
                                exit 0
@@ -339,17 +409,15 @@ main()
                esac
        done
        
-       [ "${OPTIND}" -gt "$#" ] || ErrQuit "unexpected argument \""${!OPTIND}"\"."
+       [ "${OPTIND}" -gt "$#" ] || ErrQuit "unexpected argument \"${!OPTIND}\"."
        
        if IsMacOS; then
                if [ "${EUID}" -ne 0 ]; then
                        echo "Re-launching with sudo"
-                       exec sudo ${script}
+                       exec sudo "${script}" "$@"
                fi
-               dstPath=/var/tmp
        else
                [ "${EUID}" -eq 0 ] || ErrQuit "$( basename "${script}" ) needs to be run as root."
-               dstPath=/var/mobile/Library/Logs/CrashReporter
        fi
        
        tempPath=$( mktemp -d -q ) || ErrQuit "Failed to make temp directory."
@@ -359,7 +427,7 @@ main()
        trap SignalHandler      SIGINT SIGTERM
        trap ExitHandler        EXIT
        
-       LogMsg "About: $( basename "${script}" ) version ${version} ($( md5 -q ${script} ))."
+       LogMsg "About: $( basename "${script}" ) version ${version} ($( md5 -q "${script}" ))."
        if [ "${dnssdutil}" != "dnssdutil" ]; then
                if [ -x "$( which "${dnssdutil}" )" ]; then
                        LogMsg "Using $( "${dnssdutil}" -V ) at $( which "${dnssdutil}" )."
@@ -368,11 +436,15 @@ main()
                fi
        fi
        
+       serviceTypesOfInterest=( $( IFS=$'\n' sort -u <<< "${serviceTypesOfInterest[*]}" ) )
+       
+       GetStateDump 'before'
        RunNetStat
        StartPacketCapture
        SaveExistingPacketCaptures
        RunBrowseTest
        RunMulticastTests
+       GetStateDump 'after'
        StopPacketCapture
        ArchiveLogs
 }
index 7dde2f5ed63fc462dc9a2f248431273c738979b4..9cb08e54022790bc57a8a8c2cb5b6d11ba0e791f 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2015-2019 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.
@@ -15,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "mDNSEmbeddedAPI.h"
+#include "SymptomReporter.h"
 
 #include <arpa/inet.h>
 #include <dlfcn.h>
 #include <stdint.h>
 #include <sys/socket.h>
 #include <AvailabilityMacros.h>
-#include <TargetConditionals.h>
-
-#define TARGET_OS_MACOSX    (TARGET_OS_MAC && !TARGET_OS_IPHONE)
-
-#if (!TARGET_OS_MACOSX || (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
 #include <SymptomReporter/SymptomReporter.h>
-#else
-#include <Symptoms/SymptomReporter.h>
-#endif
 
 #define SYMPTOM_REPORTER_mDNSResponder_NUMERIC_ID  101
 #define SYMPTOM_REPORTER_mDNSResponder_TEXT_ID     "com.apple.mDNSResponder"
@@ -39,6 +30,8 @@
 #define SYMPTOM_DNS_NO_REPLIES          0x00065001
 #define SYMPTOM_DNS_RESUMED_RESPONDING  0x00065002
 
+mDNSu32 NumUnreachableDNSServers;
+
 static symptom_framework_t symptomReporter = mDNSNULL;
 static symptom_framework_t (*symptom_framework_init_f)(symptom_ident_t id, const char *originator_string) = mDNSNULL;
 static symptom_t (*symptom_new_f)(symptom_framework_t framework, symptom_ident_t id) = mDNSNULL;
@@ -50,11 +43,7 @@ mDNSlocal mStatus SymptomReporterInitCheck(void)
     mStatus err;
     static mDNSBool triedInit = mDNSfalse;
     static void *symptomReporterLib = mDNSNULL;
-#if (!TARGET_OS_MACOSX || (MAC_OS_X_VERSION_MAX_ALLOWED >= 101200))
     static const char path[] = "/System/Library/PrivateFrameworks/SymptomReporter.framework/SymptomReporter";
-#else
-    static const char path[] = "/System/Library/PrivateFrameworks/Symptoms.framework/Frameworks/SymptomReporter.framework/SymptomReporter";
-#endif
 
     if (!triedInit)
     {
@@ -95,7 +84,8 @@ mDNSlocal mStatus SymptomReporterReportDNSReachability(const mDNSAddr *addr, mDN
     struct sockaddr_storage sockAddr;
     size_t sockAddrSize;
 
-    LogInfo("SymptomReporterReportDNSReachability: DNS server %#a is %sreachable", addr, isReachable ? "" : "un");
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+        "SymptomReporterReportDNSReachability: DNS server " PRI_IP_ADDR " is " PUB_S "reachable", addr, isReachable ? "" : "un");
 
     if (addr->type == mDNSAddrType_IPv4)
     {
@@ -117,7 +107,8 @@ mDNSlocal mStatus SymptomReporterReportDNSReachability(const mDNSAddr *addr, mDN
     }
     else
     {
-        LogMsg("SymptomReporterReportDNSReachability: addr is not an IPv4 or IPv6 address!");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+            "SymptomReporterReportDNSReachability: addr is not an IPv4 or IPv6 address!");
         err = mStatus_BadParamErr;
         goto exit;
     }
@@ -143,11 +134,11 @@ mDNSexport mStatus SymptomReporterDNSServerReachable(mDNS *const m, const mDNSAd
 
     for (s = m->DNSServers; s; s = s->next)
     {
-        if (s->flags & DNSServer_FlagDelete)
+        if (s->flags & DNSServerFlag_Delete)
             continue;
-        if ((s->flags & DNSServer_FlagUnreachable) && mDNSSameAddress(addr, &s->addr))
+        if ((s->flags & DNSServerFlag_Unreachable) && mDNSSameAddress(addr, &s->addr))
         {
-            s->flags &= ~DNSServer_FlagUnreachable;
+            s->flags &= ~DNSServerFlag_Unreachable;
             NumUnreachableDNSServers--;
             found = mDNStrue;
         }
@@ -173,10 +164,10 @@ mDNSexport mStatus SymptomReporterDNSServerUnreachable(DNSServer *s)
     if (err != mStatus_NoError)
         goto exit;
 
-    if ((s->flags & DNSServer_FlagDelete) || (s->flags & DNSServer_FlagUnreachable))
+    if ((s->flags & DNSServerFlag_Delete) || (s->flags & DNSServerFlag_Unreachable))
         goto exit;
 
-    s->flags |= DNSServer_FlagUnreachable;
+    s->flags |= DNSServerFlag_Unreachable;
     NumUnreachableDNSServers++;
 
     err = SymptomReporterReportDNSReachability(&s->addr, mDNSfalse);
diff --git a/mDNSMacOSX/SymptomReporter.h b/mDNSMacOSX/SymptomReporter.h
new file mode 100644 (file)
index 0000000..5cde328
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#ifndef __SymptomReporter_h
+#define __SymptomReporter_h
+
+#include "mDNSEmbeddedAPI.h"
+
+extern mDNSu32 NumUnreachableDNSServers;
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+extern mStatus SymptomReporterDNSServerReachable(mDNS *const m, const mDNSAddr *addr);
+extern mStatus SymptomReporterDNSServerUnreachable(DNSServer *s);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif // __SymptomReporter_h
diff --git a/mDNSMacOSX/Tests/BATS Scripts/bats_test_proxy.sh b/mDNSMacOSX/Tests/BATS Scripts/bats_test_proxy.sh
new file mode 100755 (executable)
index 0000000..03e0bdf
--- /dev/null
@@ -0,0 +1,105 @@
+#!/bin/sh
+#
+# bats_test_proxy.sh
+# mDNSResponder Tests
+#
+# Copyright (c) 2019 Apple Inc. All rights reserved.
+
+# tests whether the state dump will create at most MAX_NUM_DUMP_FILES, to avoid wasting too much space.
+base_test="dnssdutil dnsquery -s 127.0.0.1 -n apple.com -t a"
+
+# Enable the proxy and test over TCP
+function test_proxy_tcp {
+    test_proxy_on $base_test --tcp
+    return $?
+}
+
+# Enable the proxy and test over UDP
+function test_proxy_udp {
+    test_proxy_on $base_test
+    return $?
+}
+
+# Test the proxy over TCP without enabling it (should fail)
+function test_noproxy_tcp {
+    test_proxy $base_test --tcp
+    if [ $? == 0 ]; then
+        return 1;
+    fi
+    return 0
+}
+
+# Test the proxy over UDP without enabling it (should fail)
+function test_noproxy_udp {
+    test_proxy $base_test
+    if [ $? == 0 ]; then
+        return 1;
+    fi
+    return 0
+}
+
+function test_proxy_on {
+    local command_line="$*"
+    local ret=1
+    
+    # Enable the proxy
+    dnssdutil dnsproxy -i lo0 &
+    local dnssdutil_pid=$!
+
+    # See if that worked
+    sleep 1
+    local dnssdutil_pid_now=$(ps xa |sed -n -e 's/^ *\([0-9][0-9]*\).*$/\1/' -e "/$dnssdutil_pid/p")
+    if [ $dnssdutil_pid != "$dnssdutil_pid_now" ]; then
+        echo "Failed to enable DNS proxy $dnssdutil_pid $dnssdutil_pid_now."
+        return 1
+    fi
+    
+    test_proxy $command_line
+    ret=$?
+
+    # Disable the proxy and wait for that to finish
+    kill -HUP $dnssdutil_pid
+    wait $dnssdutil_pid
+    return $ret
+}
+
+function test_proxy {
+    local command_line="$*"
+    local ret=1
+    # Try to do the DNS lookup
+    local output=$($command_line |egrep "^End reason:")
+    if [ "$output" = "End reason: received response" ]; then
+        echo "Proxy is working: $output"
+        ret=0
+    else
+        echo "Proxy is not working: $output"
+    fi
+    return $ret
+}
+
+ret=0
+# Functions are put inside an array, use ($test) to evaluate it
+declare -a tests=("test_proxy_tcp"
+                  "test_proxy_udp"
+                  "test_noproxy_tcp"
+                  "test_noproxy_udp")
+echo ""
+echo "----Proxy Test Start, $(date)----"
+for test in "${tests[@]}"; do
+    echo "running $test:"
+    ($test)
+    if [[ $? -eq 0 ]]; then
+        echo "passed"$'\n' # use $'\n' to print one more newline character
+    else
+        ret=1
+        echo "failed"$'\n'
+    fi
+done
+echo "----Proxy Test End, $(date)----"
+exit $ret
+
+# Local Variables:
+# tab-width: 4
+# fill-column: 108
+# indent-tabs-mode: nil
+# End:
diff --git a/mDNSMacOSX/Tests/BATS Scripts/bats_test_state_dump.sh b/mDNSMacOSX/Tests/BATS Scripts/bats_test_state_dump.sh
new file mode 100644 (file)
index 0000000..fde40e0
--- /dev/null
@@ -0,0 +1,172 @@
+#!/bin/sh
+#
+# bats_test_state_dump.sh
+# mDNSResponder Tests
+#
+# Copyright (c) 2019 Apple Inc. All rights reserved.
+
+
+# trigger state dump
+function triger_state_dump {
+    local command_line="$1"
+    output="$($command_line)"
+    if [[ $? -ne 0 ]]; then
+        printf "dns-sd -O exit with non-zero return value, the returned error message is:\n"
+        echo $output
+        return 1
+    fi
+    return 0
+}
+
+# trigger state dump and check if the file is created successfully
+function triger_state_dump_and_check_file {
+    # $1 is the command line used to trigger state dump
+    triger_state_dump "$1"
+    if [[ $? -ne 0 ]]; then
+        return 1
+    fi
+    # the returned result is like the following:
+    # State Dump Is Saved to: /private/var/log/mDNSResponder/mDNSResponder_state_dump_2019-03-01_17-07-10-260-08-00.txt
+    #              Time Used: 33 ms
+    # splited the result with '\n'
+    IFS=$'\n' read -r -d '' -a line_being_read <<< "$output"
+    # ${line_being_read[0]} contains "State Dump Is Saved to: /private/var/log/mDNSResponder/mDNSResponder_state_dump_2019-03-01_17-07-10-260-08-00.txt"
+    IFS=":" read -r -d '' -a line_being_splitted <<< "${line_being_read[0]}"
+    # get the path "/private/var/log/mDNSResponder/mDNSResponder_state_dump_2019-03-01_17-07-10-260-08-00.txt"
+    file_name=$(echo "${line_being_splitted[1]}" | xargs)
+    # check if the file exists in the disk
+    if [ ! -f $file_name ]; then
+        printf "State dump is not created under %s\n" $file_name
+        return 1
+    fi
+    return 0
+}
+
+# verify that the state dump contains the full content
+function verify_state_dump_content {
+    # the passed parameter is the file content to be checked
+    local file="$1"
+    # the first line of file should start with "---- BEGIN STATE LOG ----"
+    local file_start_string="---- BEGIN STATE LOG ----"
+    if [[ ! "$file" == "$file_start_string"* ]]; then
+        printf "State dump file does not start with %s\n" "$file_start_string"
+        return 1
+    fi
+
+    # the last line of file should start with "----  END STATE LOG  ----"
+    local last_line=$(echo "$file" | tail -n1)
+    local file_end_string="----  END STATE LOG  ----"
+    if [[ ! "$last_line" == "$file_end_string"* ]]; then
+        printf "State dump file does not end with %s\n" "$file_end_string"
+        return 1
+    fi
+
+    return 0
+}
+
+function test_check_dump_directory {
+    local dump_path="/private/var/log/mDNSResponder"
+    if [ ! -d "$dump_path" ]; then
+        printf "Directory \"%s\" does not exist\n" $dump_path
+        return 1
+    fi
+    local permission=$(stat -f "%OLp" $dump_path)
+    if [ ! $permission == "755" ]; then
+        printf "Directory \"%s\" has incorrect permission. expected=755; actual=%s\n" $dump_path $permission
+        return 1
+    fi
+    local owner=$(ls -ld $dump_path | awk '{print $3}')
+    if [ ! $owner == "_mdnsresponder" ]; then
+        printf "Directory \"%s\" has incorrect owner. expected=_mdnsresponder; actual=%s\n" $dump_path "$owner"
+        return 1
+    fi
+    return 0
+}
+
+function test_output_to_plain_txt_file {
+    triger_state_dump_and_check_file "dns-sd -O"
+    if [[ $? -ne 0 ]]; then
+        return 1
+    fi
+    # get the file content
+    local file_content=$(cat $file_name)
+    verify_state_dump_content "$file_content" && rm "$file_name"
+    return $?
+}
+
+# tests if "dns-sd -O -compress" works as expected
+function test_output_to_archive {
+    triger_state_dump_and_check_file "dns-sd -O -compress"
+    if [[ $? -ne 0 ]]; then
+        return 1
+    fi
+    # get the uncompressed file name
+    local file_name_uncompressed=$(tar -tf "$file_name")
+    # unzip the file
+    tar -xf "$file_name" --directory /tmp/
+    # get the file content
+    local file_content=$(cat "/tmp/$file_name_uncompressed")
+    verify_state_dump_content "$file_content" && rm "$file_name" && rm "/tmp/$file_name_uncompressed"
+    return $?
+}
+
+# tests if "dns-sd -O -stdout" works as expected
+function test_output_to_stdout {
+    triger_state_dump "dns-sd -O -stdout"
+    if [[ $? -ne 0 ]]; then
+        return 1
+    fi
+    # delete the last line of output, which is "             Time Used: <time> ms"
+    output=$(echo "$output" | sed '$d')
+    verify_state_dump_content "$output"
+    return $?
+}
+
+# tests whether the state dump will create at most MAX_NUM_DUMP_FILES, to avoid wasting too much space.
+function test_dump_limit {
+    # calls "dns-sd -O -compress" for 10 times
+    local counter=1
+    while [ $counter -le 10 ]
+    do
+        triger_state_dump_and_check_file "dns-sd -O -compress"
+        if [[ $? -ne 0 ]];then
+            return 1;
+        fi
+        ((counter++))
+    done
+
+    # $file_name is already initialized when we call "dns-sd -O -compress" above
+    local directory=$(dirname "$file_name")
+    # get the number of files under $directory
+    local file_count=$(ls -Uba1 "$directory" | grep ^mDNSResponder_state_dump_ | wc -l | xargs)
+    # clean up the directory
+    rm -rf ${directory}/*
+    # the number of files should be MAX_NUM_DUMP_FILES, which is defined as 5 in mDNSResponder
+    if [[ $file_count -eq 5 ]]; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+ret=0
+# Functions are put inside an array, use ($test) to evaluate it
+declare -a tests=("test_check_dump_directory"
+                  "test_output_to_plain_txt_file"
+                  "test_output_to_archive"
+                  "test_output_to_stdout"
+                  "test_dump_limit")
+echo ""
+echo "----State Dump Test Start, $(date)----"
+for test in "${tests[@]}"; do
+    echo "running $test:"
+    ($test)
+    if [[ $? -eq 0 ]]; then
+        echo "passed"$'\n' # use $'\n' to print one more newline character
+    else
+        ret=1
+        echo "failed"$'\n'
+    fi
+done
+echo "----State Dump Test End, $(date)----"
+exit $ret
diff --git a/mDNSMacOSX/Tests/CNameRecordTest.m b/mDNSMacOSX/Tests/CNameRecordTest.m
new file mode 100644 (file)
index 0000000..873561d
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#include "unittest_common.h"
+#import <XCTest/XCTest.h>
+
+struct UDPSocket_struct
+{
+       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
+};
+typedef struct UDPSocket_struct UDPSocket;
+
+// This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A".
+uint8_t query_client_msgbuf[35] = {
+       0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
+       0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
+       0x01, 0x00, 0x01
+};
+
+// This uDNS message is a canned response that was originally captured by wireshark.
+uint8_t query_response_msgbuf[108] = {
+    0x69, 0x41, // transaction id
+       0x85, 0x80, // flags
+       0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr
+       0x00, 0x02,     // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1,
+       0x00, 0x01,     // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com.
+       0x00, 0x00, 0x09, 0x31, 0x32, 0x33,
+    0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03,
+    0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
+    0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34,
+    0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16,
+    0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69,
+    0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f
+};
+
+// Variables associated with contents of the above uDNS message
+#define uDNS_TargetQID 16745
+char udns_original_domainname_cstr[] = "123server.dotbennu.com.";
+char udns_cname_domainname_cstr[] = "test212.dotbennu.com.";
+//static const mDNSv4Addr dns_response_ipv4 = {{ 10, 100, 0, 1 }};
+
+@interface CNameRecordTest : XCTestCase
+{
+    UDPSocket* local_socket;
+    request_state* client_request_message;}
+@end
+
+@implementation CNameRecordTest
+
+// The InitThisUnitTest() initializes the mDNSResponder environment as well as
+// a DNSServer. It also allocates memory for a local_socket and client request.
+// Note: This unit test does not send packets on the wire and it does not open sockets.
+- (void)setUp
+{
+    // Init unit test environment and verify no error occurred.
+    mStatus result = init_mdns_environment(mDNStrue);
+    XCTAssertEqual(result, mStatus_NoError);
+    
+    // Add one DNS server and verify it was added.
+    AddDNSServer_ut();
+    XCTAssertEqual(CountOfUnicastDNSServers(&mDNSStorage), 1);
+    
+    // Create memory for a socket that is never used or opened.
+    local_socket = (UDPSocket *) mDNSPlatformMemAllocateClear(sizeof(*local_socket));
+    
+    // Create memory for a request that is used to make this unit test's client request.
+    client_request_message = calloc(1, sizeof(request_state));
+}
+
+- (void)tearDown
+{
+    mDNS *m = &mDNSStorage;
+    request_state* req = client_request_message;
+    DNSServer   *ptr, **p = &m->DNSServers;
+    
+    while (req->replies)
+    {
+        reply_state *reply = req->replies;
+        req->replies = req->replies->next;
+        mDNSPlatformMemFree(reply);
+    }
+    mDNSPlatformMemFree(req);
+    
+    mDNSPlatformMemFree(local_socket);
+    
+    while (*p)
+    {
+        ptr = *p;
+        *p = (*p)->next;
+        LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
+        mDNSPlatformMemFree(ptr);
+    }
+}
+
+// This test simulates a uds client request by setting up a client request and then
+// calling mDNSResponder's handle_client_request.  The handle_client_request function
+// processes the request and starts a query.  This unit test verifies
+// the client request and query were setup as expected.  This unit test also calls
+// mDNS_execute which determines the cache does not contain the new question's
+// answer.
+- (void)testStartClientQueryRequest
+{
+    mDNS *const m = &mDNSStorage;
+    request_state* req = client_request_message;
+    char *msgptr = (char *)query_client_msgbuf;
+    size_t msgsz = sizeof(query_client_msgbuf);
+    mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+    DNSQuestion *q;
+    mStatus err = mStatus_NoError;
+    char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+    
+    // Process the unit test's client request
+    start_client_request(req, msgptr, msgsz, query_request, local_socket);
+    XCTAssertEqual(err, mStatus_NoError);
+    
+    // Verify the request fields were set as expected
+    XCTAssertNil((__bridge id)req->next);
+    XCTAssertNil((__bridge id)req->primary);
+    XCTAssertEqual(req->sd, client_req_sd);
+    XCTAssertEqual(req->process_id, client_req_process_id);
+    XCTAssertFalse(strcmp(req->pid_name, client_req_pid_name));
+    XCTAssertEqual(req->validUUID, mDNSfalse);
+    XCTAssertEqual(req->errsd, 0);
+    XCTAssertEqual(req->uid, client_req_uid);
+    XCTAssertEqual(req->ts, t_complete);
+    XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
+    XCTAssertEqual(req->msgend, msgptr+msgsz);
+    XCTAssertNil((__bridge id)(void*)req->msgbuf);
+    XCTAssertEqual(req->hdr.version, VERSION);
+    XCTAssertNil((__bridge id)req->replies);
+    XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
+    XCTAssertEqual(req->flags, kDNSServiceFlagsReturnIntermediates);
+    XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexAny);
+    
+    // Verify the query fields were set as expected
+    q = &req->u.queryrecord.op.q;
+    XCTAssertNotEqual(q, (DNSQuestion *)mDNSNULL);
+    XCTAssertEqual(q, m->Questions);
+    XCTAssertEqual(q, m->NewQuestions);
+    XCTAssertEqual(q->SuppressUnusable, mDNSfalse);
+    XCTAssertEqual(q->ReturnIntermed, mDNStrue);
+    XCTAssertEqual(q->Suppressed, mDNSfalse);
+    
+    ConvertDomainNameToCString(&q->qname, qname_cstr);
+    XCTAssertFalse(strcmp(qname_cstr, udns_original_domainname_cstr));
+    XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+    
+    XCTAssertEqual(q->InterfaceID, mDNSInterface_Any);
+    XCTAssertEqual(q->flags, req->flags);
+    XCTAssertEqual(q->qtype, 1);
+    XCTAssertEqual(q->qclass, 1);
+    XCTAssertEqual(q->LongLived, 0);
+    XCTAssertEqual(q->ExpectUnique, mDNSfalse);
+    XCTAssertEqual(q->ForceMCast, 0);
+    XCTAssertEqual(q->TimeoutQuestion, 0);
+    XCTAssertEqual(q->WakeOnResolve, 0);
+    XCTAssertEqual(q->UseBackgroundTraffic, 0);
+    XCTAssertEqual(q->ValidationRequired, 0);
+    XCTAssertEqual(q->ValidatingResponse, 0);
+    XCTAssertEqual(q->ProxyQuestion, 0);
+    XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
+    XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
+    XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
+    XCTAssertEqual(q->AppendSearchDomains, 0);
+    XCTAssertNil((__bridge id)q->DuplicateOf);
+    
+    // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
+    // It won't be yet because the cache is empty.
+    m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+    mDNS_Execute(m);
+    
+    // Verify mDNS_Execute processed the new question.
+    XCTAssertNil((__bridge id)m->NewQuestions);
+    
+    // Verify the cache is empty and the request got no reply.
+    XCTAssertEqual(m->rrcache_totalused, 0);
+    XCTAssertNil((__bridge id)req->replies);
+}
+#if 0
+// This unit test receives a canned uDNS response message by calling the mDNSCoreReceive() function.
+// It then verifies cache entries were added for the CNAME and A records that were contained in the
+// answers of the canned response, query_response_msgbuf.  This unit test also verifies that
+// 2 add events were generated for the client.
+- (void)testPopulateCacheWithClientResponseRecords
+{
+    mDNS *const m = &mDNSStorage;
+    DNSMessage *msgptr = (DNSMessage *)query_response_msgbuf;
+    size_t msgsz = sizeof(query_response_msgbuf);
+    struct reply_state *reply;
+    request_state* req = client_request_message;
+    DNSQuestion *q = &req->u.queryrecord.q;
+    const char *data;
+    const char *end;
+    char name[kDNSServiceMaxDomainName];
+    uint16_t rrtype, rrclass, rdlen;
+    const char *rdata;
+    size_t len;
+    char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+    
+    // Receive and populate the cache with canned response
+    receive_response(req, msgptr, msgsz);
+    
+    // Verify 2 cache entries for CName and A record are present
+    mDNSu32 CacheUsed =0, notUsed =0;
+    LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
+    XCTAssertEqual(CacheUsed, m->rrcache_totalused);
+    XCTAssertEqual(CacheUsed, 4); // 2 for the CacheGroup object plus 2 for the A and CNAME records
+    XCTAssertEqual(m->PktNum, 1); // one packet was received
+    
+    // Verify question's qname is now set with the A record's domainname
+    ConvertDomainNameToCString(&q->qname, domainname_cstr);
+    XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+    XCTAssertFalse(strcmp(domainname_cstr, udns_cname_domainname_cstr));
+    
+    // Verify client's add event for CNAME is properly formed
+    reply = req->replies;
+    XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+    XCTAssertNil((__bridge id)reply->next);
+    
+    data    = (char *)&reply->rhdr[1];
+    end     = data+reply->totallen;
+    get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+    rrtype  = get_uint16(&data, end);
+    rrclass = get_uint16(&data, end);
+    rdlen   = get_uint16(&data, end);
+    rdata   = get_rdata(&data, end, rdlen);
+    len     = get_reply_len(name, rdlen);
+    
+    XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+    XCTAssertEqual(reply->mhdr->version, VERSION);
+    XCTAssertEqual(reply->mhdr->datalen, len);
+    XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+    XCTAssertEqual(reply->mhdr->op, query_reply_op);
+    
+    XCTAssertEqual(reply->rhdr->flags, htonl(kDNSServiceFlagsAdd));
+    XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexAny);
+    XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+    
+    XCTAssertEqual(rrtype, kDNSType_CNAME);
+    XCTAssertEqual(rrclass, kDNSClass_IN);
+    ConvertDomainNameToCString((const domainname *const)rdata, domainname_cstr);
+    XCTAssertFalse(strcmp(domainname_cstr, "test212.dotbennu.com."));
+    
+    // The mDNS_Execute call generates an add event for the A record
+    m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+    mDNS_Execute(m);
+    
+    // Verify the client's reply contains a properly formed add event for the A record.
+    reply = req->replies;
+    XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+    XCTAssertNotEqual(reply->next, (reply_state*)mDNSNULL);
+    reply = reply->next;
+    
+    data    = (char *)&reply->rhdr[1];
+    end     = data+reply->totallen;
+    get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+    rrtype  = get_uint16(&data, end);
+    rrclass = get_uint16(&data, end);
+    rdlen   = get_uint16(&data, end);
+    rdata   = get_rdata(&data, end, rdlen);
+    len     = get_reply_len(name, rdlen);
+    
+    XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+    XCTAssertEqual(reply->mhdr->version, VERSION);
+    XCTAssertEqual(reply->mhdr->datalen, len);
+    
+    XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+    XCTAssertEqual(reply->mhdr->op, query_reply_op);
+    
+    XCTAssertEqual(reply->rhdr->flags, htonl(kDNSServiceFlagsAdd));
+    XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexAny);
+    XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+    
+    XCTAssertEqual(rrtype, kDNSType_A);
+    XCTAssertEqual(rrclass, kDNSClass_IN);
+    XCTAssertEqual(rdata[0], dns_response_ipv4.b[0]);
+    XCTAssertEqual(rdata[1], dns_response_ipv4.b[1]);
+    XCTAssertEqual(rdata[2], dns_response_ipv4.b[2]);
+    XCTAssertEqual(rdata[3], dns_response_ipv4.b[3]);
+}
+
+// This function verifies the cache and event handling occurred as expected when a network change happened.
+// The uDNS_SetupDNSConfig is called to simulate a network change and two outcomes occur. First the A record
+// query is restarted and sent to a new DNS server. Second the cache records are purged. Then mDNS_Execute
+// is called and it removes the purged cache records and generates a remove event for the A record.
+// The following are verified:
+//      1.) The restart of query for A record.
+//      2.) The cache is empty after mDNS_Execute removes the cache entres.
+//      3.) The remove event is verified by examining the request's reply data.
+- (void)testSimulateNetworkChangeAndVerify
+{
+    mDNS *const m = &mDNSStorage;
+    request_state*  req = client_request_message;
+    DNSQuestion*    q = &req->u.queryrecord.q;
+    mDNSu32 CacheUsed =0, notUsed =0;
+    const char *data;    const char *end;
+    char name[kDNSServiceMaxDomainName];
+    uint16_t rrtype, rrclass, rdlen;
+    const char *rdata;
+    size_t len;
+    
+    // The uDNS_SetupDNSConfig reconfigures the resolvers so the A record query is restarted and
+    // both the CNAME and A record are purged.
+    uDNS_SetupDNSConfig(m);
+    
+    // Verify the A record query was restarted.  This is done indirectly by noticing the transaction id and interval have changed.
+    XCTAssertEqual(q->ThisQInterval, InitialQuestionInterval);
+    XCTAssertNotEqual(q->TargetQID.NotAnInteger, uDNS_TargetQID);
+    
+    // Then mDNS_Execute removes both records from the cache and calls the client back with a remove event for A record.
+    m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+    mDNS_Execute(m);
+    
+    // Verify the cache entries are removed
+    LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
+    XCTAssertEqual(CacheUsed, m->rrcache_totalused);
+    XCTAssertEqual(CacheUsed, 0);
+    
+    // Verify the A record's remove event is setup as expected in the reply data
+    struct reply_state *reply;
+    reply = req->replies;
+    XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+    XCTAssertNotEqual(reply->next, (reply_state*)mDNSNULL);
+    XCTAssertNotEqual(reply->next->next, (reply_state*)mDNSNULL);
+
+    reply = reply->next->next; // Get to last event to verify remove event
+    data    = (char *)&reply->rhdr[1];
+    end     = data+reply->totallen;
+    get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
+    rrtype  = get_uint16(&data, end);
+    rrclass = get_uint16(&data, end);
+    rdlen   = get_uint16(&data, end);
+    rdata   = get_rdata(&data, end, rdlen);
+    len     = get_reply_len(name, rdlen);
+    
+    XCTAssertEqual(reply->totallen, reply->mhdr->datalen + sizeof(ipc_msg_hdr));
+    XCTAssertEqual(reply->mhdr->version, VERSION);
+    XCTAssertEqual(reply->mhdr->datalen, len);
+    XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+    XCTAssertEqual(reply->mhdr->op, query_reply_op);
+    
+    XCTAssertNotEqual(reply->rhdr->flags, htonl(kDNSServiceFlagsAdd));
+    XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexAny);
+    XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+    
+    XCTAssertEqual(rrtype, kDNSType_A);
+    XCTAssertEqual(rrclass, kDNSClass_IN);
+    XCTAssertEqual(rdata[0], dns_response_ipv4.b[0]);
+    XCTAssertEqual(rdata[1], dns_response_ipv4.b[1]);
+    XCTAssertEqual(rdata[2], dns_response_ipv4.b[2]);
+    XCTAssertEqual(rdata[3], dns_response_ipv4.b[3]);
+}
+#endif
+
+@end
diff --git a/mDNSMacOSX/Tests/DNSMessageTest.m b/mDNSMacOSX/Tests/DNSMessageTest.m
new file mode 100644 (file)
index 0000000..d30e010
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017-2018 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.
+ */
+
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h"
+#import <XCTest/XCTest.h>
+
+@interface DNSMessageTest : XCTestCase
+{
+    DNSMessage *msg;
+}
+@end
+
+@implementation DNSMessageTest
+
+- (void)setUp
+{
+    msg = (DNSMessage *)malloc (sizeof(DNSMessage));
+    XCTAssert(msg != NULL);
+    
+    // message header should be 12 bytes
+    XCTAssertEqual(sizeof(msg->h),        12);
+}
+
+- (void)tearDown
+{
+    XCTAssert(msg != NULL);
+    free(msg);
+}
+
+- (void)testMessageInitialization
+{
+    // Initialize the message
+    InitializeDNSMessage(&msg->h, onesID, QueryFlags);
+    
+    // Check that the message is initialized properly
+    XCTAssertEqual(msg->h.numAdditionals, 0);
+    XCTAssertEqual(msg->h.numAnswers,     0);
+    XCTAssertEqual(msg->h.numQuestions,   0);
+    XCTAssertEqual(msg->h.numAuthorities, 0);
+}
+
+#if 0
+- (void)testPerformanceExample {
+    // This is an example of a performance test case.
+    [self measureBlock:^{
+        // Put the code you want to measure the time of here.
+    }];
+}
+#endif
+
+@end
diff --git a/mDNSMacOSX/Tests/HelperFunctionTest.m b/mDNSMacOSX/Tests/HelperFunctionTest.m
new file mode 100644 (file)
index 0000000..4497a9d
--- /dev/null
@@ -0,0 +1,58 @@
+//
+//  HelperFunctionTest.m
+//  Tests
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#import <XCTest/XCTest.h>
+#include "unittest_common.h"
+
+@interface HelperFunctionTest : XCTestCase
+
+@end
+
+@implementation HelperFunctionTest
+
+- (void)setUp {
+    // It is empty for now.
+}
+
+- (void)tearDown {
+    // It is empty for now.
+}
+
+- (void)testCFStringToDomainLabel {
+    // test_cstring[i][0] is the input
+    // test_cstring[i][1] is the expected correct output
+    static const char * const test_cstring[][2] = {
+        {"short", "short"},
+        {"this-is-a-normal-computer-name", "this-is-a-normal-computer-name"},
+        {"", ""},
+        {"This is an ascii string whose length is more than 63 bytes, where it takes one byte to store every character", "This is an ascii string whose length is more than 63 bytes, whe"},
+        {"यह एक एस्सी स्ट्रिंग है जिसकी लंबाई साठ तीन बाइट्स से अधिक है, जहां यह हर चरित्र को संग्रहीत करने के लिए एक बाइट लेता है", "यह एक एस्सी स्ट्रिंग है "}, // "यह एक एस्सी स्ट्रिंग है " is 62 byte, and "यह एक एस्सी स्ट्रिंग है जि" is more than 63, so the result is expected to truncated to 62 bytes instead of 63 bytes
+        {"वितीय टेस्ट ट्राई टी॰वी॰", "वितीय टेस्ट ट्राई टी॰वी"},
+        {"这是一个超过六十三比特的其中每个中文字符占三比特的中文字符串", "这是一个超过六十三比特的其中每个中文字符占"},
+        {"🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝", "🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝"} // "🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝" is 60 bytes, and "🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝🃝" is more than 63 bytes so the result is expected to be truncated to 60 bytes instead of 64 bytes
+    };
+
+    for (int i = 0, n = sizeof(test_cstring) / sizeof(test_cstring[0]); i < n; i++) {
+        // construct CFString from input
+        CFStringRef name_ref = CFStringCreateWithCString(kCFAllocatorDefault, test_cstring[i][0], kCFStringEncodingUTF8);
+        XCTAssertTrue(name_ref != NULL, @"unit test internal error. {descrption=\"name_ref should be non-NULL.\"}");
+
+        // call the function being tested
+        domainlabel label;
+        mDNSDomainLabelFromCFString_ut(name_ref, &label);
+
+        // Check if the result is correct
+        XCTAssertEqual(label.c[0], strlen(test_cstring[i][1]),
+                       @"name length is not equal. {expect=%d,actual=%d}", strlen(test_cstring[i][1]), label.c[0]);
+        XCTAssertTrue(memcmp(label.c + 1, test_cstring[i][1], label.c[0]) == 0,
+                      @"name is not correctly decoded. {expect='%s',actual='%s'}", test_cstring[i][1], label.c + 1);
+
+        CFRelease(name_ref);
+    }
+}
+
+@end
diff --git a/mDNSMacOSX/Tests/Info.plist b/mDNSMacOSX/Tests/Info.plist
new file mode 100644 (file)
index 0000000..6c40a6c
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>$(DEVELOPMENT_LANGUAGE)</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>BNDL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleVersion</key>
+       <string>1</string>
+</dict>
+</plist>
diff --git a/mDNSMacOSX/Tests/LocalOnlyTimeoutTest.m b/mDNSMacOSX/Tests/LocalOnlyTimeoutTest.m
new file mode 100644 (file)
index 0000000..9e0e952
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2017-2019 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.
+ */
+
+#include "unittest_common.h"
+#include "mDNSMacOSX.h"
+#import <XCTest/XCTest.h>
+
+// This query request message was generated from the following command: "dns-sd -lo -timeout -Q cardinal2.apple.com. A"
+char query_req_msgbuf[33]= {
+       0x00, 0x01, 0x90, 0x00,
+       // DNSServiceFlags.L = (kDNSServiceFlagsReturnIntermediates |kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsTimeout)
+       0xff, 0xff, 0xff, 0xff,
+       // interfaceIndex = mDNSInterface_LocalOnly
+       0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c,
+       0x32, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x00, 0x00, 0x01, 0x00,
+       0x01
+};
+
+mDNSlocal mStatus InitEtcHostsRecords(void)
+{
+    mDNS *m = &mDNSStorage;
+    struct sockaddr_storage hostaddr;
+    
+    AuthHash newhosts;
+    mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
+    
+    memset(&hostaddr, 0, sizeof(hostaddr));
+    get_ip("127.0.0.1", &hostaddr);
+    
+    domainname domain;
+    MakeDomainNameFromDNSNameString(&domain, "localhost");
+    
+    mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+    
+    memset(&hostaddr, 0, sizeof(hostaddr));
+    get_ip("0000:0000:0000:0000:0000:0000:0000:0001", &hostaddr);
+    
+    MakeDomainNameFromDNSNameString(&domain, "localhost");
+    
+    mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+    
+    memset(&hostaddr, 0, sizeof(hostaddr));
+    get_ip("255.255.255.255", &hostaddr);
+    
+    MakeDomainNameFromDNSNameString(&domain, "broadcasthost");
+    
+    mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+    
+    memset(&hostaddr, 0, sizeof(hostaddr));
+    get_ip("17.226.40.200", &hostaddr);
+    
+    MakeDomainNameFromDNSNameString(&domain, "cardinal2.apple.com");
+    
+    mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
+    UpdateEtcHosts_ut(&newhosts);
+    
+    m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+    mDNS_Execute(m);
+    
+    return mStatus_NoError;
+}
+
+@interface LocalOnlyATimeoutTest : XCTestCase
+{
+    request_state* client_request_message;
+    UDPSocket* local_socket;
+    char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+}
+@end
+
+@implementation LocalOnlyATimeoutTest
+
+// The InitUnitTest() initializes a minimal mDNSResponder environment as
+// well as allocates memory for a local_socket and client request.
+// It also sets the domainname_cstr specified in the client's query request.
+// Note: This unit test does not send packets on the wire and it does not open sockets.
+- (void)setUp
+{
+       // Init mDNSStorage
+       mStatus result = init_mdns_storage();
+    XCTAssertEqual(result, mStatus_NoError);
+
+       // Allocate a client request
+       local_socket = (UDPSocket *)calloc(1, sizeof(*local_socket));
+
+       // Allocate memory for a request that is used to make client requests.
+       client_request_message = calloc(1, sizeof(request_state));
+
+       // Init domainname that is used by unit tests
+       strlcpy(domainname_cstr, "cardinal2.apple.com.", sizeof(domainname_cstr));
+}
+
+// This function does memory cleanup and no verification.
+- (void)tearDown
+{
+    mDNSPlatformMemFree(local_socket);
+}
+
+// This unit test starts a local only request for "cardinal2.apple.com.".  It first
+// calls start_client_request to start a query, it then verifies the
+// req and query data structures are set as expected. Next, the cache is verified to
+// be empty by AnswerNewLocalOnlyQuestion() and so results in GenerateNegativeResponse()
+// getting called which sets up a reply with a negative answer in it for the client.
+// On return from mDNS_Execute, the client's reply structure is verified to be set as
+// expected. Lastly the timeout is simulated and mDNS_Execute is called. This results
+// in a call to TimeoutQuestions(). And again, the GenerateNegativeResponse() is called
+// which returns a negative response to the client.  This time the client reply is verified
+// to be setup with a timeout result.
+- (void)testStartLocalOnlyClientQueryRequest
+{
+       mDNS *const m = &mDNSStorage;
+    request_state* req = client_request_message;
+       char *msgptr = (char *)query_req_msgbuf;
+       size_t msgsz = sizeof(query_req_msgbuf);
+       DNSQuestion *q;
+       mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+       mStatus err = mStatus_NoError;
+       char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+       struct reply_state *reply;
+       size_t len;
+
+       // Process the unit test's client request
+       start_client_request(req, msgptr, msgsz, query_request, local_socket);
+       XCTAssertEqual(err, mStatus_NoError);
+
+       // Verify the query initialized and request fields were set as expected
+       XCTAssertEqual(req->hdr.version, VERSION);
+       XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
+       XCTAssertEqual(req->flags, (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
+       XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexLocalOnly);
+    XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
+
+       q = &req->u.queryrecord.op.q;
+       XCTAssertEqual(q, m->NewLocalOnlyQuestions);
+       XCTAssertNil((__bridge id)m->Questions);
+       XCTAssertNil((__bridge id)m->NewQuestions);
+       XCTAssertEqual(q->SuppressUnusable, 1);
+       XCTAssertEqual(q->ReturnIntermed, 1);
+       XCTAssertEqual(q->Suppressed, mDNSfalse);                                                                       // Regress <rdar://problem/27571734>
+
+       ConvertDomainNameToCString(&q->qname, qname_cstr);
+       XCTAssertFalse(strcmp(qname_cstr, domainname_cstr));
+       XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+
+       XCTAssertEqual(q->InterfaceID, mDNSInterface_LocalOnly);
+       XCTAssertEqual(q->flags, req->flags);
+       XCTAssertEqual(q->qtype, 1);
+       XCTAssertEqual(q->qclass, 1);
+       XCTAssertEqual(q->LongLived, 0);
+       XCTAssertEqual(q->ExpectUnique, mDNSfalse);
+       XCTAssertEqual(q->ForceMCast, 0);
+       XCTAssertEqual(q->TimeoutQuestion, 1);
+       XCTAssertEqual(q->WakeOnResolve, 0);
+       XCTAssertEqual(q->UseBackgroundTraffic, 0);
+       XCTAssertEqual(q->ValidationRequired, 0);
+       XCTAssertEqual(q->ValidatingResponse, 0);
+       XCTAssertEqual(q->ProxyQuestion, 0);
+    XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
+       XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
+    XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
+       XCTAssertNotEqual(q->StopTime, 0);
+       XCTAssertEqual(q->AppendSearchDomains, 0);
+    XCTAssertNil((__bridge id)q->DuplicateOf);
+
+       // At this point the the cache is empty. Calling mDNS_Execute will answer the local-only
+       // question with a negative response.
+       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+       mDNS_Execute(m);  // Regress <rdar://problem/28721294>
+
+       // Verify reply is a negative response and error code is set to kDNSServiceErr_NoSuchRecord error.
+       reply = req->replies;
+    XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+
+       XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+       XCTAssertEqual(q->LOAddressAnswers, 0);
+
+       len = get_reply_len(qname_cstr, 0);
+
+       XCTAssertNil((__bridge id)reply->next);
+       XCTAssertEqual(reply->totallen, reply->mhdr->datalen + sizeof(ipc_msg_hdr));
+       XCTAssertEqual(reply->mhdr->version, VERSION);
+       XCTAssertEqual(reply->mhdr->datalen, len);
+       XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+       XCTAssertEqual(reply->mhdr->op, query_reply_op);
+
+    XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+       XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly);       // Regress <rdar://problem/27340874>
+       XCTAssertEqual(reply->rhdr->error,
+                                       (DNSServiceErrorType)htonl(kDNSServiceErr_NoSuchRecord));       // Regress <rdar://problem/24827555>
+
+       // Simulate what udsserver_idle normally does for clean up
+       freeL("StartLocalOnlyClientQueryRequest:reply", reply);
+       req->replies = NULL;
+
+       // Simulate the query time out of the local-only question.
+       // The expected behavior is a negative answer with time out error
+       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+       q->StopTime = mDNS_TimeNow_NoLock(m);
+       m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
+       mDNS_Execute(m);
+
+       // Verify the reply is a negative response with timeout error.
+       reply = req->replies;
+    XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+    XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+    XCTAssertEqual(q->LOAddressAnswers, 0);
+
+       len = get_reply_len(qname_cstr, 0);
+
+    XCTAssertNil((__bridge id)reply->next);
+       XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+       XCTAssertEqual(reply->mhdr->version, VERSION);
+       XCTAssertEqual(reply->mhdr->datalen, len);
+       XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+       XCTAssertEqual(reply->mhdr->op, query_reply_op);
+    XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+       XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly);       // Regress <rdar://problem/27340874>
+       XCTAssertEqual(reply->rhdr->error,
+                                       (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout));            // Regress <rdar://problem/27562965>
+
+       // Free request and reallocate to use when query is restarted
+       free_req(req);
+       client_request_message = calloc(1, sizeof(request_state));
+}
+
+// This unit test populates the cache with four /etc/hosts records and then
+// verifies there are four entries in the cache.
+- (void)testPopulateCacheWithClientLOResponseRecords
+{
+       mDNS *const m = &mDNSStorage;
+
+       // Verify cache is empty
+       int count = LogEtcHosts_ut(m);
+       XCTAssertEqual(count, 0);
+
+       // Populate /etc/hosts
+       mStatus result = InitEtcHostsRecords();
+       XCTAssertEqual(result, mStatus_NoError);
+
+       // mDNS_Execute is called to populate the /etc/hosts cache.
+       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+       mDNS_Execute(m);
+
+       count = LogEtcHosts_ut(m);
+       XCTAssertEqual(count, 4);
+    
+    [self _testRestartLocalOnlyClientQueryRequest];   //  Continuation of this test
+}
+
+// This unit test starts a local only request for "cardinal2.apple.com.".  It first
+// calls start_client_request to start a query, it then verifies the
+// req and query data structures are set as expected. Next, the cache is verified to
+// contain the answer by AnswerNewLocalOnlyQuestion() and so results in setting up an
+// answer reply to the client. On return from mDNS_Execute, the client's reply structure
+// is verified to be set as expected. Lastly the timeout is simulated and mDNS_Execute is
+// called. This results in a call to TimeoutQuestions(). And this time, the
+// GenerateNegativeResponse() is called which returns a negative response to the client
+// which specifies the timeout occurred. Again, the answer reply is verified to
+// to specify a timeout.
+- (void)_testRestartLocalOnlyClientQueryRequest
+{
+       mDNS *const m = &mDNSStorage;
+       request_state* req = client_request_message;
+       char *msgptr = (char *)query_req_msgbuf;
+       size_t msgsz = sizeof(query_req_msgbuf);        DNSQuestion *q;
+       mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
+       mStatus err = mStatus_NoError;
+       char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+       struct reply_state *reply;
+       size_t len;
+
+       // Process the unit test's client request
+       start_client_request(req, msgptr, msgsz, query_request, local_socket);
+    XCTAssertEqual(err, mStatus_NoError);
+
+       XCTAssertEqual(req->hdr.version, VERSION);
+    XCTAssertGreaterThan((mDNSs32)req->data_bytes, min_size);
+       XCTAssertEqual(req->flags, (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
+       XCTAssertEqual(req->interfaceIndex, kDNSServiceInterfaceIndexLocalOnly);
+    XCTAssertNotEqual(req->terminate, (req_termination_fn)0);
+    XCTAssertNil((__bridge id)m->Questions);
+
+       q = &req->u.queryrecord.op.q;
+       XCTAssertEqual(q, m->NewLocalOnlyQuestions);
+       XCTAssertEqual(q->SuppressUnusable, 1);
+       XCTAssertEqual(q->ReturnIntermed, 1);
+       XCTAssertEqual(q->Suppressed, mDNSfalse);                                                                               // Regress <rdar://problem/27571734>
+       XCTAssertEqual(q->qnamehash, DomainNameHashValue(&q->qname));
+       XCTAssertEqual(q->InterfaceID, mDNSInterface_LocalOnly);
+       XCTAssertEqual(q->flags, req->flags);
+       XCTAssertEqual(q->qtype, 1);
+       XCTAssertEqual(q->qclass, 1);
+       XCTAssertEqual(q->LongLived, 0);
+       XCTAssertEqual(q->ExpectUnique, mDNSfalse);
+       XCTAssertEqual(q->ForceMCast, 0);
+       XCTAssertEqual(q->TimeoutQuestion, 1);
+       XCTAssertEqual(q->WakeOnResolve, 0);
+       XCTAssertEqual(q->UseBackgroundTraffic, 0);
+       XCTAssertEqual(q->ValidationRequired, 0);
+       XCTAssertEqual(q->ValidatingResponse, 0);
+       XCTAssertEqual(q->ProxyQuestion, 0);
+    XCTAssertNotEqual((void*)q->QuestionCallback, (void*)mDNSNULL);
+    XCTAssertNil((__bridge id)q->DNSSECAuthInfo);
+    XCTAssertNil((__bridge id)(void*)q->DAIFreeCallback);
+    XCTAssertNotEqual(q->StopTime, 0);
+    XCTAssertEqual(q->AppendSearchDomains, 0);
+    XCTAssertNil((__bridge id)q->DuplicateOf);
+       ConvertDomainNameToCString(&q->qname, qname_cstr);
+    XCTAssertFalse(strcmp(qname_cstr, domainname_cstr));
+
+       // Answer local-only question with found cache entry
+       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+       mDNS_Execute(m);                                                                                                                        // Regress <rdar://problem/28721294>
+    XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+       XCTAssertEqual(req->u.queryrecord.op.answered, 1);
+       XCTAssertEqual(q->LOAddressAnswers, 1);
+       XCTAssertEqual(q, m->LocalOnlyQuestions);
+
+       reply = req->replies;
+       len = get_reply_len(qname_cstr, 4);
+
+    XCTAssertNil((__bridge id)reply->next);
+       XCTAssertEqual(reply->totallen, len + sizeof(ipc_msg_hdr));
+       XCTAssertEqual(reply->mhdr->version, VERSION);
+       XCTAssertEqual(reply->mhdr->datalen, len);
+       XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+       XCTAssertEqual(reply->mhdr->op, query_reply_op);
+       XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+       XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly);       // Regress <rdar://problem/27340874>
+       XCTAssertEqual(reply->rhdr->error, kDNSServiceErr_NoError);
+
+       // Simulate the query time out of the local-only question.
+       // The expected behavior is a negative answer with time out error
+       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
+       q->StopTime = mDNS_TimeNow_NoLock(m);
+       m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
+       mDNS_Execute(m);
+
+       reply = req->replies->next;
+       XCTAssertNotEqual(reply, (reply_state*)mDNSNULL);
+    XCTAssertNil((__bridge id)reply->next);
+    XCTAssertNil((__bridge id)m->NewLocalOnlyQuestions);
+       XCTAssertEqual(q->LOAddressAnswers, 0);
+       len = get_reply_len(qname_cstr, 0);
+
+    XCTAssertNil((__bridge id)reply->next);
+       XCTAssertEqual(reply->totallen, len + + sizeof(ipc_msg_hdr));
+       XCTAssertEqual(reply->mhdr->version, VERSION);
+       XCTAssertEqual(reply->mhdr->datalen, len);
+       XCTAssertEqual(reply->mhdr->ipc_flags, 0);
+       XCTAssertEqual(reply->mhdr->op, query_reply_op);
+    XCTAssertTrue((reply->rhdr->flags & htonl(kDNSServiceFlagsAdd)));
+       XCTAssertEqual(reply->rhdr->ifi, kDNSServiceInterfaceIndexLocalOnly);       // Regress <rdar://problem/27340874>
+       XCTAssertEqual(reply->rhdr->error,
+                                       (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout));            // Regress <rdar://problem/27562965>
+
+       free_req(req);
+}
+
+@end
diff --git a/mDNSMacOSX/Tests/ResourceRecordTest.m b/mDNSMacOSX/Tests/ResourceRecordTest.m
new file mode 100644 (file)
index 0000000..8a71f43
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017-2018 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.
+ */
+
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h"
+#import <XCTest/XCTest.h>
+
+@interface ResourceRecordTest : XCTestCase
+{
+}
+@end
+
+@implementation ResourceRecordTest
+
+- (void)setUp
+{
+}
+
+- (void)tearDown
+{
+}
+
+- (void)testTXTSetup
+{
+    AuthRecord authRec;
+    mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeShared, AuthRecordAny,mDNSNULL, mDNSNULL);
+    XCTAssertEqual(authRec.resrec.rrtype,               kDNSType_TXT);
+    XCTAssertEqual(authRec.resrec.RecordType,           kDNSRecordTypeShared);
+    XCTAssertEqual(authRec.resrec.rdata->MaxRDLength,   sizeof(RDataBody));
+}
+
+- (void)testASetup
+{
+    AuthRecord authRec;
+    mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+    
+    XCTAssertEqual(authRec.resrec.rrtype,           kDNSType_A);
+    XCTAssertEqual(authRec.resrec.RecordType,       kDNSRecordTypeUnique);
+    // Add more verifications
+}
+
+- (void)testOPTSetup
+{
+    AuthRecord opt;
+    mDNSu32    updatelease = 7200;
+
+    // Setup the OPT Record
+    mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
+
+    // Verify the basic initialization is all ok
+
+    opt.resrec.rrclass    = NormalMaxDNSMessageData;
+    opt.resrec.rdlength   = sizeof(rdataOPT);   // One option in this OPT record
+    opt.resrec.rdestimate = sizeof(rdataOPT);
+    opt.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
+    opt.resrec.rdata->u.opt[0].u.updatelease = updatelease;
+
+    // Put the resource record in and verify everything is fine
+#if 0
+    mDNSu8     data[AbsoluteMaxDNSMessageData];
+    mDNSu8     *p = data;
+    mDNSu16    numAdditionals;
+    
+    p = PutResourceRecordTTLWithLimit((DNSMessage*)&data, p, &numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, data + AbsoluteMaxDNSMessageData);
+#endif
+}
+
+// Repeat with bad data to make sure it bails out cleanly
+
+#if 0
+- (void)testPerformanceExample {
+    // This is an example of a performance test case.
+    [self measureBlock:^{
+        // Put the code you want to measure the time of here.
+    }];
+}
+#endif
+
+@end
diff --git a/mDNSMacOSX/Tests/mDNSCoreReceiveTest.m b/mDNSMacOSX/Tests/mDNSCoreReceiveTest.m
new file mode 100644 (file)
index 0000000..e2c3245
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2017-2018 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.
+ */
+
+#include "unittest_common.h"
+#import <XCTest/XCTest.h>
+
+// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
+uint8_t udns_query_request_message[28] = {            // contains 1 question for www.f5.com
+    0x31, 0xca, // transaction id
+    0x01, 0x00,    // flags
+    0x00, 0x01,    // 1 question
+    0x00, 0x00,    // no anwsers
+    0x00, 0x00,    // no authoritative answers
+    0x00, 0x00, // no additionals
+    0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+
+// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
+// Then the header id (more specifically, the msg->h.id) was deliberately cleared to force code
+// path to traverse regression case, <rdar://problem/28556513>.
+uint8_t udns_query_request_message_with_invalid_id[28] = {  // contains 1 question for www.f5.com, msg->h.id = 0
+    0x00, 0x00,    // transaction id
+    0x01, 0x00, // flags
+    0x00, 0x01, // 1 question
+    0x00, 0x00, // no anwsers
+    0x00, 0x00, // no authoritative answers
+    0x00, 0x00, // no additionals
+    0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
+};
+
+uint8_t arp_request_packet[28] = {  // contains 1 question for www.f5.com, msg->h.id = 0
+    0x00, 0x01, // hardware type: enet
+    0x08, 0x00, // protocol type: IP
+    0x06, // hardware size
+    0x04, // Protcol size
+    0x00, 0x01, // opcode request
+    0x24, 0x01, 0xc7, 0x24, 0x35, 0x00, // Sender mac addr
+    0x11, 0xe2, 0x14, 0x01,    // Sender ip addr
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,    // target mac addr
+    0x11, 0xe2, 0x17, 0xbe    // target ip addr
+};
+
+mDNSlocal void InitmDNSStorage(mDNS *const m)
+{
+    memset(m, 0, sizeof(mDNS));
+}
+
+@interface mDNSCoreReceiveTest : XCTestCase
+{
+}
+@end
+
+@implementation mDNSCoreReceiveTest
+
+- (void)setUp
+{
+    mDNSPlatformTimeInit();
+    mDNS_LoggingEnabled = 0;
+    mDNS_PacketLoggingEnabled = 0;
+}
+
+- (void)tearDown {
+}
+
+- (void)testValidQueryReq
+{
+    mDNS *const m = &mDNSStorage;
+    mDNSAddr srcaddr, dstaddr;
+    mDNSIPPort srcport, dstport;
+    DNSMessage * msg;
+    const mDNSu8 * end;
+    
+    // Init unit test environment and verify no error occurred.
+    mStatus result = init_mdns_environment(mDNStrue);
+    XCTAssertEqual(result, mStatus_NoError);
+    
+    // Used random values for srcaddr and srcport
+    srcaddr.type       = mDNSAddrType_IPv4;
+    srcaddr.ip.v4.b[0] = 192;
+    srcaddr.ip.v4.b[1] = 168;
+    srcaddr.ip.v4.b[2] = 1;
+    srcaddr.ip.v4.b[3] = 10;
+    srcport.NotAnInteger = swap16((mDNSu16)53);
+    
+    // Used random values for dstaddr and dstport
+    dstaddr.type       = mDNSAddrType_IPv4;
+    dstaddr.ip.v4.b[0] = 192;
+    dstaddr.ip.v4.b[1] = 168;
+    dstaddr.ip.v4.b[2] = 1;
+    dstaddr.ip.v4.b[3] = 20;
+    dstport.NotAnInteger = swap16((mDNSu16)49339);
+    
+    // Set message to a DNS message (copied from a WireShark packet)
+    msg = (DNSMessage *)udns_query_request_message;
+    end = udns_query_request_message + sizeof(udns_query_request_message);
+    
+    // Execute mDNSCoreReceive using a valid DNS message
+    mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &dstaddr, dstport, if_nametoindex("en0"));
+    
+    // Verify that mDNSCoreReceiveQuery traversed the normal code path
+    XCTAssertEqual(m->mDNSStats.NormalQueries,  1);
+}
+
+- (void)testNullDstQueryReqTest
+{
+    mDNS *const m = &mDNSStorage;
+    mDNSAddr srcaddr;
+    mDNSIPPort srcport, dstport;
+    DNSMessage * msg;
+    const mDNSu8 * end;
+
+    // This test case does not require setup of interfaces, the record's cache, or pending questions
+    // so m is initialized to all zeros.
+    InitmDNSStorage(m);
+
+    // Used random values for srcaddr and srcport
+    srcaddr.type       = mDNSAddrType_IPv4;
+    srcaddr.ip.v4.b[0] = 192;
+    srcaddr.ip.v4.b[1] = 168;
+    srcaddr.ip.v4.b[2] = 1;
+    srcaddr.ip.v4.b[3] = 10;
+    srcport.NotAnInteger = swap16((mDNSu16)53);
+
+    // Used random value for dstport
+    dstport.NotAnInteger = swap16((mDNSu16)49339);
+
+    // Set message to a DNS message (copied from a WireShark packet)
+    msg = (DNSMessage *)udns_query_request_message_with_invalid_id;
+    end = udns_query_request_message_with_invalid_id + sizeof(udns_query_request_message_with_invalid_id);
+
+    // Execute mDNSCoreReceive to regress <rdar://problem/28556513>
+    mDNSCoreReceive(m, msg, end, &srcaddr, srcport, NULL, dstport, if_nametoindex("en0"));
+
+    // Verify that mDNSCoreReceiveQuery was NOT traversed through the normal code path
+    XCTAssertEqual(m->mDNSStats.NormalQueries,  0);
+
+    // Verify code path that previously crashed, in <rdar://problem/28556513>, now traverses successfully
+    // by checking a counter that was incremented on code path that crashed.
+    XCTAssertEqual(m->MPktNum,                  1);
+}
+
+
+#if 0
+- (void)testPerformanceExample {
+    // This is an example of a performance test case.
+    [self measureBlock:^{
+        // Put the code you want to measure the time of here.
+    }];
+}
+#endif
+
+@end
diff --git a/mDNSMacOSX/Tests/mDNSResponder.plist b/mDNSMacOSX/Tests/mDNSResponder.plist
new file mode 100644 (file)
index 0000000..025d212
--- /dev/null
@@ -0,0 +1,784 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Project</key>
+       <string>mDNSResponder</string>
+       <key>RadarComponents</key>
+       <dict>
+               <key>Name</key>
+               <string>mDNSResponder</string>
+               <key>Version</key>
+               <string>all</string>
+       </dict>
+       <key>Tests</key>
+       <array>
+               <dict>
+                       <key>TestName</key>
+                       <string>GAIPerf Advanced</string>
+                       <key>Description</key>
+                       <string>Tests correctness of resolving hostnames via DNS using the GAIPerf Advanced test suite.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>900</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>gaiperf</string>
+                               <string>--suite</string>
+                               <string>advanced</string>
+                               <string>--timeLimit</string>
+                               <string>250</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--skipPathEval</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 1-1-1</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>1</string>
+                               <string>--txtSize</string>
+                               <string>1</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>1</string>
+                               <string>--countAAAA</string>
+                               <string>1</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 1-1-1 (No Additionals)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record. Responses from mdnsreplier contain no additional answers.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>1</string>
+                               <string>--txtSize</string>
+                               <string>1</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>1</string>
+                               <string>--countAAAA</string>
+                               <string>1</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--noAdditionals</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 10-100-2</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>10</string>
+                               <string>--txtSize</string>
+                               <string>100</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 10-100-2 (No Additionals)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. Responses from mdnsreplier contain no additional answers.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>10</string>
+                               <string>--txtSize</string>
+                               <string>100</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--noAdditionals</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 100-500-2</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>100</string>
+                               <string>--txtSize</string>
+                               <string>500</string>
+                               <string>--browseTime</string>
+                               <string>5</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 100-500-2 (No Additionals)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records. Responses from mdnsreplier contain no additional answers.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>100</string>
+                               <string>--txtSize</string>
+                               <string>500</string>
+                               <string>--browseTime</string>
+                               <string>5</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--noAdditionals</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 1-1-1 (No Cache Flush)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record. Cache is not flushed beforehand.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>1</string>
+                               <string>--txtSize</string>
+                               <string>1</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>1</string>
+                               <string>--countAAAA</string>
+                               <string>1</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 1-1-1 (No Cache Flush, No Additionals)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of one service instance with one one-byte TXT record, one A record, and one AAAA record. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>1</string>
+                               <string>--txtSize</string>
+                               <string>1</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>1</string>
+                               <string>--countAAAA</string>
+                               <string>1</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--noAdditionals</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 10-100-2 (No Cache Flush)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>10</string>
+                               <string>--txtSize</string>
+                               <string>100</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 10-100-2 (No Cache Flush, No Additionals)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>10</string>
+                               <string>--txtSize</string>
+                               <string>100</string>
+                               <string>--browseTime</string>
+                               <string>3</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--noAdditionals</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 100-500-2 (No Cache Flush)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>100</string>
+                               <string>--txtSize</string>
+                               <string>500</string>
+                               <string>--browseTime</string>
+                               <string>5</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--format</string>
+                               <string>json</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery 100-500-2 (No Cache Flush, No Additionals)</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of 100 service instances with one 500-byte TXT record, two A records, and two AAAA records. Cache is not flushed beforehand. Responses from mdnsreplier contain no additional answers.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>100</string>
+                               <string>--txtSize</string>
+                               <string>500</string>
+                               <string>--browseTime</string>
+                               <string>5</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv4</string>
+                               <string>--ipv6</string>
+                               <string>--noAdditionals</string>
+                               <string>--format</string>
+                               <string>json</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery w/Packet Drops 10</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of ten service instances with one 100-byte TXT record, two A records, and two AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>30</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>10</string>
+                               <string>--txtSize</string>
+                               <string>100</string>
+                               <string>--browseTime</string>
+                               <string>16</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv6</string>
+                               <string>--udrop</string>
+                               <string>0.5</string>
+                               <string>--mdrop</string>
+                               <string>0.5</string>
+                               <string>--maxDropCount</string>
+                               <string>3</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNS Discovery w/Packet Drops 100</string>
+                       <key>Description</key>
+                       <string>Tests mDNS discovery and resolution of 100 service instances with one 100-byte TXT record, two A records, and two AAAA records. The first three responses per service instance are subject to a 0.5 probability of being dropped to test query retries.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>30</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>mdnsdiscovery</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--instanceCount</string>
+                               <string>100</string>
+                               <string>--txtSize</string>
+                               <string>100</string>
+                               <string>--browseTime</string>
+                               <string>18</string>
+                               <string>--countA</string>
+                               <string>2</string>
+                               <string>--countAAAA</string>
+                               <string>2</string>
+                               <string>--ipv6</string>
+                               <string>--udrop</string>
+                               <string>0.5</string>
+                               <string>--mdrop</string>
+                               <string>0.5</string>
+                               <string>--maxDropCount</string>
+                               <string>3</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--flushCache</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>DotLocal Queries</string>
+                       <key>Description</key>
+                       <string>Tests DNS and mDNS queries for domain names in the local domain.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>40</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>dotlocal</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--format</string>
+                               <string>json</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>Service Registration</string>
+                       <key>Description</key>
+                       <string>Tests Bonjour service registration.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <true/>
+                       <key>Timeout</key>
+                       <integer>120</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>registration</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--bats</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>Probe Conflicts</string>
+                       <key>Description</key>
+                       <string>Tests various probe conflict scenarios, some of which are expected to result in service instance and record renames.</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>300</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>probeconflicts</string>
+                               <string>--interface</string>
+                               <string>lo0</string>
+                               <string>--format</string>
+                               <string>json</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>TCP Fallback</string>
+                       <key>Description</key>
+                       <string>Tests mDNSResponder&apos;s TCP fallback mechanism, which is triggered by UDP responses with invalid message IDs that would otherwise be acceptable.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>90</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>gaiperf</string>
+                               <string>--suite</string>
+                               <string>basic</string>
+                               <string>--timeLimit</string>
+                               <string>250</string>
+                               <string>--format</string>
+                               <string>json</string>
+                               <string>--skipPathEval</string>
+                               <string>--badUDPMode</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>State Dump</string>
+                       <key>Description</key>
+                       <string>1.  Tests whether the state dump can be triggered correctly, and whether the file (or stdout&apos;s output) contains the full state information. 2. Checks whether the number of state dump files has an upper limit to avoid wasting disk space.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <true/>
+                       <key>Timeout</key>
+                       <integer>60</integer>
+                       <key>IgnoreOutput</key>
+                       <false/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>browseAll</string>
+                               <string>&amp;&amp;</string>
+                               <string>/bin/sh</string>
+                               <string>/AppleInternal/Tests/mDNSResponder/bats_test_state_dump.sh</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>DNS Proxy</string>
+                       <key>Description</key>
+                       <string>1.  Tests the DNS Proxy by doing a DNS UDP query. 2. Tests the DNS proxy by doing a DNS TCP query.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <true/>
+                       <key>Timeout</key>
+                       <integer>60</integer>
+                       <key>IgnoreOutput</key>
+                       <false/>
+                       <key>Command</key>
+                       <array>
+                               <string>/bin/sh</string>
+                               <string>/AppleInternal/Tests/mDNSResponder/bats_test_proxy.sh</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>Expensive/Constrained Interface</string>
+                       <key>Description</key>
+                       <string>Test the following situation:
+1. The interface is set to expensive and inexpensive, and the query is set to DenyExpensive, a continuous ADD/REMOVE sequence is expected.
+2. The interface is set to expensive and inexpensive, and the query does not DenyExpensive, no update is expected.
+3. The interface is set to constrained and unconstrained, and the query is set to DenyConstrained, a continuous ADD/REMOVE sequence is expected.
+4. The interface is set to constrained and unconstrained, and the query does not DenyConstrained, no update is expected.
+5. The interface is set to expensive and constrained, and the query is set to DenyExpensive and DenyConstrained.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>1200</integer>
+                       <key>IgnoreOutput</key>
+                       <false/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/local/bin/dnssdutil</string>
+                               <string>test</string>
+                               <string>expensive_constrained_updates</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>mDNSResponder Leaks</string>
+                       <key>Description</key>
+                       <string>Checks mDNSResponder for memory leaks.</string>
+                       <key>AsRoot</key>
+                       <true/>
+                       <key>RequiresWiFi</key>
+                       <false/>
+                       <key>Timeout</key>
+                       <integer>10</integer>
+                       <key>IgnoreOutput</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>/usr/bin/leaks</string>
+                               <string>mDNSResponder</string>
+                       </array>
+               </dict>
+               <dict>
+                       <key>TestName</key>
+                       <string>XCTests</string>
+                       <key>Description</key>
+                       <string>mDNSResponder XCTests</string>
+                       <key>WorkingDirectory</key>
+                       <string>/AppleInternal/XCTests/com.apple.mDNSResponder/</string>
+                       <key>AsRoot</key>
+                       <false/>
+                       <key>RequiresWiFi</key>
+                       <true/>
+                       <key>Timeout</key>
+                       <integer>20</integer>
+                       <key>ShowSubtestResults</key>
+                       <true/>
+                       <key>Command</key>
+                       <array>
+                               <string>BATS_XCTEST_CMD</string>
+                               <string>-NSTreatUnknownArgumentsAsOpen</string>
+                               <string>NO</string>
+                               <string>-ApplePersistenceIgnoreState</string>
+                               <string>YES</string>
+                               <string>-XCTest</string>
+                               <string>Self</string>
+                               <string>Tests.xctest</string>
+                       </array>
+               </dict>
+       </array>
+</dict>
+</plist>
index 881f8c9e63dabc7d3c4e37faf5923cec3f78c805..f9ae905a3edea24285be3509fbb1fc52967c71b4 100644 (file)
        </array>
        <key>MachServices</key>
        <dict>
-               <key>com.apple.mDNSResponder.dnsproxy</key>
+               <key>com.apple.dnssd.service</key>
+               <true/>
+               <key>com.apple.mDNSResponder.log_utility</key>
                <true/>
-               <key>com.apple.mDNSResponder.dnsctl</key>
+               <key>com.apple.mDNSResponder.dnsproxy</key>
                <true/>
        </dict>
        <key>Sockets</key>
diff --git a/mDNSMacOSX/command_line_client_entitlements/dns-sd-entitlements.plist b/mDNSMacOSX/command_line_client_entitlements/dns-sd-entitlements.plist
new file mode 100644 (file)
index 0000000..3823528
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>com.apple.mDNSResponder.log_utility</key>
+       <true/>
+</dict>
+</plist>
+
index 233ffb99cc400ab39f174c1f45d6b7e52e5d50ec..53dcead0566d6d56330a26593aca4aba4a598bf5 100644 (file)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil -*-
  *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
 #include <SystemConfiguration/SCDynamicStoreCopyDHCPInfo.h>
 #include <err.h>
 #include <sysexits.h>
-
-#ifdef UNIT_TEST
-#include "unittest.h"
-#endif
+#include <TargetConditionals.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 "xpc_services.h"           // Interface to XPC services
+#include "xpc_services.h"
+#include "xpc_service_dns_proxy.h"
+#include "xpc_service_log_utility.h"
 #include "helper.h"
+#include "posix_utilities.h"        // for getLocalTimestamp()
 
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
 #include "Metrics.h"
 #endif
 
-#if APPLE_OSX_mDNSResponder
-static os_log_t        log_general             = NULL;
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+#include "dnssd_server.h"
 #endif
 
-
 // Used on OSX(10.11.x onwards) for manipulating mDNSResponder program arguments
 #if APPLE_OSX_mDNSResponder
 // plist file to read the user's preferences
@@ -73,7 +72,7 @@ static os_log_t       log_general             = NULL;
 #define kPreferencesKey_DefaultToBLETriggered     CFSTR("DefaultToBLETriggered")
 #endif  // ENABLE_BLE_TRIGGERED_BONJOUR
 
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
 #define kPreferencesKey_PreallocateCacheMemory    CFSTR("PreallocateCacheMemory")
 #endif
 #endif
@@ -109,14 +108,19 @@ static mDNSBool NoMulticastAdvertisements = mDNSfalse; // By default, advertise
 extern mDNSBool StrictUnicastOrdering;
 extern mDNSBool AlwaysAppendSearchDomains;
 extern mDNSBool EnableAllowExpired;
+mDNSexport void INFOCallback(void);
+mDNSexport void dump_state_to_fd(int fd);
 
 #if ENABLE_BLE_TRIGGERED_BONJOUR
 extern mDNSBool EnableBLEBasedDiscovery;
 extern mDNSBool DefaultToBLETriggered;
 #endif  // ENABLE_BLE_TRIGGERED_BONJOUR
 
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
 static mDNSBool PreallocateCacheMemory = mDNSfalse;
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_MEM_LIMIT)
 #define kRRCacheMemoryLimit 1000000 // For now, we limit the cache to at most 1MB on iOS devices.
 #endif
 
@@ -138,89 +142,16 @@ static KQSocketEventSource *gEventSources;
 #pragma mark - General Utility Functions
 #endif
 
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-
-char _malloc_options[] = "AXZ";
-
-mDNSlocal void validatelists(mDNS *const m)
+#if MDNS_MALLOC_DEBUGGING
+void mDNSPlatformValidateLists()
 {
-#if BONJOUR_ON_DEMAND
-    mDNSu32 NumAllInterfaceRecords   = 0;
-    mDNSu32 NumAllInterfaceQuestions = 0;
-#endif // BONJOUR_ON_DEMAND
+    mDNS *const m = &mDNSStorage;
 
-    // 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 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->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)
-            LogMemCorruption("ResourceRecords list: %p name %p does not point to namestorage %p %##s",
-                             rr, rr->resrec.name->c, rr->namestorage.c, rr->namestorage.c);
-#if BONJOUR_ON_DEMAND
-        if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
-#endif // BONJOUR_ON_DEMAND
-    }
-
-    for (rr = m->DuplicateRecords; rr; rr=rr->next)
-    {
-        if (rr->next == (AuthRecord *)~0 || rr->resrec.RecordType == 0 || rr->resrec.RecordType == 0xFF)
-            LogMemCorruption("DuplicateRecords list: %p is garbage (%X)", rr, rr->resrec.RecordType);
-#if BONJOUR_ON_DEMAND
-        if (!AuthRecord_uDNS(rr) && !RRLocalOnly(rr)) NumAllInterfaceRecords++;
-#endif // BONJOUR_ON_DEMAND
-    }
-
-    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->next == (DNSQuestion*)~0 || q->ThisQInterval == (mDNSs32) ~0)
-            LogMemCorruption("Questions list: %p is garbage (%lX %p)", q, q->ThisQInterval, q->next);
-        if (q->DuplicateOf && q->LocalSocket)
-            LogMemCorruption("Questions list: Duplicate Question %p should not have LocalSocket set %##s (%s)", q, q->qname.c, DNSTypeName(q->qtype));
-#if BONJOUR_ON_DEMAND
-        if (!LocalOnlyOrP2PInterface(q->InterfaceID) && mDNSOpaque16IsZero(q->TargetQID))
-            NumAllInterfaceQuestions++;
-#endif // BONJOUR_ON_DEMAND
-    }
-
-    CacheGroup                  *cg;
-    CacheRecord                 *cr;
-    mDNSu32 slot;
-    FORALL_CACHERECORDS(slot, cg, cr)
-    {
-        if (cr->resrec.RecordType == 0 || cr->resrec.RecordType == 0xFF)
-            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)
@@ -231,54 +162,8 @@ mDNSlocal void validatelists(mDNS *const m)
     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]);
-
-#if BONJOUR_ON_DEMAND
-    if (m->NumAllInterfaceRecords != NumAllInterfaceRecords)
-       LogMemCorruption("NumAllInterfaceRecords is %d should be %d", m->NumAllInterfaceRecords, NumAllInterfaceRecords);
-    
-    if (m->NumAllInterfaceQuestions != NumAllInterfaceQuestions)
-       LogMemCorruption("NumAllInterfaceQuestions is %d should be %d", m->NumAllInterfaceQuestions, NumAllInterfaceQuestions);
-#endif // BONJOUR_ON_DEMAND
 }
-
-mDNSexport void *mallocL(char *msg, unsigned int size)
-{
-    // Allocate space for two words of sanity checking data before the requested block
-    mDNSu32 *mem = malloc(sizeof(mDNSu32) * 2 + size);
-    if (!mem)
-    { LogMsg("malloc( %s : %d ) failed", msg, size); return(NULL); }
-    else
-    {
-        if      (size > 32768)                      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;
-        //mDNSPlatformMemZero(&mem[2], size);
-        memset(&mem[2], 0xFF, size);
-        validatelists(&mDNSStorage);
-        return(&mem[2]);
-    }
-}
-
-mDNSexport void freeL(char *msg, void *x)
-{
-    if (!x)
-        LogMsg("free( %s @ NULL )!", msg);
-    else
-    {
-        mDNSu32 *mem = ((mDNSu32 *)x) - 2;
-        if      (mem[0] == 0xDEADDEAD)  { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg, mem[1], &mem[2]); return; }
-        if      (mem[0] != 0xDEAD1234)  { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!",  msg, mem[1], &mem[2]); return; }
-        if      (mem[1] > 32768)                    LogMsg("free( %s : %lu @ %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]);
-        mem[0] = 0xDEADDEAD;
-        memset(mem+2, 0xFF, mem[1]);
-        validatelists(&mDNSStorage);
-        free(mem);
-    }
-}
-
-#endif
+#endif // MDNS_MALLOC_DEBUGGING
 
 //*************************************************************************************************************
 // Registration
@@ -374,7 +259,7 @@ mDNSlocal void mDNS_StatusCallback(mDNS *const m, mStatus result)
     {
         // Allocate another chunk of cache storage
         static unsigned int allocated = 0;
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, CACHE_MEM_LIMIT)
         if (allocated >= kRRCacheMemoryLimit) return;  // For now we limit the cache to at most 1MB on iOS devices
 #endif
         allocated += kRRCacheGrowSize;
@@ -440,142 +325,174 @@ mDNSlocal void HandleSIG(int sig)
 
 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
 
-mDNSexport void INFOCallback(void)
+mDNSexport void dump_state_to_fd(int fd)
 {
+    mDNS *const m = &mDNSStorage;
+    char buffer[1024];
+    buffer[0] = '\0';
+
     mDNSs32 utc = mDNSPlatformUTC();
     const mDNSs32 now = mDNS_TimeNow(&mDNSStorage);
     NetworkInterfaceInfoOSX     *i;
     DNSServer *s;
     McastResolver *mr;
+    char timestamp[64]; // 64 is enough to store the UTC timestmp
 
-    LogMsg("---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+    LogToFD(fd, "---- BEGIN STATE LOG ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+    getLocalTimestamp(timestamp, sizeof(timestamp));
+    LogToFD(fd, "Date: %s", timestamp);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- BEGIN STATE LOG ---- (" PUB_S ")", timestamp);
 
-    udsserver_info();
+    udsserver_info_dump_to_fd(fd);
 
-    LogMsgNoIdent("----- Platform Timers -----");
-    LogTimer("m->NextCacheCheck       ", mDNSStorage.NextCacheCheck);
-    LogTimer("m->NetworkChanged       ", mDNSStorage.NetworkChanged);
-    LogTimer("m->p->NotifyUser        ", mDNSStorage.p->NotifyUser);
-    LogTimer("m->p->HostNameConflict  ", mDNSStorage.p->HostNameConflict);
-    LogTimer("m->p->KeyChainTimer     ", mDNSStorage.p->KeyChainTimer);
+    LogToFD(fd, "----- Platform Timers -----");
+    LogTimerToFD(fd, "m->NextCacheCheck       ", mDNSStorage.NextCacheCheck);
+    LogTimerToFD(fd, "m->NetworkChanged       ", mDNSStorage.NetworkChanged);
+    LogTimerToFD(fd, "m->p->NotifyUser        ", mDNSStorage.p->NotifyUser);
+    LogTimerToFD(fd, "m->p->HostNameConflict  ", mDNSStorage.p->HostNameConflict);
+    LogTimerToFD(fd, "m->p->KeyChainTimer     ", mDNSStorage.p->KeyChainTimer);
 
-    xpcserver_info(&mDNSStorage);
+    log_dnsproxy_info_to_fd(fd, &mDNSStorage);
 
-    LogMsgNoIdent("----- KQSocketEventSources -----");
-    if (!gEventSources) LogMsgNoIdent("<None>");
+    LogToFD(fd, "----- KQSocketEventSources -----");
+    if (!gEventSources) LogToFD(fd, "<None>");
     else
     {
         KQSocketEventSource *k;
         for (k = gEventSources; k; k=k->next)
-            LogMsgNoIdent("%3d %s %s", k->fd, k->kqs.KQtask, k->fd == mDNSStorage.uds_listener_skt ? "Listener for incoming UDS clients" : " ");
+            LogToFD(fd, "%3d %s %s", k->fd, k->kqs.KQtask, k->fd == mDNSStorage.uds_listener_skt ? "Listener for incoming UDS clients" : " ");
     }
 
-    LogMsgNoIdent("------ Network Interfaces ------");
-    if (!mDNSStorage.p->InterfaceList) LogMsgNoIdent("<None>");
+    LogToFD(fd, "------ Network Interfaces ------");
+    if (!mDNSStorage.p->InterfaceList) LogToFD(fd, "<None>");
     else
     {
-        LogMsgNoIdent("  Struct addr           Registered                MAC               BSSID                                Interface Address");
+        LogToFD(fd, "  Struct addr           Registered                MAC               BSSID                                Interface Address");
         for (i = mDNSStorage.p->InterfaceList; i; i = i->next)
         {
             // Allow six characters for interface name, for names like "vmnet8"
             if (!i->Exists)
-                LogMsgNoIdent("%p %2ld, %p,  %s %-6s %.6a %.6a %#-14a dormant for %d seconds",
-                              i, i->ifinfo.InterfaceID, i->Registered,
-                              i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
-                              &i->ifinfo.ip, utc - i->LastSeen);
+                LogToFD(fd, "%p %2ld, %p,  %s %-6s %.6a %.6a %#-14a dormant for %d seconds",
+                          i, i->ifinfo.InterfaceID, i->Registered,
+                          i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
+                          &i->ifinfo.ip, utc - i->LastSeen);
             else
             {
                 const CacheRecord *sps[3];
                 FindSPSInCache(&mDNSStorage, &i->ifinfo.NetWakeBrowse, sps);
-                LogMsgNoIdent("%p %2ld, %p,  %s %-6s %.6a %.6a %s %s %s %s %s %s %#a",
-                              i, i->ifinfo.InterfaceID, i->Registered,
-                              i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
-                              i->ifinfo.InterfaceActive ? "Active" : "      ",
-                              i->ifinfo.IPv4Available ? "v4" : "  ",
-                              i->ifinfo.IPv6Available ? "v6" : "  ",
-                              i->ifinfo.Advertise ? "A" : " ",
-                              i->ifinfo.McastTxRx ? "M" : " ",
-                              !(i->ifinfo.InterfaceActive && i->ifinfo.NetWake) ? " " : !sps[0] ? "p" : "P",
-                              &i->ifinfo.ip);
+                LogToFD(fd, "%p %2ld, %p,  %s %-6s %.6a %.6a %s %s %s %s %s %s %#a",
+                          i, i->ifinfo.InterfaceID, i->Registered,
+                          i->sa_family == AF_INET ? "v4" : i->sa_family == AF_INET6 ? "v6" : "??", i->ifinfo.ifname, &i->ifinfo.MAC, &i->BSSID,
+                          i->ifinfo.InterfaceActive ? "Active" : "      ",
+                          i->ifinfo.IPv4Available ? "v4" : "  ",
+                          i->ifinfo.IPv6Available ? "v6" : "  ",
+                          i->ifinfo.Advertise ? "A" : " ",
+                          i->ifinfo.McastTxRx ? "M" : " ",
+                          !(i->ifinfo.InterfaceActive && i->ifinfo.NetWake) ? " " : !sps[0] ? "p" : "P",
+                          &i->ifinfo.ip);
 
                 // Only print the discovered sleep proxies once for the lead/active interface of an interface set.
                 if (i == i->Registered && (sps[0] || sps[1] || sps[2]))
                 {
-                    LogMsgNoIdent("         Sleep Proxy Metric   Name");
-                    if (sps[0]) LogMsgNoIdent("  %13d %#s", SPSMetric(sps[0]->resrec.rdata->u.name.c), sps[0]->resrec.rdata->u.name.c);
-                    if (sps[1]) LogMsgNoIdent("  %13d %#s", SPSMetric(sps[1]->resrec.rdata->u.name.c), sps[1]->resrec.rdata->u.name.c);
-                    if (sps[2]) LogMsgNoIdent("  %13d %#s", SPSMetric(sps[2]->resrec.rdata->u.name.c), sps[2]->resrec.rdata->u.name.c);
+                    LogToFD(fd, "         Sleep Proxy Metric   Name");
+                    if (sps[0]) LogToFD(fd, "  %13d %#s", SPSMetric(sps[0]->resrec.rdata->u.name.c), sps[0]->resrec.rdata->u.name.c);
+                    if (sps[1]) LogToFD(fd, "  %13d %#s", SPSMetric(sps[1]->resrec.rdata->u.name.c), sps[1]->resrec.rdata->u.name.c);
+                    if (sps[2]) LogToFD(fd, "  %13d %#s", SPSMetric(sps[2]->resrec.rdata->u.name.c), sps[2]->resrec.rdata->u.name.c);
                 }
             }
         }
     }
 
-    LogMsgNoIdent("--------- DNS Servers(%d) ----------", NumUnicastDNSServers);
-    if (!mDNSStorage.DNSServers) LogMsgNoIdent("<None>");
+    LogToFD(fd, "--------- DNS Servers(%d) ----------", CountOfUnicastDNSServers(&mDNSStorage));
+    if (!mDNSStorage.DNSServers) LogToFD(fd, "<None>");
     else
     {
         for (s = mDNSStorage.DNSServers; s; s = s->next)
         {
             NetworkInterfaceInfoOSX *ifx = IfindexToInterfaceInfoOSX(s->interface);
-            LogMsgNoIdent("DNS Server %##s %s%s%#a:%d %d %s %d %u %s %s %s %s %s %s",
-                          s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
-                          s->penaltyTime ? (s->penaltyTime - mDNS_TimeNow(&mDNSStorage)) : 0, DNSScopeToString(s->scopeType),
-                          s->timeout, s->resGroupID,
-                          s->req_A ? "v4" : "!v4",  
-                          s->req_AAAA ? "v6" : "!v6",
-                          s->isCell ? "cell" : "!cell",
-                          s->isExpensive ? "exp" : "!exp",
-                          s->isCLAT46 ? "clat46" : "!clat46",
-                          s->DNSSECAware ? "DNSSECAware" : "!DNSSECAware");
+            LogToFD(fd, "DNS Server %##s %s%s%#a:%d %d %s %d %d %sv4 %sv6 %scell %sexp %sconstrained %sCLAT46 %sDNSSECAware",
+                    s->domain.c, ifx ? ifx->ifinfo.ifname : "", ifx ? " " : "", &s->addr, mDNSVal16(s->port),
+                    s->penaltyTime ? (s->penaltyTime - mDNS_TimeNow(&mDNSStorage)) : 0, DNSScopeToString(s->scopeType),
+                    s->timeout, s->resGroupID,
+                    s->usableA       ? "" : "!",
+                    s->usableAAAA    ? "" : "!",
+                    s->isCell        ? "" : "!",
+                    s->isExpensive   ? "" : "!",
+                    s->isConstrained ? "" : "!",
+                    s->isCLAT46      ? "" : "!",
+                    s->DNSSECAware   ? "" : "!");
         }
     }
 
-    LogMsgNoIdent("v4answers %d", mDNSStorage.p->v4answers);
-    LogMsgNoIdent("v6answers %d", mDNSStorage.p->v6answers);
-    LogMsgNoIdent("Last DNS Trigger: %d ms ago", (now - mDNSStorage.p->DNSTrigger));
+    LogToFD(fd, "v4answers %d", mDNSStorage.p->v4answers);
+    LogToFD(fd, "v6answers %d", mDNSStorage.p->v6answers);
+    LogToFD(fd, "Last DNS Trigger: %d ms ago", (now - mDNSStorage.p->DNSTrigger));
+
+    LogToFD(fd, "-------- Interface Monitors --------");
+    const CFIndex n = m->p->InterfaceMonitors ? CFArrayGetCount(m->p->InterfaceMonitors) : 0;
+    if (n > 0)
+    {
+        for (CFIndex j = 0; j < n; j++)
+        {
+            mdns_interface_monitor_t monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, j);
+            char *description = mdns_copy_description(monitor);
+            if (description)
+            {
+                LogToFD(fd, "%s", description);
+                free(description);
+            }
+            else
+            {
+                LogToFD(fd, "monitor %p (no description)", monitor);
+            }
+        }
+    }
+    else
+    {
+        LogToFD(fd, "No interface monitors");
+    }
 
-    LogMsgNoIdent("--------- Mcast Resolvers ----------");
-    if (!mDNSStorage.McastResolvers) LogMsgNoIdent("<None>");
+    LogToFD(fd, "--------- Mcast Resolvers ----------");
+    if (!mDNSStorage.McastResolvers) LogToFD(fd, "<None>");
     else
     {
         for (mr = mDNSStorage.McastResolvers; mr; mr = mr->next)
-            LogMsgNoIdent("Mcast Resolver %##s timeout %u", mr->domain.c, mr->timeout);
+            LogToFD(fd, "Mcast Resolver %##s timeout %u", mr->domain.c, mr->timeout);
     }
 
-    LogMsgNoIdent("------------ Hostnames -------------");
-    if (!mDNSStorage.Hostnames) LogMsgNoIdent("<None>");
+    LogToFD(fd, "------------ Hostnames -------------");
+    if (!mDNSStorage.Hostnames) LogToFD(fd, "<None>");
     else
     {
         HostnameInfo *hi;
         for (hi = mDNSStorage.Hostnames; hi; hi = hi->next)
         {
-            LogMsgNoIdent("%##s v4 %d %s", hi->fqdn.c, hi->arv4.state, ARDisplayString(&mDNSStorage, &hi->arv4));
-            LogMsgNoIdent("%##s v6 %d %s", hi->fqdn.c, hi->arv6.state, ARDisplayString(&mDNSStorage, &hi->arv6));
+            LogToFD(fd, "%##s v4 %d %s", hi->fqdn.c, hi->arv4.state, ARDisplayString(&mDNSStorage, &hi->arv4));
+            LogToFD(fd, "%##s v6 %d %s", hi->fqdn.c, hi->arv6.state, ARDisplayString(&mDNSStorage, &hi->arv6));
         }
     }
 
-    LogMsgNoIdent("--------------- FQDN ---------------");
-    if (!mDNSStorage.FQDN.c[0]) LogMsgNoIdent("<None>");
+    LogToFD(fd, "--------------- FQDN ---------------");
+    if (!mDNSStorage.FQDN.c[0]) LogToFD(fd, "<None>");
     else
     {
-        LogMsgNoIdent("%##s", mDNSStorage.FQDN.c);
+        LogToFD(fd, "%##s", mDNSStorage.FQDN.c);
     }
 
-#if AWD_METRICS
-    LogMetrics();
-#endif
-    LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
-    LogMsg("----  END STATE LOG  ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
-}
+    #if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
+        LogMetricsToFD(fd);
+    #endif
 
+//    getLocalTimestamp(timestamp, sizeof(timestamp));
+    LogToFD(fd, "Date: %s", timestamp);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- END STATE LOG ---- (" PUB_S ")", timestamp);
+    LogToFD(fd, "----  END STATE LOG  ---- %s %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
+}
 
-mDNSexport void mDNSPlatformLogToFile(int log_level, const char *buffer)
+mDNSexport void INFOCallback(void)
 {
-    if (!log_general)
-        os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in init_logging()");
-    else
-        os_log_with_type(log_general, log_level, "%{private}s", buffer);
-    
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
+        "Sending SIGINFO to mDNSResponder daemon is deprecated. To trigger state dump, please use 'dns-sd -O', enter 'dns-sd -h' for more information");
 }
 
 // Writes the state out to the dynamic store and also affects the ASL filter level
@@ -592,13 +509,13 @@ mDNSexport void UpdateDebugState()
     }
 
     CFNumberRef numOne = CFNumberCreate(NULL, kCFNumberSInt32Type, &one);
-    if (!numOne)
+    if (numOne == NULL)
     {
         LogMsg("UpdateDebugState: Could not create CFNumber one");
         return;
     }
     CFNumberRef numZero = CFNumberCreate(NULL, kCFNumberSInt32Type, &zero);
-    if (!numZero)
+    if (numZero == NULL)
     {
         LogMsg("UpdateDebugState: Could not create CFNumber zero");
         CFRelease(numOne);
@@ -722,7 +639,7 @@ mDNSlocal kern_return_t mDNSDaemonInitialize(void)
         return(err);
     }
 
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
     if (PreallocateCacheMemory)
     {
         const int growCount = (kRRCacheMemoryLimit + kRRCacheGrowSize - 1) / kRRCacheGrowSize;
@@ -1046,8 +963,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNSs32 now)
 
             //interval = 48; // For testing
 
-#if !TARGET_OS_EMBEDDED
-#ifdef kIOPMAcknowledgmentOptionSystemCapabilityRequirements
+#if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
             if (m->p->IOPMConnection)   // If lightweight-wake capability is available, use that
             {
                 const CFDateRef WakeDate = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent() + interval);
@@ -1056,7 +972,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNSs32 now)
                 {
                     const mDNSs32 reqs         = kIOPMSystemPowerStateCapabilityNetwork;
                     const CFNumberRef Requirements = CFNumberCreate(NULL, kCFNumberSInt32Type, &reqs);
-                    if (!Requirements) LogMsg("ScheduleNextWake: CFNumberCreate failed");
+                    if (Requirements == NULL) LogMsg("ScheduleNextWake: CFNumberCreate failed");
                     else
                     {
                         const void *OptionKeys[2] = { kIOPMAckDHCPRenewWakeDate, kIOPMAckSystemCapabilityRequirements };
@@ -1070,8 +986,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNSs32 now)
                 LogSPS("AllowSleepNow: Will request lightweight wakeup in %d seconds", interval);
             }
             else                        // else schedule the wakeup using the old API instead to
-#endif // kIOPMAcknowledgmentOptionSystemCapabilityRequirements
-#endif // TARGET_OS_EMBEDDED
+#endif
             {
                 // If we wake within +/- 30 seconds of our requested time we'll assume the system woke for us,
                 // so we should put it back to sleep. To avoid frustrating the user, we always request at least
@@ -1118,7 +1033,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNSs32 now)
     }
 
     LogSPS("AllowSleepNow: %s(%lX) %s at %ld (%d ticks remaining)",
-#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
+#if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
            (m->p->IOPMConnection) ? "IOPMConnectionAcknowledgeEventWithOptions" :
 #endif
            (result == kIOReturnSuccess) ? "IOAllowPowerChange" : "IOCancelPowerChange",
@@ -1127,7 +1042,7 @@ mDNSlocal mDNSBool AllowSleepNow(mDNSs32 now)
     m->SleepLimit = 0;  // Don't clear m->SleepLimit until after we've logged it above
     m->TimeSlept = mDNSPlatformUTC();
 
-#if !TARGET_OS_EMBEDDED && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
+#if TARGET_OS_OSX && defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements)
     if (m->p->IOPMConnection) IOPMConnectionAcknowledgeEventWithOptions(m->p->IOPMConnection, m->p->SleepCookie, opts);
     else
 #endif
@@ -1163,9 +1078,18 @@ mDNSlocal void PrepareForIdle(void *m_param)
     // Run mDNS_Execute to find out the time we next need to wake up
     mDNSs32 start          = mDNSPlatformRawTime();
     mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+    if (m->DNSPushServers != mDNSNULL)
+    {
+        nextTimerEvent = dso_idle(m, nextTimerEvent);
+    }
+#endif
     mDNSs32 end            = mDNSPlatformRawTime();
     if (end - start >= WatchDogReportingThreshold)
-        LogInfo("CustomSourceHandler:WARNING: Idle task took %dms to complete", end - start);
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
+            "CustomSourceHandler: WARNING: Idle task took %d ms to complete", end - start);
+    }
 
     mDNSs32 now = mDNS_TimeNow(m);
 
@@ -1259,12 +1183,25 @@ mDNSlocal void * KQueueLoop(void *m_param)
         // Run mDNS_Execute to find out the time we next need to wake up
         mDNSs32 start          = mDNSPlatformRawTime();
         mDNSs32 nextTimerEvent = udsserver_idle(mDNSDaemonIdle(m));
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+        dnssd_server_idle();
+#endif
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+        if (m->DNSPushServers != mDNSNULL)
+        {
+            mDNS_Lock(m);
+            nextTimerEvent = dso_idle(m, m->timenow, nextTimerEvent);
+            mDNS_Unlock(m);
+        }
+#endif
         mDNSs32 end            = mDNSPlatformRawTime();
         if (end - start >= WatchDogReportingThreshold)
-            LogInfo("WARNING: Idle task took %dms to complete", end - start);
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, "WARNING: Idle task took %d ms to complete", end - start);
+        }
 
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
-        validatelists(m);
+#if MDNS_MALLOC_DEBUGGING >= 1
+        mDNSPlatformValidateLists();
 #endif
 
         mDNSs32 now = mDNS_TimeNow(m);
@@ -1382,7 +1319,10 @@ mDNSlocal void * KQueueLoop(void *m_param)
                 kqentry->KQcallback(new_events[i].ident, new_events[i].filter, kqentry->KQcontext, (new_events[i].flags & EV_EOF) != 0);
                 mDNSs32 etime = mDNSPlatformRawTime();
                 if (etime - stime >= WatchDogReportingThreshold)
-                    LogInfo("WARNING: %s took %dms to complete", KQtask, etime - stime);
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING, 
+                        "WARNING: " PUB_S " took %d ms to complete", KQtask, etime - stime);
+                }
             }
         }
     }
@@ -1410,7 +1350,7 @@ mDNSlocal mDNSBool PreferencesGetValueBool(CFStringRef key, mDNSBool defaultValu
     mDNSBool result = defaultValue;
 
     boolean = CFPreferencesCopyAppValue(key, kProgramArguments);
-    if (boolean)
+    if (boolean != NULL)
     {
         if (CFGetTypeID(boolean) == CFBooleanGetTypeID())
             result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse;
@@ -1427,7 +1367,7 @@ mDNSlocal int PreferencesGetValueInt(CFStringRef key, int defaultValue)
     int result = defaultValue;
 
     number = CFPreferencesCopyAppValue(key, kProgramArguments);
-    if (number)
+    if (number != NULL)
     {
         if ((CFGetTypeID(number) == CFNumberGetTypeID()) && CFNumberGetValue(number, kCFNumberIntType, &numberValue))
             result = numberValue;
@@ -1468,23 +1408,35 @@ mDNSlocal void SandboxProcess(void)
 #endif // MDNS_NO_SANDBOX
 }
 
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+#define MDNS_OS_LOG_CATEGORY_INIT(NAME) \
+    do\
+    { \
+        mDNSLogCategory_ ## NAME = os_log_create("com.apple.mDNSResponder", # NAME ); \
+        if (!mDNSLogCategory_ ## NAME ) \
+        { \
+            os_log_error(OS_LOG_DEFAULT, "Could NOT create the " # NAME " log handle in mDNSResponder"); \
+            mDNSLogCategory_ ## NAME = OS_LOG_DEFAULT; \
+        } \
+    } \
+    while (0)
+
+os_log_t mDNSLogCategory_Default = NULL;
+os_log_t mDNSLogCategory_mDNS    = NULL;
+os_log_t mDNSLogCategory_uDNS    = NULL;
+os_log_t mDNSLogCategory_SPS     = NULL;
+os_log_t mDNSLogCategory_XPC     = NULL;
+
 mDNSlocal void init_logging(void)
 {
-    log_general      = os_log_create("com.apple.mDNSResponder", "AllINFO");
-    
-    if (!log_general)
-    {
-        // OS_LOG_DEFAULT is the default logging object, if you are not creating a custom subsystem/category
-        os_log_error(OS_LOG_DEFAULT, "Could NOT create log handle in mDNSResponder");
-    }
+    MDNS_OS_LOG_CATEGORY_INIT(Default);
+    MDNS_OS_LOG_CATEGORY_INIT(mDNS);
+    MDNS_OS_LOG_CATEGORY_INIT(uDNS);
+    MDNS_OS_LOG_CATEGORY_INIT(SPS);
+    MDNS_OS_LOG_CATEGORY_INIT(XPC);
 }
 #endif
 
-#ifdef UNIT_TEST
-// Run the unit test main
-UNITTEST_MAIN
-#else
 mDNSexport int main(int argc, char **argv)
 {
     int i;
@@ -1495,10 +1447,10 @@ mDNSexport int main(int argc, char **argv)
     bool useSandbox = mDNStrue;
 #endif
 
-#if APPLE_OSX_mDNSResponder
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
     init_logging();
 #endif
-    
+
     mDNSMacOSXSystemBuildNumber(NULL);
     LogMsg("%s starting %s %d", mDNSResponderVersionString, OSXVers ? "OSXVers" : "iOSVers", OSXVers ? OSXVers : iOSVers);
 
@@ -1582,10 +1534,10 @@ mDNSexport int main(int argc, char **argv)
     EnableBLEBasedDiscovery   = PreferencesGetValueBool(kPreferencesKey_EnableBLEBasedDiscovery,   EnableBLEBasedDiscovery);
     DefaultToBLETriggered     = PreferencesGetValueBool(kPreferencesKey_DefaultToBLETriggered,     DefaultToBLETriggered);
 #endif  // ENABLE_BLE_TRIGGERED_BONJOUR
+#endif
 
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, PREALLOCATED_CACHE)
     PreallocateCacheMemory    = PreferencesGetValueBool(kPreferencesKey_PreallocateCacheMemory,    PreallocateCacheMemory);
-#endif
 #endif
 
     // Note that mDNSPlatformInit will set DivertMulticastAdvertisements in the mDNS structure
@@ -1611,18 +1563,6 @@ mDNSexport int main(int argc, char **argv)
 #endif // MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
 
     mDNSStorage.p = &PlatformStorage;   // Make sure mDNSStorage.p is set up, because validatelists uses it
-    // Need to Start XPC Server Before LaunchdCheckin() (Reason: rdar11023750)
-    xpc_server_init();
-#if DEBUG
-    if (!useDebugSocket) {
-        if (LaunchdCheckin() == 0)
-            useDebugSocket = mDNStrue;
-    }
-    if (useDebugSocket)
-        SetDebugBoundPath();
-#else
-    LaunchdCheckin();
-#endif
 
 #ifndef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
 
@@ -1664,7 +1604,7 @@ mDNSexport int main(int argc, char **argv)
 #endif
     SandboxProcess();
 
-#if AWD_METRICS
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     status = MetricsInit();
     if (status) { LogMsg("Daemon start: MetricsInit failed (%d)", status); }
 #endif
@@ -1672,6 +1612,22 @@ mDNSexport int main(int argc, char **argv)
     status = mDNSDaemonInitialize();
     if (status) { LogMsg("Daemon start: mDNSDaemonInitialize failed"); goto exit; }
 
+    // Need to Start XPC Server Before LaunchdCheckin() (Reason: radar:11023750)
+    xpc_server_init();
+#if MDNSRESPONDER_SUPPORTS(APPLE, DNSSD_XPC_SERVICE)
+    dnssd_server_init();
+#endif
+#if DEBUG
+    if (!useDebugSocket) {
+        if (LaunchdCheckin() == 0)
+            useDebugSocket = mDNStrue;
+    }
+    if (useDebugSocket)
+        SetDebugBoundPath();
+#else
+    LaunchdCheckin();
+#endif
+
     status = udsserver_init(launchd_fds, launchd_fds_count);
     if (status) { LogMsg("Daemon start: udsserver_init failed"); goto exit; }
 
@@ -1700,14 +1656,16 @@ mDNSexport int main(int argc, char **argv)
 exit:
     return(status);
 }
-#endif // UNIT_TEST
 
 // uds_daemon.c support routines /////////////////////////////////////////////
 
-mDNSlocal void kqUDSEventCallback(int fd, short filter, void *context, __unused mDNSBool encounteredEOF)
+mDNSlocal void kqUDSEventCallback(int fd, short filter, void *context, mDNSBool encounteredEOF)
 {
     const KQSocketEventSource *const source = context;
-    source->callback(fd, filter, source->context);
+    (void)filter; // unused
+    (void)encounteredEOF; // unused
+    
+    source->callback(fd, source->context);
 }
 
 // Arrange things so that when data appears on fd, callback is called with context
@@ -1718,7 +1676,7 @@ mDNSexport mStatus udsSupportAddFDToEventLoop(int fd, udsEventCallback callback,
     while (*p && (*p)->fd != fd) p = &(*p)->next;
     if (*p) { LogMsg("udsSupportAddFDToEventLoop: ERROR fd %d already has EventLoop source entry", fd); return mStatus_AlreadyRegistered; }
 
-    KQSocketEventSource *newSource = (KQSocketEventSource*) mallocL("KQSocketEventSource", sizeof *newSource);
+    KQSocketEventSource *newSource = (KQSocketEventSource*) callocL("KQSocketEventSource", sizeof(*newSource));
     if (!newSource) return mStatus_NoMemoryErr;
 
     newSource->next           = mDNSNULL;
diff --git a/mDNSMacOSX/dnsctl-entitlements.plist b/mDNSMacOSX/dnsctl-entitlements.plist
deleted file mode 100644 (file)
index d724352..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.mDNSResponder.dnsproxy</key>
-    <true/>
-    <key>com.apple.mDNSResponder.dnsctl</key>
-    <true/>
-</dict>
-</plist>
diff --git a/mDNSMacOSX/dnssd.c b/mDNSMacOSX/dnssd.c
new file mode 100644 (file)
index 0000000..565dda6
--- /dev/null
@@ -0,0 +1,1350 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#include "dnssd_private.h"
+
+#include "dnssd_object.h"
+#include "dnssd_xpc.h"
+
+#include <CoreUtils/CoreUtils.h>
+#include <os/object_private.h>
+#include <xpc/private.h>
+
+#if 0
+//======================================================================================================================
+#pragma mark - Kind Declarations
+#endif
+
+#define DNSSD_STRUCT(NAME)     struct dnssd_ ## NAME ## _s
+#define DNSSD_TYPE(NAME)       dnssd_ ## NAME ## _t
+
+#define DNSSD_KIND_DECLARE(NAME)                                                                                                                               \
+       static DNSSD_TYPE(NAME)                                                                                                                                         \
+       _dnssd_ ## NAME ## _alloc(void);                                                                                                                        \
+                                                                                                                                                                                               \
+       static char *                                                                                                                                                           \
+       _dnssd_ ## NAME ## _copy_description(DNSSD_TYPE(NAME) object, bool debug, bool privacy);        \
+                                                                                                                                                                                               \
+       static void                                                                                                                                                                     \
+       _dnssd_ ## NAME ## _finalize(DNSSD_TYPE(NAME) object)
+
+// Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
+// comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
+// the warning hasn't been disabled.
+
+#define DNSSD_BASE_CHECK(NAME, SUPER)                                                                                                                                  \
+       check_compile_time(offsetof(DNSSD_STRUCT(NAME), base) == 0);                                                                            \
+       check_compile_time(sizeof_field(DNSSD_STRUCT(NAME), base) == sizeof(DNSSD_STRUCT(SUPER)));                      \
+       extern int _dnssd_base_type_check[sizeof(&(((DNSSD_TYPE(NAME))0)->base) == ((DNSSD_TYPE(SUPER))0))]
+
+#define DNSSD_KIND_DEFINE(NAME, SUPER)                                                                                         \
+       static const struct dnssd_kind_s _dnssd_ ## NAME ## _kind = {                           \
+               &_dnssd_ ## SUPER ## _kind,                                                                                             \
+               # NAME,                                                                                                                                 \
+               _dnssd_ ## NAME ## _copy_description,                                                                   \
+               _dnssd_ ## NAME ## _finalize,                                                                                   \
+       };                                                                                                                                                      \
+                                                                                                                                                               \
+       static DNSSD_TYPE(NAME)                                                                                                         \
+       _dnssd_ ## NAME ## _alloc(void)                                                                                         \
+       {                                                                                                                                                       \
+               DNSSD_TYPE(NAME) obj = dnssd_object_ ## NAME ## _alloc(sizeof(*obj));   \
+               require_quiet(obj, exit);                                                                                               \
+                                                                                                                                                               \
+               const dnssd_object_t base = (dnssd_object_t)obj;                                                \
+               base->kind = &_dnssd_ ## NAME ## _kind;                                                                 \
+                                                                                                                                                               \
+       exit:                                                                                                                                           \
+               return obj;                                                                                                                             \
+       }                                                                                                                                                       \
+       DNSSD_BASE_CHECK(NAME, SUPER)
+
+DNSSD_KIND_DECLARE(getaddrinfo);
+DNSSD_KIND_DECLARE(getaddrinfo_result);
+
+typedef char * (*dnssd_copy_description_f)(dnssd_any_t object, bool debug, bool privacy);
+typedef void   (*dnssd_finalize_f)(dnssd_any_t object);
+
+typedef const struct dnssd_kind_s *    dnssd_kind_t;
+struct dnssd_kind_s {
+       dnssd_kind_t                            superkind;                      // This kind's superkind.
+       const char *                            name;                           // Name of this kind.
+       dnssd_copy_description_f        copy_description;       // Creates a textual description of object.
+       dnssd_finalize_f                        finalize;                       // Releases object's resources right before the object is freed.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_object Kind Definition
+#endif
+
+struct dnssd_object_s {
+       _OS_OBJECT_HEADER(const void *_os_obj_isa, _os_obj_refcnt, _os_obj_xref_cnt);
+       dnssd_kind_t    kind;   // Pointer to an object's kind.
+};
+
+static const struct dnssd_kind_s _dnssd_object_kind = {
+       NULL,           // No superkind.
+       "object",
+       NULL,           // No copy_description method.
+       NULL,           // No finalize method.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo Kind Definition
+#endif
+
+typedef enum {
+       dnssd_getaddrinfo_state_nascent         = 0,
+       dnssd_getaddrinfo_state_starting        = 1,
+       dnssd_getaddrinfo_state_started         = 2,
+       dnssd_getaddrinfo_state_failed          = 3,
+       dnssd_getaddrinfo_state_invalidated     = 4,
+} dnssd_getaddrinfo_state_t;
+
+struct dnssd_getaddrinfo_s {
+       struct dnssd_object_s                           base;                   // Object base.
+       dnssd_getaddrinfo_t                                     next;                   // Next getaddrinfo object in list.
+       uint64_t                                                        command_id;             // Command ID.
+       dispatch_queue_t                                        user_queue;             // User's dispatch queue for invoking result and event handlers.
+       dispatch_queue_t                                        mutex_queue;    // Mutex for accessing result_list from different queues.
+       xpc_object_t                                            params;                 // Parameters dictionary for getaddrinfo command.
+       xpc_object_t                                            hostname;               // Reference to hostname from parameters dictionary.
+       dispatch_source_t                                       event_source;   // Data source for triggering result and event handlers.
+       dnssd_getaddrinfo_result_t                      result_list;    // List of getaddrinfo results.
+       dnssd_getaddrinfo_result_handler_t      result_handler; // User's result handler.
+       dnssd_event_handler_t                           event_handler;  // User's event handler.
+       dnssd_getaddrinfo_state_t                       state;                  // Internal state.
+       OSStatus                                                        error;                  // Pending error.
+       bool                                                            user_activated; // True if the object has been activated by user.
+};
+
+DNSSD_KIND_DEFINE(getaddrinfo, object);
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo_result Kind Definition
+#endif
+
+struct dnssd_getaddrinfo_result_s {
+       struct dnssd_object_s                   base;                           // Object base.
+       sockaddr_ip                                             addr;                           // IPv4 or IPv6 address of hostname.
+       xpc_object_t                                    hostname;                       // Requested hostname to resolve.
+       xpc_object_t                                    actual_hostname;        // The actual/canonical hostname of the requested hostname.
+       xpc_object_t                                    auth_tag;                       // Authentication tag.
+       uint32_t                                                interface_index;        // Interface index to which the result pertains.
+       dnssd_getaddrinfo_result_type_t type;                           // Type of getaddrinfo result.
+       dnssd_getaddrinfo_result_t              next;                           // Next getaddrinfo result in list.
+};
+
+DNSSD_KIND_DEFINE(getaddrinfo_result, object);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Constants
+#endif
+
+#define DNSSD_EVENT_HAVE_RESULTS       (1U << 0)       // Results are available.
+#define DNSSD_EVENT_REMOVE_ALL         (1U << 1)       // Previously delivered results are no longer valid.
+#define DNSSD_EVENT_ERROR                      (1U << 2)       // An error was encountered.
+
+// Strings for redacted description items.
+
+#define DNSSD_REDACTED_HOSTNAME_STR                    "<redacted hostname>"
+#define DNSSD_REDACTED_ACTUAL_HOSTNAME_STR     "<redacted actual hostname>"
+#define DNSSD_REDACTED_IPv4_ADDRESS_STR                "<redacted IPv4 address>"
+#define DNSSD_REDACTED_IPv6_ADDRESS_STR                "<redacted IPv6 address>"
+
+#if 0
+//======================================================================================================================
+#pragma mark - Local Prototypes
+#endif
+
+static dispatch_queue_t
+_dnssd_client_queue(void);
+
+static xpc_connection_t
+_dnssd_client_connection(void);
+
+static uint64_t
+_dnssd_client_get_new_id(void);
+
+static void
+_dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static OSStatus
+_dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error);
+
+static void
+_dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t gai, dnssd_getaddrinfo_result_t result_list);
+
+static void
+_dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t gai);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t gai, OSStatus error);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname, xpc_object_t result_dict, OSStatus *out_error);
+
+static DNSServiceErrorType
+_dnssd_osstatus_to_dns_service_error(OSStatus status);
+
+#if !defined(dnssd_release_null_safe)
+       #define dnssd_release_null_safe(X)      \
+               do {                                                    \
+                       if (X) {                                        \
+                               dnssd_release(X);               \
+                       }                                                       \
+               } while(0)
+#endif
+
+#if !defined(dnssd_forget)
+       #define dnssd_forget(X) ForgetCustom(X, dnssd_release)
+#endif
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_object Public Methods
+#endif
+
+void
+dnssd_retain(dnssd_any_t object)
+{
+       os_retain(object.base);
+}
+
+//======================================================================================================================
+
+void
+dnssd_release(dnssd_any_t object)
+{
+       os_release(object.base);
+}
+
+//======================================================================================================================
+
+char *
+dnssd_copy_description(dnssd_any_t object)
+{
+       return dnssd_object_copy_description(object, false, false);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_object Private Methods
+#endif
+
+char *
+dnssd_object_copy_description(dnssd_any_t object, bool debug, bool privacy)
+{
+       for (dnssd_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+               if (kind->copy_description) {
+                       char *desc = kind->copy_description(object, debug, privacy);
+                       return desc;
+               }
+       }
+       return NULL;
+}
+
+//======================================================================================================================
+
+void
+dnssd_object_finalize(dnssd_any_t object)
+{
+       for (dnssd_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+               if (kind->finalize) {
+                       kind->finalize(object);
+               }
+       }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo Public Methods
+#endif
+
+dnssd_getaddrinfo_t
+dnssd_getaddrinfo_create(void)
+{
+       dnssd_getaddrinfo_t     gai = NULL;
+       dnssd_getaddrinfo_t     obj = _dnssd_getaddrinfo_alloc();
+       require_quiet(obj, exit);
+
+       obj->params = xpc_dictionary_create(NULL, NULL, 0);
+       require_quiet(obj->params, exit);
+
+       obj->mutex_queue = dispatch_queue_create("com.apple.dnssd.getaddrinfo.mutex", DISPATCH_QUEUE_SERIAL);
+       require_quiet(obj->mutex_queue, exit);
+
+       gai = obj;
+       obj = NULL;
+
+exit:
+       dnssd_release_null_safe(obj);
+       return gai;
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t me, dispatch_queue_t queue)
+{
+       if (!me->user_activated) {
+               dispatch_retain(queue);
+               dispatch_release_null_safe(me->user_queue);
+               me->user_queue = queue;
+       } else if (!me->user_queue) {
+               me->user_queue = queue;
+               dispatch_retain(me->user_queue);
+               _dnssd_client_activate_getaddrinfo_async(me);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t me, DNSServiceFlags flags)
+{
+       if (!me->user_activated) {
+               dnssd_xpc_parameters_set_flags(me->params, flags);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t me, const char *hostname)
+{
+       if (!me->user_activated) {
+               dnssd_xpc_parameters_set_hostname(me->params, hostname);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t me, uint32_t interface_index)
+{
+       if (!me->user_activated) {
+               dnssd_xpc_parameters_set_interface_index(me->params, interface_index);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t me, DNSServiceProtocol protocols)
+{
+       if (!me->user_activated) {
+               dnssd_xpc_parameters_set_protocols(me->params, protocols);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t me, pid_t pid)
+{
+       if (!me->user_activated) {
+               dnssd_xpc_parameters_set_delegate_pid(me->params, pid);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t me, uuid_t uuid)
+{
+       if (!me->user_activated) {
+               dnssd_xpc_parameters_set_delegate_uuid(me->params, uuid);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_handler_t handler)
+{
+       dnssd_getaddrinfo_result_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+       if (me->result_handler) {
+               Block_release(me->result_handler);
+       }
+       me->result_handler = new_handler;
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t me, dnssd_event_handler_t handler)
+{
+       dnssd_event_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+       if (me->event_handler) {
+               Block_release(me->event_handler);
+       }
+       me->event_handler = new_handler;
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t me, bool need)
+{
+       if (!me->user_activated) {
+               dnssd_xpc_parameters_set_need_authentication_tags(me->params, need);
+       }
+}
+
+//======================================================================================================================
+
+void
+dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
+{
+       if (!me->user_activated) {
+               if (me->user_queue) {
+                       _dnssd_client_activate_getaddrinfo_async(me);
+               }
+               me->user_activated = true;
+       }
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me);
+
+void
+dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
+{
+       dnssd_retain(me);
+       dispatch_async(_dnssd_client_queue(),
+       ^{
+               _dnssd_client_invalidate_getaddrinfo(me);
+               dnssd_release(me);
+       });
+}
+
+static void
+_dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+       require_quiet(gai->state != dnssd_getaddrinfo_state_invalidated, exit);
+
+       _dnssd_client_deregister_getaddrinfo(gai);
+       if ((gai->state == dnssd_getaddrinfo_state_starting) || (gai->state == dnssd_getaddrinfo_state_started)) {
+               xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
+               if (msg) {
+                       dnssd_xpc_message_set_id(msg, gai->command_id);
+                       dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_STOP);
+                       xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
+                       ^(xpc_object_t reply)
+                       {
+                               (void)reply;
+                       });
+                       xpc_release(msg);
+               }
+       }
+       _dnssd_getaddrinfo_invalidate(gai);
+       gai->state = dnssd_getaddrinfo_state_invalidated;
+
+exit:
+       return;
+}
+
+static void
+_dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
+{
+       dispatch_source_forget(&me->event_source);
+       _dnssd_getaddrinfo_remove_all_results(me);
+
+       if (me->user_queue) {
+               dnssd_retain(me);
+               dispatch_async(me->user_queue,
+               ^{
+                       if (me->event_handler) {
+                               me->event_handler(dnssd_event_invalidated, kDNSServiceErr_NoError);
+                       }
+                       dnssd_release(me);
+               });
+       }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo Private Methods
+#endif
+
+static char *
+_dnssd_getaddrinfo_copy_description(dnssd_getaddrinfo_t me, const bool debug, const bool privacy)
+{
+       const char *hostname;
+       if (me->hostname) {
+               hostname = xpc_string_get_string_ptr(me->hostname);
+               if (privacy && hostname) {
+                       hostname = DNSSD_REDACTED_HOSTNAME_STR;
+               }
+       } else {
+               hostname = NULL;
+       }
+
+       char *  desc    = NULL;
+       char *  buf_ptr = NULL;
+       size_t  buf_len = 0;
+       for (;;)
+       {
+               size_t                  need    = 0;
+               char *                  dst             = buf_ptr;
+               char * const    end             = &buf_ptr[buf_len];
+               int                             n;
+
+               if (debug) {
+                       const size_t len = (size_t)(end - dst);
+                       n = snprintf(dst, len, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
+                       require_quiet(n >= 0, exit);
+
+                       if (buf_ptr) {
+                               dst = (((size_t)n) < len) ? &dst[n] : end;
+                       } else {
+                               need += (size_t)n;
+                       }
+               }
+               n = snprintf(dst, (size_t)(end - dst), "hostname = %s", hostname ? hostname : "<NO HOSTNAME>");
+               require_quiet(n >= 0, exit);
+
+               if (!buf_ptr) {
+                       need += (size_t)n;
+                       buf_len = need + 1;
+                       buf_ptr = malloc(buf_len);
+                       require_quiet(buf_ptr, exit);
+               } else {
+                       break;
+               }
+       }
+       desc    = buf_ptr;
+       buf_ptr = NULL;
+
+exit:
+       FreeNullSafe(buf_ptr);
+       return desc;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_finalize(dnssd_getaddrinfo_t me)
+{
+       dispatch_forget(&me->user_queue);
+       dispatch_forget(&me->mutex_queue);
+       xpc_forget(&me->params);
+       xpc_forget(&me->hostname);
+       BlockForget(&me->result_handler);
+       BlockForget(&me->event_handler);
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_t result_list)
+{
+       dispatch_sync(me->mutex_queue,
+       ^{
+               dnssd_getaddrinfo_result_t *ptr = &me->result_list;
+               while (*ptr) {
+                       ptr = &(*ptr)->next;
+               }
+               *ptr = result_list;
+       });
+       dispatch_source_merge_data(me->event_source, DNSSD_EVENT_HAVE_RESULTS);
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t me)
+{
+       dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
+       if (me->event_source) {
+               dispatch_source_merge_data(me->event_source, DNSSD_EVENT_REMOVE_ALL);
+       }
+
+       dnssd_getaddrinfo_result_t result;
+       while ((result = result_list) != NULL) {
+               result_list = result->next;
+               dnssd_release(result);
+       }
+}
+
+//======================================================================================================================
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t me)
+{
+       __block dnssd_getaddrinfo_result_t list;
+       dispatch_sync(me->mutex_queue,
+       ^{
+               list = me->result_list;
+               me->result_list = NULL;
+       });
+       return list;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t me, OSStatus error)
+{
+       dispatch_sync(me->mutex_queue,
+       ^{
+               me->error = error;
+       });
+       dispatch_source_merge_data(me->event_source, DNSSD_EVENT_ERROR);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo_result Public Methods
+#endif
+
+dnssd_getaddrinfo_result_type_t
+dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me)
+{
+       return me->type;
+}
+
+//======================================================================================================================
+
+const char *
+dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t me)
+{
+       return xpc_string_get_string_ptr(me->actual_hostname);
+}
+
+//======================================================================================================================
+
+const struct sockaddr *
+dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me)
+{
+       return &me->addr.sa;
+}
+
+//======================================================================================================================
+
+const char *
+dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t me)
+{
+       return xpc_string_get_string_ptr(me->hostname);
+}
+
+//======================================================================================================================
+
+uint32_t
+dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t me)
+{
+       return me->interface_index;
+}
+
+//======================================================================================================================
+
+const void *
+dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t me, size_t *out_length)
+{
+       const void *    auth_tag_ptr;
+       size_t                  auth_tag_len;
+
+       if (me->auth_tag) {
+               auth_tag_ptr = xpc_data_get_bytes_ptr(me->auth_tag);
+               auth_tag_len = xpc_data_get_length(me->auth_tag);
+       } else {
+               auth_tag_ptr = NULL;
+               auth_tag_len = 0;
+       }
+       if (out_length) {
+               *out_length = auth_tag_len;
+       }
+       return auth_tag_ptr;
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd_getaddrinfo_result Private Methods
+#endif
+
+static char *
+_dnssd_getaddrinfo_result_copy_description(dnssd_getaddrinfo_result_t me, const bool debug, const bool privacy)
+{
+       const char *hostname;
+       if (me->hostname) {
+               hostname = xpc_string_get_string_ptr(me->hostname);
+               if (privacy && hostname) {
+                       hostname = DNSSD_REDACTED_HOSTNAME_STR;
+               }
+       } else {
+               hostname = NULL;
+       }
+
+       const char *actual_hostname;
+       if (me->actual_hostname) {
+               actual_hostname = xpc_string_get_string_ptr(me->actual_hostname);
+               if (privacy && actual_hostname) {
+                       actual_hostname = DNSSD_REDACTED_ACTUAL_HOSTNAME_STR;
+               }
+       } else {
+               actual_hostname = NULL;
+       }
+       char addr_buf[INET6_ADDRSTRLEN];
+       check_compile_time_code(sizeof(addr_buf) >= INET_ADDRSTRLEN);
+       check_compile_time_code(sizeof(addr_buf) >= INET6_ADDRSTRLEN);
+
+       const char *addr;
+       if (me->addr.sa.sa_family == AF_INET) {
+               if (privacy) {
+                       addr = DNSSD_REDACTED_IPv4_ADDRESS_STR;
+               } else {
+                       addr = inet_ntop(AF_INET, &me->addr.v4.sin_addr.s_addr, addr_buf, (socklen_t)sizeof(addr_buf));
+               }
+       } else if (me->addr.sa.sa_family == AF_INET6) {
+               if (privacy) {
+                       addr = DNSSD_REDACTED_IPv6_ADDRESS_STR;
+               } else {
+                       addr = inet_ntop(AF_INET6, me->addr.v6.sin6_addr.s6_addr, addr_buf, (socklen_t)sizeof(addr_buf));
+               }
+       } else {
+               addr = NULL;
+       }
+
+       char *  desc    = NULL;
+       char *  buf_ptr = NULL;
+       size_t  buf_len = 0;
+       for (;;)
+       {
+               char *                  dst             = buf_ptr;
+               char * const    end             = &buf_ptr[buf_len];
+               size_t                  need    = 0;
+               int                             n;
+
+               if (debug) {
+                       const size_t len = (size_t)(end - dst);
+                       n = snprintf(dst, len, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
+                       require_quiet(n >= 0, exit);
+
+                       if (buf_ptr) {
+                               dst = (((size_t)n) < len) ? &dst[n] : end;
+                       } else {
+                               need += (size_t)n;
+                       }
+               }
+               n = snprintf(dst, (size_t)(end - dst), "[%s] %s (%s) -> %s (interface index %lu)",
+                       dnssd_getaddrinfo_result_type_to_string(me->type), hostname ? hostname : "<NO HOSTNAME>",
+                       actual_hostname ? actual_hostname : "<NO ACTUAL HOSTNAME>", addr ? addr : "<NO IP ADDRESS>",
+                       (unsigned long)me->interface_index);
+               require_quiet(n >= 0, exit);
+
+               if (!buf_ptr) {
+                       need += (size_t)n;
+                       buf_len = need + 1;
+                       buf_ptr = malloc(buf_len);
+                       require_quiet(buf_ptr, exit);
+               } else {
+                       break;
+               }
+       }
+       desc    = buf_ptr;
+       buf_ptr = NULL;
+
+exit:
+       FreeNullSafe(buf_ptr);
+       return desc;
+}
+
+//======================================================================================================================
+
+void
+_dnssd_getaddrinfo_result_finalize(dnssd_getaddrinfo_result_t me)
+{
+       xpc_forget(&me->hostname);
+       xpc_forget(&me->actual_hostname);
+       xpc_forget(&me->auth_tag);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - dnssd Client
+#endif
+
+static dnssd_getaddrinfo_t g_gai_list = NULL;
+
+static dispatch_queue_t
+_dnssd_client_queue(void)
+{
+       static dispatch_once_t  once    = 0;
+       static dispatch_queue_t queue   = NULL;
+
+       dispatch_once(&once,
+       ^{
+               dispatch_queue_attr_t const attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
+                       QOS_CLASS_UTILITY, 0);
+               queue = dispatch_queue_create("com.apple.dnssd.client", attr);
+       });
+       return queue;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_handle_message(xpc_object_t msg);
+static void
+_dnssd_client_handle_interruption(void);
+
+static xpc_connection_t
+_dnssd_client_connection(void)
+{
+       static dispatch_once_t  once            = 0;
+       static xpc_connection_t connection      = NULL;
+
+       dispatch_once(&once,
+       ^{
+               connection = xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME, _dnssd_client_queue(),
+                       XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+               xpc_connection_set_event_handler(connection,
+               ^(xpc_object_t event)
+               {
+                       if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
+                               _dnssd_client_handle_message(event);
+                       } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
+                               _dnssd_client_handle_interruption();
+                       }
+               });
+               xpc_connection_activate(connection);
+       });
+       return connection;
+}
+
+static void
+_dnssd_client_handle_message(xpc_object_t msg)
+{
+       const uint64_t command_id = dnssd_xpc_message_get_id(msg, NULL);
+       dnssd_getaddrinfo_t gai;
+       for (gai = g_gai_list; gai; gai = gai->next) {
+               if (gai->command_id == command_id) {
+                       break;
+               }
+       }
+       require_quiet(gai, exit);
+
+       const OSStatus error = dnssd_xpc_message_get_error(msg, NULL);
+       if (!error) {
+               xpc_object_t const result_array = dnssd_xpc_message_get_results(msg);
+               require_quiet(result_array, exit);
+
+               dnssd_getaddrinfo_result_t                              result_list     = NULL;
+               __block dnssd_getaddrinfo_result_t *    result_ptr      = &result_list;
+               xpc_array_apply(result_array,
+               ^bool(__unused size_t index, xpc_object_t result_dict)
+               {
+                       dnssd_getaddrinfo_result_t result = _dnssd_getaddrinfo_result_create_from_dictionary(gai->hostname,
+                               result_dict, NULL);
+                       if (result) {
+                               *result_ptr     = result;
+                               result_ptr      = &result->next;
+                       }
+                       return true;
+               });
+               require_quiet(result_list, exit);
+
+               _dnssd_getaddrinfo_append_results(gai, result_list);
+               result_list = NULL;
+       } else {
+               _dnssd_client_fail_getaddrinfo(gai, error);
+       }
+
+exit:
+       return;
+}
+
+static void
+_dnssd_client_handle_interruption(void)
+{
+       dnssd_getaddrinfo_t next_gai;
+       for (dnssd_getaddrinfo_t gai = g_gai_list; gai; gai = next_gai) {
+               next_gai = gai->next;
+               gai->state = dnssd_getaddrinfo_state_starting;
+               const OSStatus err = _dnssd_client_send_getaddrinfo_command(gai);
+               if (!err) {
+                       _dnssd_getaddrinfo_remove_all_results(gai);
+               } else {
+                       _dnssd_client_fail_getaddrinfo(gai, err);
+               }
+       }
+}
+
+//======================================================================================================================
+
+static uint64_t
+_dnssd_client_get_new_id(void)
+{
+       static uint64_t last_id = 0;
+       return ++last_id;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai);
+
+static OSStatus
+_dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai);
+
+static void
+_dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai)
+{
+       dnssd_retain(gai);
+       dispatch_async(_dnssd_client_queue(),
+       ^{
+               _dnssd_client_activate_getaddrinfo(gai);
+               dnssd_release(gai);
+       });
+}
+
+static void
+_dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+       OSStatus err;
+       require_action_quiet(gai->state == dnssd_getaddrinfo_state_nascent, exit, err = kNoErr);
+
+       err = _dnssd_getaddrinfo_activate(gai);
+       if (err) {
+               gai->state = dnssd_getaddrinfo_state_failed;
+               goto exit;
+       }
+
+       gai->command_id = _dnssd_client_get_new_id();
+       gai->state = dnssd_getaddrinfo_state_starting;
+
+       _dnssd_client_register_getaddrinfo(gai);
+
+       err = _dnssd_client_send_getaddrinfo_command(gai);
+       if (err) {
+               _dnssd_client_fail_getaddrinfo(gai, err);
+       }
+
+exit:
+       return;
+}
+
+static void
+_dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t gai, unsigned long events);
+
+static OSStatus
+_dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
+{
+       OSStatus err;
+       xpc_object_t const hostname = dnssd_xpc_parameters_get_hostname_object(me->params);
+       require_action_quiet(hostname, exit, err = kParamErr);
+
+       me->hostname = xpc_copy(hostname);
+       require_action_quiet(me->hostname, exit, err = kNoResourcesErr);
+
+       me->event_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR, 0, 0, me->user_queue);
+       require_action_quiet(me->event_source, exit, err = kNoResourcesErr);
+
+       dnssd_retain(me);
+       dispatch_source_t const event_source = me->event_source;
+       dispatch_source_set_event_handler(me->event_source,
+       ^{
+               _dnssd_getaddrinfo_process_events(me, dispatch_source_get_data(event_source));
+       });
+       dispatch_source_set_cancel_handler(me->event_source,
+       ^{
+               dnssd_release(me);
+       });
+       dispatch_activate(me->event_source);
+       err = kNoErr;
+
+exit:
+       if (err) {
+               dnssd_retain(me);
+               dispatch_async(me->user_queue,
+               ^{
+                       if (me->event_handler) {
+                               me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(err));
+                       }
+                       dnssd_release(me);
+               });
+       }
+       return err;
+}
+
+static void
+_dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t me, unsigned long events)
+{
+       if (events & DNSSD_EVENT_REMOVE_ALL) {
+               if (me->event_handler) {
+                       me->event_handler(dnssd_event_remove_all, kDNSServiceErr_NoError);
+               }
+       }
+
+       if (events & DNSSD_EVENT_HAVE_RESULTS) {
+               dnssd_getaddrinfo_result_t result;
+               dnssd_getaddrinfo_result_t result_array[32];
+               dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
+
+               size_t result_count = 0;
+               while ((result = result_list) != NULL) {
+                       result_list             = result->next;
+                       result->next    = NULL;
+                       result_array[result_count++] = result;
+
+                       if ((result_count == countof(result_array)) || !result_list) {
+                               if (me->result_handler) {
+                                       me->result_handler(result_array, result_count);
+                               }
+                               for (size_t i = 0; i < result_count; ++i) {
+                                       dnssd_release(result_array[i]);
+                               }
+                               result_count = 0;
+                       }
+               }
+       }
+
+       if (events & DNSSD_EVENT_ERROR) {
+               __block OSStatus error;
+               dispatch_sync(me->mutex_queue,
+               ^{
+                       error = me->error;
+                       me->error = kNoErr;
+               });
+               if (me->event_handler && error) {
+                       me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(error));
+               }
+       }
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+       gai->next       = g_gai_list;
+       g_gai_list      = gai;
+       dnssd_retain(gai);
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai)
+{
+       dnssd_getaddrinfo_t *ptr;
+       for (ptr = &g_gai_list; *ptr; ptr = &(*ptr)->next)
+       {
+               if (*ptr == gai) {
+                       break;
+               }
+       }
+       if (*ptr) {
+               *ptr = gai->next;
+               gai->next = NULL;
+               dnssd_release(gai);
+       }
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply);
+
+static OSStatus
+_dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai)
+{
+       OSStatus err;
+       xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
+       require_action_quiet(msg, exit, err = kNoResourcesErr);
+
+       dnssd_xpc_message_set_id(msg, gai->command_id);
+       dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_GETADDRINFO);
+       dnssd_xpc_message_set_parameters(msg, gai->params);
+
+       dnssd_retain(gai);
+       xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
+       ^(xpc_object_t reply)
+       {
+               _dnssd_client_handle_getaddrinfo_reply(gai, reply);
+               dnssd_release(gai);
+       });
+       xpc_release(msg);
+       err = kNoErr;
+
+exit:
+       return err;
+}
+
+static void
+_dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply)
+{
+       require_quiet(gai->state == dnssd_getaddrinfo_state_starting, exit);
+
+       if (xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
+               const OSStatus error = dnssd_xpc_message_get_error(reply, NULL);
+               if (error) {
+                       _dnssd_client_fail_getaddrinfo(gai, error);
+               } else {
+                       gai->state = dnssd_getaddrinfo_state_started;
+               }
+       } else if (reply != XPC_ERROR_CONNECTION_INTERRUPTED) {
+               OSStatus error;
+               if (reply == XPC_ERROR_CONNECTION_INVALID) {
+                       error = kDNSServiceErr_ServiceNotRunning;
+               } else {
+                       error = kDNSServiceErr_Unknown;
+               }
+               _dnssd_client_fail_getaddrinfo(gai, error);
+       }
+
+exit:
+       return;
+}
+
+//======================================================================================================================
+
+static void
+_dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error)
+{
+       _dnssd_client_deregister_getaddrinfo(gai);
+       gai->state = dnssd_getaddrinfo_state_failed;
+       _dnssd_getaddrinfo_post_error_event(gai, error);
+}
+
+//======================================================================================================================
+//     _dnssd_getaddrinfo_result_create_from_dictionary
+//======================================================================================================================
+
+static bool
+_dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
+       DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
+       xpc_object_t *out_rdata, xpc_object_t *out_auth_tag);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type, xpc_object_t hostname,
+       xpc_object_t actual_hostname, int addr_family, const void *addr_data, uint32_t interface_index,
+       xpc_object_t auth_tag, OSStatus *out_error);
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname, xpc_object_t result_dict, OSStatus *out_error)
+{
+       OSStatus                                        err;
+       xpc_object_t                            actual_hostname, rdata, auth_tag;
+       DNSServiceErrorType                     error;
+       DNSServiceFlags                         flags;
+       uint32_t                                        interface_index;
+       uint16_t                                        rtype;
+       dnssd_getaddrinfo_result_t      result = NULL;
+
+       const bool success = _dnssd_extract_result_dict_values(result_dict, &actual_hostname, &error, &flags,
+               &interface_index, &rtype, NULL, &rdata, &auth_tag);
+       require_action_quiet(success, exit, err = kMalformedErr);
+
+       if ((error != kDNSServiceErr_NoError) &&
+               (error != kDNSServiceErr_NoSuchRecord)) {
+               err = kUnexpectedErr;
+               goto exit;
+       }
+       require_action_quiet((rtype == kDNSServiceType_A) || (rtype == kDNSServiceType_AAAA), exit, err = kTypeErr);
+
+       dnssd_getaddrinfo_result_type_t result_type;
+       if (error == kDNSServiceErr_NoSuchRecord) {
+               result_type = dnssd_getaddrinfo_result_type_no_address;
+       } else {
+               if (flags & kDNSServiceFlagsAdd) {
+                       if (flags & kDNSServiceFlagsExpiredAnswer) {
+                               result_type = dnssd_getaddrinfo_result_type_expired;
+                       } else {
+                               result_type = dnssd_getaddrinfo_result_type_add;
+                       }
+               } else {
+                       result_type = dnssd_getaddrinfo_result_type_remove;
+               }
+               if (rtype == kDNSServiceType_A) {
+                       require_action_quiet(xpc_data_get_length(rdata) == 4, exit, err = kMalformedErr);
+               } else {
+                       require_action_quiet(xpc_data_get_length(rdata) == 16, exit, err = kMalformedErr);
+               }
+       }
+       const int addr_family = (rtype == kDNSServiceType_A) ? AF_INET : AF_INET6;
+       result = _dnssd_getaddrinfo_result_create(result_type, hostname, actual_hostname, addr_family,
+               xpc_data_get_bytes_ptr(rdata), interface_index, auth_tag, &err);
+       require_noerr_quiet(err, exit);
+
+exit:
+       if (err) {
+               dnssd_forget(&result);
+       }
+       if (out_error) {
+               *out_error = err;
+       }
+       return result;
+}
+
+static bool
+_dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
+       DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
+       xpc_object_t *out_rdata, xpc_object_t *out_auth_tag)
+{
+       bool result_is_valid = false;
+       xpc_object_t const hostname = dnssd_xpc_result_get_record_name_object(result);
+       require_quiet(hostname, exit);
+
+       xpc_object_t const rdata = dnssd_xpc_result_get_record_data_object(result);
+       require_quiet(rdata, exit);
+
+       if (out_hostname) {
+               *out_hostname = hostname;
+       }
+       if (out_error) {
+               *out_error = dnssd_xpc_result_get_error(result, NULL);
+       }
+       if (out_flags) {
+               *out_flags = dnssd_xpc_result_get_flags(result, NULL);
+       }
+       if (out_interface_index) {
+               *out_interface_index = dnssd_xpc_result_get_interface_index(result, NULL);
+       }
+       if (out_type) {
+               *out_type = dnssd_xpc_result_get_record_type(result, NULL);
+       }
+       if (out_class) {
+               *out_class = dnssd_xpc_result_get_record_class(result, NULL);
+       }
+       if (out_rdata) {
+               *out_rdata = rdata;
+       }
+       if (out_auth_tag) {
+               *out_auth_tag = dnssd_xpc_result_get_authentication_tag_object(result);
+       }
+       result_is_valid = true;
+
+exit:
+       return result_is_valid;
+}
+
+static dnssd_getaddrinfo_result_t
+_dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type, xpc_object_t hostname,
+       xpc_object_t actual_hostname, int addr_family, const void *addr_data, uint32_t interface_index,
+       xpc_object_t auth_tag, OSStatus *out_error)
+{
+       OSStatus err;
+       dnssd_getaddrinfo_result_t result = NULL;
+       dnssd_getaddrinfo_result_t obj = _dnssd_getaddrinfo_result_alloc();
+       require_action_quiet(obj, exit, err = kNoMemoryErr);
+
+       switch (type) {
+               case dnssd_getaddrinfo_result_type_add:
+               case dnssd_getaddrinfo_result_type_remove:
+               case dnssd_getaddrinfo_result_type_no_address:
+               case dnssd_getaddrinfo_result_type_expired:
+                       break;
+
+               default:
+                       err = kTypeErr;
+                       goto exit;
+       }
+       obj->type                               = type;
+       obj->interface_index    = interface_index;
+
+       require_action_quiet(xpc_get_type(hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
+
+       obj->hostname = xpc_copy(hostname);
+       require_action_quiet(obj->hostname, exit, err = kNoResourcesErr);
+
+       require_action_quiet(xpc_get_type(actual_hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
+
+       obj->actual_hostname = xpc_copy(actual_hostname);
+       require_action_quiet(obj->actual_hostname, exit, err = kNoResourcesErr);
+
+       require_action_quiet((addr_family == AF_INET) || (addr_family == AF_INET6), exit, err = kTypeErr);
+
+       if (addr_family == AF_INET) {
+               obj->addr.sa.sa_family  = AF_INET;
+               obj->addr.v4.sin_len    = sizeof(struct sockaddr_in);
+               if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
+                       memcpy(&obj->addr.v4.sin_addr.s_addr, addr_data, 4);
+               }
+       } else {
+               obj->addr.sa.sa_family  = AF_INET6;
+               obj->addr.v6.sin6_len   = sizeof(struct sockaddr_in6);
+               if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
+                       memcpy(&obj->addr.v6.sin6_addr.s6_addr, addr_data, 16);
+               }
+       }
+
+       if (auth_tag) {
+               require_action_quiet(xpc_get_type(auth_tag) == XPC_TYPE_DATA, exit, err = kTypeErr);
+
+               obj->auth_tag = xpc_copy(auth_tag);
+               require_action_quiet(obj->auth_tag, exit, err = kNoResourcesErr);
+       }
+       result  = obj;
+       obj             = NULL;
+       err = kNoErr;
+
+exit:
+       if (out_error) {
+               *out_error = err;
+       }
+       dnssd_release_null_safe(obj);
+       return result;
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Misc. Helpers
+#endif
+
+static DNSServiceErrorType
+_dnssd_osstatus_to_dns_service_error(OSStatus error)
+{
+       switch (error) {
+               case kNoMemoryErr:
+               case kNoResourcesErr:
+                       error = kDNSServiceErr_NoMemory;
+                       break;
+
+               case kParamErr:
+                       error = kDNSServiceErr_BadParam;
+                       break;
+
+               default:
+                       if ((error >= kGenericErrorBase) && (error <= kGenericErrorEnd)) {
+                               error = kDNSServiceErr_Unknown;
+                       }
+                       break;
+       }
+       return error;
+}
diff --git a/mDNSMacOSX/dnssd_object.h b/mDNSMacOSX/dnssd_object.h
new file mode 100644 (file)
index 0000000..3a1c73d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef __DNSSD_OBJECT_H__
+#define __DNSSD_OBJECT_H__
+
+#include "dnssd_private.h"
+
+//======================================================================================================================
+#pragma mark - dnssd_object Private Method Declarations
+
+char *
+dnssd_object_copy_description(dnssd_any_t object, bool debug, bool privacy);
+
+void
+dnssd_object_finalize(dnssd_any_t object);
+
+#define DNSSD_OBJECT_ALLOC_DECLARE(NAME)               \
+       dnssd_ ## NAME ## _t                                            \
+       dnssd_object_ ## NAME ## _alloc(size_t size)
+
+DNSSD_OBJECT_ALLOC_DECLARE(getaddrinfo);
+DNSSD_OBJECT_ALLOC_DECLARE(getaddrinfo_result);
+
+#endif // __DNSSD_OBJECT_H__
diff --git a/mDNSMacOSX/dnssd_object.m b/mDNSMacOSX/dnssd_object.m
new file mode 100644 (file)
index 0000000..104dee3
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#import "dnssd_object.h"
+
+#import <stdlib.h>
+#import <Foundation/Foundation.h>
+#import <os/object_private.h>
+
+#if 0
+//======================================================================================================================
+#pragma mark - Class Declarations
+#endif
+
+#define DNSSD_OBJECT_CLASS_DECLARE(NAME)                                                               \
+       _OS_OBJECT_DECL_SUBCLASS_INTERFACE(dnssd_ ## NAME, dnssd_object)        \
+       extern int _dnssd_dummy_variable
+
+_OS_OBJECT_DECL_SUBCLASS_INTERFACE(dnssd_object, object)
+
+DNSSD_OBJECT_CLASS_DECLARE(getaddrinfo);
+DNSSD_OBJECT_CLASS_DECLARE(getaddrinfo_result);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Class Definitions
+#endif
+
+@implementation OS_OBJECT_CLASS(dnssd_object)
+- (void)dealloc
+{
+       dnssd_object_finalize(self);
+       [super dealloc];
+}
+
+- (NSString *)description
+{
+       char * const desc = dnssd_object_copy_description(self, false, false);
+       if (desc) {
+               NSString * const string = [NSString stringWithUTF8String:desc];
+               free(desc);
+               return string;
+       } else {
+               return nil;
+       }
+}
+
+- (NSString *)debugDescription
+{
+       char * const desc = dnssd_object_copy_description(self, true, false);
+       if (desc) {
+               NSString * const string = [NSString stringWithUTF8String:desc];
+               free(desc);
+               return string;
+       } else {
+               return nil;
+       }
+}
+
+- (NSString *)redactedDescription
+{
+       char * const desc = dnssd_object_copy_description(self, false, true);
+       if (desc) {
+               NSString * const string = [NSString stringWithUTF8String:desc];
+               free(desc);
+               return string;
+       } else {
+               return nil;
+       }
+}
+@end
+
+#define DNSSD_CLASS(NAME)      OS_OBJECT_CLASS(dnssd_ ## NAME)
+#define DNSSD_OBJECT_CLASS_DEFINE(NAME)                                                                                                        \
+       @implementation DNSSD_CLASS(NAME)                                                                                                       \
+       @end                                                                                                                                                            \
+                                                                                                                                                                               \
+       dnssd_ ## NAME ## _t                                                                                                                            \
+       dnssd_object_ ## NAME ## _alloc(const size_t size)                                                                      \
+       {                                                                                                                                                                       \
+               return (dnssd_## NAME ##_t)_os_object_alloc([DNSSD_CLASS(NAME) class], size);   \
+       }                                                                                                                                                                       \
+       extern int _dnssd_dummy_variable
+
+DNSSD_OBJECT_CLASS_DEFINE(getaddrinfo);
+DNSSD_OBJECT_CLASS_DEFINE(getaddrinfo_result);
diff --git a/mDNSMacOSX/dnssd_private.h b/mDNSMacOSX/dnssd_private.h
new file mode 100644 (file)
index 0000000..cfe87f9
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef __DNSSD_PRIVATE_H__
+#define __DNSSD_PRIVATE_H__
+
+#include <dispatch/dispatch.h>
+#include <dns_sd.h>
+#include <os/object.h>
+
+#if OS_OBJECT_USE_OBJC
+       #define DNSSD_DECL(NAME)                OS_OBJECT_DECL_SUBCLASS(dnssd_ ## NAME, dnssd_object)
+       #define DNSSD_RETURNS_RETAINED  OS_OBJECT_RETURNS_RETAINED
+
+       OS_OBJECT_DECL(dnssd_object,);
+#else
+       #define DNSSD_DECL(NAME)                typedef struct dnssd_ ## NAME ## _s *   dnssd_ ## NAME ## _t
+       #define DNSSD_RETURNS_RETAINED
+
+       DNSSD_DECL(object);
+#endif
+
+#define DNSSD_ASSUME_NONNULL_BEGIN     OS_ASSUME_NONNULL_BEGIN
+#define DNSSD_ASSUME_NONNULL_END       OS_ASSUME_NONNULL_END
+
+DNSSD_DECL(getaddrinfo);
+DNSSD_DECL(getaddrinfo_result);
+
+DNSSD_ASSUME_NONNULL_BEGIN
+
+#if OS_OBJECT_USE_OBJC
+       typedef dnssd_object_t  dnssd_any_t;
+#else
+       #if !defined(__cplusplus)
+               typedef union {
+                       dnssd_object_t                          base;
+                       dnssd_getaddrinfo_t                     gai;
+                       dnssd_getaddrinfo_result_t      gai_result;
+               } dnssd_any_t __attribute__((__transparent_union__));
+       #else
+               typedef void *  dnssd_any_t;
+       #endif
+#endif
+
+#define DNSSD_MALLOC   __attribute__((__malloc__))
+#define DNSSD_AVAILABLE        SPI_AVAILABLE(macos(10.15), ios(13.0), watchos(6.0), tvos(13.0))
+
+__BEGIN_DECLS
+
+/*!
+ *     @brief
+ *             Increments the reference count of a dnssd object.
+ *
+ *     @param object
+ *             The dnssd object.
+ *
+ *     @discussion
+ *             Calls to dnssd_retain() must be balanced with calls to dnssd_release().
+ */
+DNSSD_AVAILABLE
+void
+dnssd_retain(dnssd_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+#undef dnssd_retain
+#define dnssd_retain(object)   [(object) retain]
+#endif
+
+/*!
+ *     @brief
+ *             Decrements the reference count of a dnssd object.
+ *
+ *     @param object
+ *             The dnssd object.
+ *
+ *     @discussion
+ *             Calls to dnssd_retain() must be balanced with calls to dnssd_release().
+ */
+DNSSD_AVAILABLE
+void
+dnssd_release(dnssd_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+#undef dnssd_release
+#define dnssd_release(object)  [(object) release]
+#endif
+
+
+/*!
+ *     @brief
+ *             Provides a textual description of a dnssd object.
+ *
+ *     @param object
+ *             The dnssd object.
+ *
+ *     @result
+ *             Textual description of the object as a C string.
+ *
+ *     @discussion
+ *             The string returned by this function must be released with <code>free(3)</code>.
+ */
+DNSSD_AVAILABLE
+DNSSD_MALLOC char * _Nullable
+dnssd_copy_description(dnssd_any_t object);
+
+/*!
+ *     @brief
+ *             Creates a getaddrinfo object.
+ *
+ *     @result
+ *             A new getaddrinfo object.
+ *
+ *     @discussion
+ *             A getaddrinfo object resolves a hostname to its IPv4 and IPv6 addresses.
+ */
+DNSSD_AVAILABLE
+DNSSD_RETURNS_RETAINED dnssd_getaddrinfo_t _Nullable
+dnssd_getaddrinfo_create(void);
+
+/*!
+ *     @brief
+ *             Specifies the queue on which to invoke the getaddrinfo object's result and event blocks.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param queue
+ *             A serial queue.
+ *
+ *     @discussion
+ *             This call must be made before activating the getaddrinfo object.
+ *
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t gai, dispatch_queue_t queue);
+
+/*!
+ *     @brief
+ *             Specifies the DNSServiceFlags to use for the getaddrinfo operation.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param flags
+ *             Flags.
+ *
+ *     @discussion
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t gai, DNSServiceFlags flags);
+
+/*!
+ *     @brief
+ *             Specifies the hostname to resolve.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param hostname
+ *             Hostname as a fully-qualified domain name.
+ *
+ *     @discussion
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t gai, const char *hostname);
+
+/*!
+ *     @brief
+ *             Specifies the index of the interface via which to resolve the hostname.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param interface_index
+ *             Interface index.
+ *
+ *     @discussion
+ *             If <code>kDNSServiceInterfaceIndexAny</code> is used as the interface index, then special behavior applies. If
+ *             the hostname is in the "local." domain, then an attempt will be made to resolve the hostname via all active
+ *             mDNS-capable interfaces. If the hostname is in any other domain, then the hostname will be resolved via the
+ *             primary interface.
+ *
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t gai, uint32_t interface_index);
+
+/*!
+ *     @brief
+ *             Specifies the types of addresses to which to resolve the hostname.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param protocols
+ *             Protocols.
+ *
+ *     @discussion
+ *             Set <code>protocols</code> to <code>kDNSServiceProtocol_IPv4</code> to resolve the hostname to IPv4 addresses.
+ *
+ *             Set <code>protocols</code> to <code>kDNSServiceProtocol_IPv6</code> to resolve the hostname to IPv6 addresses.
+ *
+ *             Set <code>protocols</code> to <code>kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6</code> to resolve the
+ *             hostname to both IPv4 and IPv6 addresses.
+ *
+ *             Set <code>protocols</code> to 0 to limit resolution to addresses of protocols of which the host has routable
+ *             addresses. That is, an attempt will be made to resolve the hostname to IPv4 addresses if and only if the host
+ *             has a routable IPv4 address. Likewise, an attempt will be made to resolve the hostname to IPv6 addresses if and
+ *             only if the host has a routable IPv6 address.
+ *
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t gai, DNSServiceProtocol protocols);
+
+/*!
+ *     @brief
+ *             Sets the process ID (PID) of the process on whose behalf the getaddrinfo operation is being performed.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param pid
+ *             PID of the process being represented.
+ *
+ *     @discussion
+ *             If a delegate PID is set, then the calling process must have the proper entitlement in order for the
+ *             getaddrinfo operation to not fail with a kDNSServiceErr_NotAuth error.
+ *
+ *             This function is an alternative to <code>dnssd_getaddrinfo_set_delegate_uuid()</code>.
+ *
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t gai, pid_t pid);
+
+/*!
+ *     @brief
+ *             Sets the UUID of the process on whose behalf the getaddrinfo operation is being performed.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param uuid
+ *             UUID of the process being represented.
+ *
+ *     @discussion
+ *             If a delegate UUID is set, then the calling process must have the proper entitlement in order for the
+ *             getaddrinfo operation to not fail with the <code>kDNSServiceErr_NotAuth</code> error.
+ *
+ *             This function is an alternative to <code>dnssd_getaddrinfo_set_delegate_pid()</code>.
+ *
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t gai, uuid_t _Nonnull uuid);
+
+/*!
+ *     @brief
+ *             Specifies whether or not getaddrinfo results (of types <code>dnssd_getaddrinfo_result_type_add</code> and
+ *             <code>dnssd_getaddrinfo_result_type_expired</code>) should include authentication tags from the stub resolver.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param need
+ *             Pass <code>true</code> if authenticated results are needed, otherwise, pass <code>false</code>.
+ *
+ *     @discussion
+ *             This function has no effect on a getaddrinfo object that has been activated or invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t gai, bool need);
+
+/*!
+ *     @brief
+ *             Activates a getaddrinfo object.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @discussion
+ *             This function has no effect on a getaddrinfo object that has already been activated or has been invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai);
+
+/*!
+ *     @brief
+ *             Asynchronously invalidates a getaddrinfo object.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @discussion
+ *             As a result of calling this function, the getaddrinfo object's event handler will be invoked with a
+ *             <code>dnssd_event_invalidated</code> event. After this, the object's event and result handlers will never be
+ *             invoked again.
+ *
+ *             This function has no effect on a getaddrinfo object that has already been invalidated.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t gai);
+
+/*!
+ *     @brief
+ *             Handler for getaddrinfo results.
+ *
+ *     @param result_array
+ *             C array of getaddrinfo results.
+ *
+ *     @param result_count
+ *             Size of the array in terms of number of results.
+ */
+typedef void (^dnssd_getaddrinfo_result_handler_t)(dnssd_getaddrinfo_result_t _Nonnull * _Nonnull result_array,
+                                                                                                  size_t result_count);
+
+/*!
+ *     @brief
+ *             Specifies a getaddrinfo object's result handler.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param handler
+ *             Result handler.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t gai, dnssd_getaddrinfo_result_handler_t _Nullable handler);
+
+/*!
+ *     @brief
+ *             Events that can occur during the lifetime of a getaddrinfo object.
+ */
+typedef enum {
+       /*! @const dnssd_event_error An error occurred. */
+       dnssd_event_error               = 1,
+       /*! @const dnssd_event_remove_all All results prior to this event are no longer valid. */
+       dnssd_event_remove_all  = 2,
+       /*! @const dnssd_event_invalidated The object has been invalidated. */
+       dnssd_event_invalidated = 3,
+} dnssd_event_t;
+
+/*!
+ *     @brief
+ *             Handler for getaddrinfo events.
+ *
+ *     @param event
+ *             Event.
+ *
+ *     @param error
+ *             The error associated with a <code>dnssd_event_error</code> event. Ignore for all other types of events.
+ *
+ *     @discussion
+ *             After a <code>dnssd_event_invalidated</code> event, a getaddrinfo object's result and event handlers will never
+ *             be invoked again.
+ */
+typedef void (^dnssd_event_handler_t)(dnssd_event_t event, DNSServiceErrorType error);
+
+/*!
+ *     @brief
+ *             Sets a getaddrinfo object's event handler.
+ *
+ *     @param gai
+ *             The getaddrinfo object.
+ *
+ *     @param handler
+ *             Event handler.
+ */
+DNSSD_AVAILABLE
+void
+dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t gai, dnssd_event_handler_t _Nullable handler);
+
+/*!
+ *     @brief
+ *             Types of getaddrinfo results.
+ */
+typedef enum {
+       /*! @const dnssd_getaddrinfo_result_type_add The contained hostname and address pair is valid. */
+       dnssd_getaddrinfo_result_type_add                       = 1,
+       /*! @const dnssd_getaddrinfo_result_type_remove The contained hostname and address pair is no longer valid. */
+       dnssd_getaddrinfo_result_type_remove            = 2,
+       /*! @const dnssd_getaddrinfo_result_type_no_address The contained hostname has no address of a particular type. */
+       dnssd_getaddrinfo_result_type_no_address        = 3,
+       /*! @const dnssd_getaddrinfo_result_type_expired A hostname and address pair contained came from an expired cached record and may no longer be valid. */
+       dnssd_getaddrinfo_result_type_expired           = 4,
+} dnssd_getaddrinfo_result_type_t;
+
+/*!
+ *     @brief
+ *             Gets a getaddrinfo result's type.
+ *
+ *     @param gai_result
+ *             The getaddrinfo result.
+ *
+ *     @result
+ *             Result type.
+ */
+DNSSD_AVAILABLE
+dnssd_getaddrinfo_result_type_t
+dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ *     @brief
+ *             Gets a getaddrinfo result's actual hostname.
+ *
+ *     @param gai_result
+ *             The getaddrinfo result.
+ *
+ *     @result
+ *             The getaddrinfo result's actual hostname.
+ *
+ *     @discussion
+ *             The hostname returned by this function is the canonical name of the hostname that was requested. In other
+ *             words, it's the canonical name of the hostname set with <code>dnssd_getaddrinfo_set_hostname()</code>.
+ *
+ *             The pointer returned by this function is valid until the getaddrinfo result is released.
+ */
+DNSSD_AVAILABLE
+const char *
+dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ *     @brief
+ *             Gets a getaddrinfo result's address.
+ *
+ *     @param gai_result
+ *             The getaddrinfo result.
+ *
+ *     @result
+ *             The getaddrinfo result's address as a sockaddr structure.
+ *
+ *     @discussion
+ *             For getaddrinfo results of type <code>dnssd_getaddrinfo_result_type_no_address</code>, the sockaddr structure's
+ *             sa_family member variable can be used to determine the type of address that the hostname lacks.
+ */
+DNSSD_AVAILABLE
+const struct sockaddr *
+dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ *     @brief
+ *             Gets a getaddrinfo result's hostname.
+ *
+ *     @param gai_result
+ *             The getaddrinfo result.
+ *
+ *     @result
+ *             The getaddrinfo result's hostname.
+ *
+ *     @discussion
+ *             The hostname returned by this function is the hostname whose resolution was requested. In other words, it's
+ *             equal to the hostname set with <code>dnssd_getaddrinfo_set_hostname()</code>.
+ *
+ *             The pointer returned by this function is valid until the getaddrinfo result is released.
+ */
+DNSSD_AVAILABLE
+const char *
+dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ *     @brief
+ *             Gets the interface index to which a getaddrinfo result pertains.
+ *
+ *     @param gai_result
+ *             The getaddrinfo result.
+ *
+ *     @result
+ *             For hostnames that were resolved via mDNS, the return value is the index of the interface via which the
+ *             hostname was resolved. For hostnames that were resolved via DNS, the return value is 0.
+ */
+DNSSD_AVAILABLE
+uint32_t
+dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t gai_result);
+
+/*!
+ *     @brief
+ *             Gets a getaddrinfo result's authentication tag.
+ *
+ *     @param gai_result
+ *             The getaddrinfo result.
+ *
+ *     @param out_length
+ *             If non-NULL, gets set to the length of the authentication tag.
+ *
+ *     @result
+ *             A pointer to the getaddrinfo result's authentication tag, if it has one. Otherwise, NULL.
+ *
+ *     @discussion
+ *             The returned pointer, if non-NULL, is valid until the getaddrinfo result is released.
+ */
+DNSSD_AVAILABLE
+const void * _Nullable
+dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t gai_result, size_t *_Nullable out_length);
+
+static inline const char *
+dnssd_getaddrinfo_result_type_to_string(dnssd_getaddrinfo_result_type_t result)
+{
+       switch (result) {
+               case dnssd_getaddrinfo_result_type_add:                 return "Add";
+               case dnssd_getaddrinfo_result_type_remove:              return "Remove";
+               case dnssd_getaddrinfo_result_type_no_address:  return "NoAddress";
+               case dnssd_getaddrinfo_result_type_expired:             return "Expired";
+               default:                                                                                return "?";
+       }
+}
+
+static inline const char *
+dnssd_event_to_string(dnssd_event_t event)
+{
+       switch (event) {
+               case dnssd_event_remove_all:    return "RemoveAll";
+               case dnssd_event_error:                 return "Error";
+               case dnssd_event_invalidated:   return "Invalidated";
+               default:                                                return "?";
+       }
+}
+
+__END_DECLS
+
+DNSSD_ASSUME_NONNULL_END
+
+#endif // __DNSSD_PRIVATE_H__
diff --git a/mDNSMacOSX/dnssd_server.c b/mDNSMacOSX/dnssd_server.c
new file mode 100644 (file)
index 0000000..6db523a
--- /dev/null
@@ -0,0 +1,910 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#include "dnssd_server.h"
+
+#include "ClientRequests.h"
+#include "dnssd_xpc.h"
+#include "mDNSMacOSX.h"
+
+#include <CoreUtils/CommonServices.h>
+#include <CoreUtils/DebugServices.h>
+#include <libproc.h>
+#include <net/necp.h>
+#include <sys/proc_info.h>
+#include <xpc/private.h>
+
+#if 0
+//======================================================================================================================
+#pragma mark - Kind Declarations
+#endif
+
+#define DX_STRUCT(NAME)                        struct dx_ ## NAME ## _s
+#define DX_TYPE(NAME)                  dx_ ## NAME ## _t
+#define DX_KIND_DECLARE(NAME)  typedef DX_STRUCT(NAME) *       DX_TYPE(NAME)
+
+#define DX_KIND_DECLARE_FULL(NAME)                                             \
+       DX_KIND_DECLARE(NAME);                                                          \
+                                                                                                               \
+       static void                                                                                     \
+       _dx_ ## NAME ## _invalidate(DX_TYPE(NAME) object);      \
+                                                                                                               \
+       static void                                                                                     \
+       _dx_ ## NAME ## _finalize(DX_TYPE(NAME) object);        \
+                                                                                                               \
+       static DX_TYPE(NAME)                                                            \
+       _dx_ ## NAME ## _alloc(void)
+
+// Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
+// comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
+// the warning hasn't been disabled.
+
+#define DX_BASE_CHECK(NAME, SUPER)                                                                                                                             \
+       check_compile_time(offsetof(DX_STRUCT(NAME), base) == 0);                                                                       \
+       check_compile_time(sizeof_field(DX_STRUCT(NAME), base) == sizeof(DX_STRUCT(SUPER)));            \
+       extern int _dx_base_type_check[sizeof(&(((DX_TYPE(NAME))0)->base) == ((DX_TYPE(SUPER))0))]
+
+#define DX_KIND_DEFINE(NAME, SUPER)                                                                                    \
+       static const struct dx_kind_s _dx_ ## NAME ## _kind = {                                 \
+               &_dx_ ## SUPER ##_kind,                                                                                         \
+               _dx_ ## NAME ## _invalidate,                                                                            \
+               _dx_ ## NAME ## _finalize,                                                                                      \
+       };                                                                                                                                              \
+                                                                                                                                                       \
+       static DX_TYPE(NAME)                                                                                                    \
+       _dx_ ## NAME ## _alloc(void)                                                                                    \
+       {                                                                                                                                               \
+               const DX_TYPE(NAME) obj = (DX_TYPE(NAME))calloc(1, sizeof(*obj));       \
+               require_quiet(obj, exit);                                                                                       \
+                                                                                                                                                       \
+               const dx_base_t base = (dx_base_t)obj;                                                          \
+               base->ref_count = 1;                                                                                            \
+               base->kind              = &_dx_ ## NAME ## _kind;                                                       \
+                                                                                                                                                       \
+       exit:                                                                                                                                   \
+               return obj;                                                                                                                     \
+       }                                                                                                                                               \
+       DX_BASE_CHECK(NAME, SUPER)
+
+DX_KIND_DECLARE(base);
+DX_KIND_DECLARE(request);
+DX_KIND_DECLARE_FULL(session);
+DX_KIND_DECLARE_FULL(getaddrinfo_request);
+
+typedef union {
+       dx_base_t                                       base;
+       dx_session_t                            session;
+       dx_request_t                            request;
+       dx_getaddrinfo_request_t        getaddrinfo_request;
+} dx_any_t __attribute__((__transparent_union__));
+
+typedef void (*dx_invalidate_f)(dx_any_t object);
+typedef void (*dx_finalize_f)(dx_any_t object);
+
+typedef const struct dx_kind_s *       dx_kind_t;
+struct dx_kind_s {
+       dx_kind_t               superkind;      // This kind's superkind. All kinds have a superkind, except the base kind.
+       dx_invalidate_f invalidate;     // Stops an object's outstanding operations, if any.
+       dx_finalize_f   finalize;       // Releases object's resources right before the object is freed.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - Base Kind Definition
+#endif
+
+struct dx_base_s {
+       dx_kind_t       kind;           // The object's kind.
+       int32_t         ref_count;      // Reference count.
+};
+
+static const struct dx_kind_s _dx_base_kind = {
+       NULL,   // No superkind.
+       NULL,   // No invalidate method.
+       NULL,   // No finalize method.
+};
+
+#if 0
+//======================================================================================================================
+#pragma mark - Request Kind Definition
+#endif
+
+struct dx_request_s {
+       struct dx_base_s        base;                   // Object base.
+       dx_request_t            next;                   // Next request in list.
+       xpc_object_t            result_array;   // Array of pending results.
+       uint64_t                        command_id;             // ID to distinquish multiple commands during a session.
+       uint32_t                        request_id;             // Request ID, used for logging purposes.
+       DNSServiceErrorType     error;                  // Pending error.
+       bool                            sent_error;             // True if the pending error has been sent to client.
+};
+
+static void
+_dx_request_finalize(dx_any_t request);
+
+static const struct dx_kind_s _dx_request_kind = {
+       &_dx_base_kind,
+       NULL,                                   // No invalidate method.
+       _dx_request_finalize,
+};
+DX_BASE_CHECK(request, base);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Session Kind Definition
+#endif
+
+struct dx_session_s {
+       struct dx_base_s        base;                                           // Object base;
+       dx_session_t            next;                                           // Next session in list.
+       dx_request_t            request_list;                           // List of outstanding requests.
+       xpc_connection_t        connection;                                     // Underlying XPC connection.
+       bool                            has_delegate_entitlement;       // True if the client is entitled to be a delegate.
+};
+
+DX_KIND_DEFINE(session, base);
+
+#if 0
+//======================================================================================================================
+#pragma mark - GetAddrInfo Request Kind Definition
+#endif
+
+struct dx_getaddrinfo_request_s {
+       struct dx_request_s                     base;                   // Request object base.
+       GetAddrInfoClientRequest        gai;                    // Underlying GetAddrInfoClientRequest.
+       xpc_object_t                            hostname;               // Hostname to be resolved for getaddrinfo requests.
+       uuid_t                                          client_uuid;    // Client's UUID for authenticating results.
+       bool                                            need_auth;              // True if results need to be authenticated.
+       bool                                            active;                 // True if the GetAddrInfoClientRequest is currently active.
+};
+
+DX_KIND_DEFINE(getaddrinfo_request, request);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Local Prototypes
+#endif
+
+static dispatch_queue_t
+_dx_server_queue(void);
+
+static void
+_dx_server_register_session(dx_session_t session);
+
+static void
+_dx_server_deregister_session(dx_session_t session);
+
+static void
+_dx_retain(dx_any_t object);
+
+static void
+_dx_release(dx_any_t object);
+#define _dx_release_null_safe(X)       do { if (X) { _dx_release(X); } } while (0)
+
+static void
+_dx_invalidate(dx_any_t object);
+
+static dx_session_t
+_dx_session_create(xpc_connection_t connection);
+
+static void
+_dx_session_activate(dx_session_t me);
+
+static DNSServiceErrorType
+_dx_session_handle_getaddrinfo_command(dx_session_t session, xpc_object_t msg);
+
+static DNSServiceErrorType
+_dx_session_handle_stop_command(dx_session_t session, xpc_object_t msg);
+
+static void
+_dx_session_send_results(dx_session_t session);
+
+static dx_getaddrinfo_request_t
+_dx_getaddrinfo_request_create(uint64_t command_id, uint32_t request_id);
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_set_hostname(dx_getaddrinfo_request_t request, xpc_object_t hostname);
+
+static void
+_dx_getaddrinfo_request_set_need_authenticaed_results(dx_getaddrinfo_request_t request, bool need,
+       const uuid_t client_uuid);
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_activate(dx_getaddrinfo_request_t request, uint32_t interface_index, DNSServiceFlags flags,
+       DNSServiceProtocol protocols, pid_t pid, const uuid_t uuid, uid_t uid);
+
+static void
+_dx_getaddrinfo_request_result_handler(mDNS *m, DNSQuestion *question, const ResourceRecord *answer,
+       QC_result qc_result, DNSServiceErrorType error, void *context);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Server Functions
+#endif
+
+static void
+_dx_server_handle_new_connection(xpc_connection_t connection);
+
+mDNSexport void
+dnssd_server_init(void)
+{
+       static xpc_connection_t listener = NULL;
+
+       listener = xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME, _dx_server_queue(),
+               XPC_CONNECTION_MACH_SERVICE_LISTENER);
+    xpc_connection_set_event_handler(listener,
+       ^(xpc_object_t event)
+       {
+               if (xpc_get_type(event) == XPC_TYPE_CONNECTION) {
+                       _dx_server_handle_new_connection((xpc_connection_t)event);
+               }
+       });
+       xpc_connection_activate(listener);
+}
+
+static void
+_dx_server_handle_new_connection(xpc_connection_t connection)
+{
+       const dx_session_t session = _dx_session_create(connection);
+       if (session) {
+               _dx_session_activate(session);
+               _dx_server_register_session(session);
+               _dx_release(session);
+       } else {
+               xpc_connection_cancel(connection);
+       }
+}
+
+
+//======================================================================================================================
+
+static dx_session_t    g_session_list  = NULL;
+
+mDNSexport void
+dnssd_server_idle(void)
+{
+       for (dx_session_t session = g_session_list; session; session = session->next) {
+               _dx_session_send_results(session);
+       }
+}
+
+//======================================================================================================================
+
+static dispatch_queue_t
+_dx_server_queue(void)
+{
+       static dispatch_once_t  once    = 0;
+       static dispatch_queue_t queue   = NULL;
+
+       dispatch_once(&once,
+       ^{
+               const dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
+                       QOS_CLASS_UTILITY, 0);
+               queue = dispatch_queue_create("com.apple.dnssd.server", attr);
+       });
+       return queue;
+}
+
+//======================================================================================================================
+
+static void
+_dx_server_register_session(dx_session_t session)
+{
+       session->next   = g_session_list;
+       g_session_list  = session;
+       _dx_retain(session);
+}
+
+//======================================================================================================================
+
+static void
+_dx_server_deregister_session(dx_session_t session)
+{
+       dx_session_t *ptr;
+       for (ptr = &g_session_list; *ptr; ptr = &(*ptr)->next) {
+               if (*ptr == session) {
+                       break;
+               }
+       }
+       if (*ptr) {
+               *ptr                    = session->next;
+               session->next   = NULL;
+               _dx_release(session);
+       }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Base Methods
+#endif
+
+static void
+_dx_retain(dx_any_t object)
+{
+       ++object.base->ref_count;
+}
+
+//======================================================================================================================
+
+static void
+_dx_release(dx_any_t object)
+{
+       if (--object.base->ref_count == 0) {
+               for (dx_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+                       if (kind->finalize) {
+                               kind->finalize(object);
+                       }
+               }
+               free(object.base);
+       }
+}
+
+//======================================================================================================================
+
+static void
+_dx_invalidate(dx_any_t object)
+{
+       for (dx_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+               if (kind->invalidate) {
+                       kind->invalidate(object);
+                       return;
+               }
+       }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Session Methods
+#endif
+
+static dx_session_t
+_dx_session_create(xpc_connection_t connection)
+{
+       const dx_session_t obj = _dx_session_alloc();
+       require_quiet(obj, exit);
+
+       obj->connection = connection;
+       xpc_retain(obj->connection);
+
+exit:
+       return obj;
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_handle_message(dx_session_t session, xpc_object_t msg);
+
+#define DNSSD_DELEGATE_ENTITLEMENT "com.apple.private.network.socket-delegate"
+
+static void
+_dx_session_activate(dx_session_t me)
+{
+       const xpc_object_t value = xpc_connection_copy_entitlement_value(me->connection, DNSSD_DELEGATE_ENTITLEMENT);
+       if (value) {
+               if (value == XPC_BOOL_TRUE) {
+                       me->has_delegate_entitlement = true;
+               }
+               xpc_release(value);
+       }
+       _dx_retain(me);
+       xpc_connection_set_target_queue(me->connection, _dx_server_queue());
+       xpc_connection_set_event_handler(me->connection,
+       ^(xpc_object_t event) {
+               const xpc_type_t type = xpc_get_type(event);
+               if (type == XPC_TYPE_DICTIONARY) {
+               KQueueLock();
+                       _dx_session_handle_message(me, event);
+               KQueueUnlock("_dx_session_handle_message");
+               } else if (event == XPC_ERROR_CONNECTION_INVALID) {
+               KQueueLock();
+                       _dx_server_deregister_session(me);
+               KQueueUnlock("_dx_server_deregister_session");
+                       _dx_session_invalidate(me);
+                       _dx_release(me);
+               } else {
+                       xpc_connection_cancel(me->connection);
+               }
+       });
+       xpc_connection_activate(me->connection);
+}
+
+static void
+_dx_session_handle_message(dx_session_t me, xpc_object_t msg)
+{
+       DNSServiceErrorType error;
+       const char * const command = dnssd_xpc_message_get_command(msg);
+       require_action_quiet(command, exit, error = kDNSServiceErr_BadParam);
+
+       if (strcmp(command, DNSSD_COMMAND_GETADDRINFO) == 0) {
+               error = _dx_session_handle_getaddrinfo_command(me, msg);
+       } else if (strcmp(command, DNSSD_COMMAND_STOP) == 0) {
+               error = _dx_session_handle_stop_command(me, msg);
+       } else {
+               error = kDNSServiceErr_BadParam;
+       }
+
+exit:
+       {
+               const xpc_object_t reply = xpc_dictionary_create_reply(msg);
+               if (likely(reply)) {
+                       dnssd_xpc_message_set_error(reply, error);
+                       xpc_connection_send_message(me->connection, reply);
+                       xpc_release(reply);
+               } else {
+                       xpc_connection_cancel(me->connection);
+               }
+       }
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_invalidate(dx_session_t me)
+{
+       xpc_connection_forget(&me->connection);
+       dx_request_t req;
+       while ((req = me->request_list) != NULL)
+       {
+               me->request_list = req->next;
+               _dx_invalidate(req);
+               _dx_release(req);
+       }
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_finalize(dx_session_t me)
+{
+       (void)me;
+}
+
+//======================================================================================================================
+
+static bool
+_dx_get_getaddrinfo_params(xpc_object_t msg, uint64_t *out_command_id, xpc_object_t *out_hostname,
+       uint32_t *out_interface_index, DNSServiceFlags *out_flags, DNSServiceProtocol *out_protocols,
+       pid_t *out_delegate_pid, const uint8_t **out_delegate_uuid, bool *out_need_auth_tags);
+
+extern mDNS    mDNSStorage;
+#define g_mdns mDNSStorage
+
+static DNSServiceErrorType
+_dx_session_handle_getaddrinfo_command(dx_session_t me, xpc_object_t msg)
+{
+       dx_getaddrinfo_request_t        req = NULL;
+       DNSServiceErrorType                     error;
+       uint64_t                                        command_id;
+       xpc_object_t                            hostname;
+       uint32_t                                        interface_index;
+       DNSServiceFlags                         flags;
+       DNSServiceProtocol                      protocols;
+       pid_t                                           pid;
+       const uint8_t *                         uuid;
+       bool                                            need_auth;
+
+       const bool valid = _dx_get_getaddrinfo_params(msg, &command_id, &hostname, &interface_index, &flags, &protocols,
+               &pid, &uuid, &need_auth);
+       require_action_quiet(valid, exit, error = kDNSServiceErr_BadParam);
+
+       if (uuid || (pid != 0)) {
+               require_action_quiet(me->has_delegate_entitlement, exit, error = kDNSServiceErr_NoAuth);
+       } else {
+               pid = xpc_connection_get_pid(me->connection);
+       }
+
+       req = _dx_getaddrinfo_request_create(command_id, g_mdns.next_request_id++);
+       require_action_quiet(req, exit, error = kDNSServiceErr_NoMemory);
+
+       error = _dx_getaddrinfo_request_set_hostname(req, hostname);
+       require_noerr_quiet(error, exit);
+
+       if (need_auth) {
+               struct proc_uniqidentifierinfo info;
+               const int n = proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
+               if (n == (int)sizeof(info)) {
+                       _dx_getaddrinfo_request_set_need_authenticaed_results(req, true, info.p_uuid);
+               }
+       }
+
+       const uid_t euid = xpc_connection_get_euid(me->connection);
+       error = _dx_getaddrinfo_request_activate(req, interface_index, flags, protocols, pid, uuid, euid);
+       require_noerr_quiet(error, exit);
+
+       req->base.next          = me->request_list;
+       me->request_list        = (dx_request_t)req;
+       req = NULL;
+
+exit:
+       _dx_release_null_safe(req);
+       static_analyzer_malloc_freed(req);
+       return error;
+}
+
+static bool
+_dx_get_getaddrinfo_params(xpc_object_t msg, uint64_t *out_command_id, xpc_object_t *out_hostname,
+       uint32_t *out_interface_index, DNSServiceFlags *out_flags, DNSServiceProtocol *out_protocols,
+       pid_t *out_delegate_pid, const uint8_t **out_delegate_uuid, bool *out_need_auth_tags)
+{
+       bool params_are_valid = false;
+       bool valid;
+       const uint64_t command_id = dnssd_xpc_message_get_id(msg, &valid);
+       require_quiet(valid, exit);
+
+       const xpc_object_t params = dnssd_xpc_message_get_parameters(msg);
+       require_quiet(params, exit);
+
+       xpc_object_t hostname = dnssd_xpc_parameters_get_hostname_object(params);
+       require_quiet(hostname, exit);
+
+       const uint32_t interface_index = dnssd_xpc_parameters_get_interface_index(params, &valid);
+       require_quiet(valid, exit);
+
+       const DNSServiceFlags flags = dnssd_xpc_parameters_get_flags(params, &valid);
+       require_quiet(valid, exit);
+
+       const uint32_t protocols = dnssd_xpc_parameters_get_protocols(params, &valid);
+       require_quiet(valid, exit);
+
+       pid_t pid;
+       const uint8_t * const uuid = dnssd_xpc_parameters_get_delegate_uuid(params);
+       if (uuid) {
+               pid = 0;
+       } else {
+               pid = dnssd_xpc_parameters_get_delegate_pid(params, NULL);
+       }
+
+       *out_command_id                 = command_id;
+       *out_hostname                   = hostname;
+       *out_interface_index    = interface_index;
+       *out_flags                              = flags;
+       *out_protocols                  = protocols;
+       *out_delegate_pid               = pid;
+       *out_delegate_uuid              = uuid;
+       *out_need_auth_tags             = dnssd_xpc_parameters_get_need_authentication_tags(params);
+       params_are_valid = true;
+
+exit:
+       return params_are_valid;
+}
+
+//======================================================================================================================
+
+static DNSServiceErrorType
+_dx_session_handle_stop_command(dx_session_t me, xpc_object_t msg)
+{
+       bool valid;
+       DNSServiceErrorType error;
+       const uint64_t command_id = dnssd_xpc_message_get_id(msg, &valid);
+       require_action_quiet(valid, exit, error = kDNSServiceErr_BadParam);
+
+       dx_request_t * ptr;
+       dx_request_t req;
+       for (ptr = &me->request_list; (req = *ptr) != NULL; ptr = &req->next) {
+               if (req->command_id == command_id) {
+                       break;
+               }
+       }
+       require_action_quiet(req, exit, error = kDNSServiceErr_BadReference);
+
+       *ptr            = req->next;
+       req->next       = NULL;
+
+       _dx_invalidate(req);
+       _dx_release(req);
+       error = kDNSServiceErr_NoError;
+
+exit:
+       return error;
+}
+
+//======================================================================================================================
+
+static void
+_dx_session_send_results(dx_session_t me)
+{
+       bool success = false;
+       for (dx_request_t req = me->request_list; req; req = req->next) {
+               if (req->result_array && (xpc_array_get_count(req->result_array) > 0)) {
+                       const xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+                       require_quiet(msg, exit);
+
+                       dnssd_xpc_message_set_id(msg, req->command_id);
+                       dnssd_xpc_message_set_error(msg, kDNSServiceErr_NoError);
+                       dnssd_xpc_message_set_results(msg, req->result_array);
+                       xpc_connection_send_message(me->connection, msg);
+                       xpc_release(msg);
+
+                       xpc_release(req->result_array);
+                       req->result_array = xpc_array_create(NULL, 0);
+                       require_quiet(req->result_array, exit);
+               }
+               if (req->error && !req->sent_error) {
+                       const xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
+                       require_quiet(msg, exit);
+
+                       dnssd_xpc_message_set_id(msg, req->command_id);
+                       dnssd_xpc_message_set_error(msg, req->error);
+                       xpc_connection_send_message(me->connection, msg);
+                       xpc_release(msg);
+                       req->sent_error = true;
+               }
+       }
+       success = true;
+
+exit:
+       if (unlikely(!success)) {
+               xpc_connection_cancel(me->connection);
+       }
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Request Methods
+#endif
+
+static void
+_dx_request_finalize(dx_request_t me)
+{
+       xpc_forget(&me->result_array);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - GetAddrInfo Request Methods
+#endif
+
+static dx_getaddrinfo_request_t
+_dx_getaddrinfo_request_create(uint64_t command_id, uint32_t request_id)
+{
+       dx_getaddrinfo_request_t req = NULL;
+       dx_getaddrinfo_request_t obj = _dx_getaddrinfo_request_alloc();
+       require_quiet(obj, exit);
+
+       obj->base.command_id    = command_id;
+       obj->base.request_id    = request_id;
+       obj->base.result_array  = xpc_array_create(NULL, 0);
+       require_quiet(obj->base.result_array, exit);
+
+       req = obj;
+       obj = NULL;
+
+exit:
+       _dx_release_null_safe(obj);
+       return req;
+}
+
+//======================================================================================================================
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_set_hostname(dx_getaddrinfo_request_t me, xpc_object_t hostname)
+{
+       DNSServiceErrorType err;
+       require_action_quiet(xpc_string_get_length(hostname) <= MAX_ESCAPED_DOMAIN_NAME, exit,
+               err = kDNSServiceErr_BadParam);
+
+       xpc_release_null_safe(me->hostname);
+       me->hostname = xpc_copy(hostname);
+       require_action_quiet(me->hostname, exit, err = kDNSServiceErr_NoMemory);
+
+       err = kDNSServiceErr_NoError;
+
+exit:
+       return err;
+}
+
+//======================================================================================================================
+
+static void
+_dx_getaddrinfo_request_set_need_authenticaed_results(dx_getaddrinfo_request_t me, bool need, const uuid_t client_uuid)
+{
+       if (need) {
+               uuid_copy(me->client_uuid, client_uuid);
+               me->need_auth = true;
+       } else {
+               uuid_clear(me->client_uuid);
+               me->need_auth = false;
+       }
+}
+
+//======================================================================================================================
+
+static DNSServiceErrorType
+_dx_getaddrinfo_request_activate(dx_getaddrinfo_request_t me, uint32_t interface_index, DNSServiceFlags flags,
+       DNSServiceProtocol protocols, pid_t pid, const uuid_t uuid, uid_t uid)
+{
+       DNSServiceErrorType err;
+       const char * const hostname_str = xpc_string_get_string_ptr(me->hostname);
+       require_action_quiet(hostname_str, exit, err = kDNSServiceErr_Unknown);
+
+       err = GetAddrInfoClientRequestStart(&me->gai, me->base.request_id, hostname_str, interface_index, flags,
+               protocols, pid, uuid, uid, _dx_getaddrinfo_request_result_handler, me);
+       require_noerr_quiet(err, exit);
+
+       _dx_retain(me);
+       me->active = true;
+
+exit:
+       return err;
+}
+
+//======================================================================================================================
+
+static void
+_dx_getaddrinfo_request_invalidate(dx_getaddrinfo_request_t me)
+{
+       if (me->active) {
+               GetAddrInfoClientRequestStop(&me->gai);
+               me->active = false;
+               _dx_release(me);
+       }
+}
+
+//======================================================================================================================
+
+static void
+_dx_getaddrinfo_request_finalize(dx_getaddrinfo_request_t me)
+{
+       xpc_forget(&me->hostname);
+}
+
+//======================================================================================================================
+
+#if defined(NECP_CLIENT_ACTION_SIGN)
+#define DNSSD_AUTHENTICATION_TAG_SIZE  32      // XXX: Defined as a workaround until NECP header defines this length.
+
+static bool
+_dx_authenticate_answer(uuid_t client_id, xpc_object_t hostname, int record_type, const void *record_data,
+       uint8_t out_auth_tag[STATIC_PARAM DNSSD_AUTHENTICATION_TAG_SIZE]);
+#endif
+
+static void
+_dx_getaddrinfo_request_result_handler(mDNS *m, DNSQuestion *question, const ResourceRecord *answer,
+       QC_result qc_result, DNSServiceErrorType error, void *context)
+{
+       (void)question;
+
+       const dx_getaddrinfo_request_t me = (dx_getaddrinfo_request_t)context;
+       if (error && (error != kDNSServiceErr_NoSuchRecord)) {
+               if (!me->base.error) {
+                       me->base.error = error;
+               }
+               goto exit;
+       }
+       require_quiet((answer->rrtype == kDNSServiceType_A) || (answer->rrtype == kDNSServiceType_AAAA), exit);
+
+       const void *    rdata_ptr;
+       size_t                  rdata_len;
+       if (!error) {
+               if (answer->rrtype == kDNSServiceType_A) {
+                       rdata_ptr = answer->rdata->u.ipv4.b;
+                       rdata_len = 4;
+               } else {
+                       rdata_ptr = answer->rdata->u.ipv6.b;
+                       rdata_len = 16;
+               }
+       } else {
+               rdata_ptr = NULL;
+               rdata_len = 0;
+       }
+
+       DNSServiceFlags flags = 0;
+       if (qc_result != QC_rmv) {
+               flags |= kDNSServiceFlagsAdd;
+       }
+    if (answer->mortality == Mortality_Ghost) {
+               flags |= kDNSServiceFlagsExpiredAnswer;
+       }
+       if (!question->InitialCacheMiss) {
+               flags |= kDNSServiceFlagAnsweredFromCache;
+       }
+       
+       const uint32_t interface_index = mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNStrue);
+       const xpc_object_t result = xpc_dictionary_create(NULL, NULL, 0);
+       if (likely(result)) {
+       char name_str[MAX_ESCAPED_DOMAIN_NAME];
+       ConvertDomainNameToCString(answer->name, name_str);
+
+               dnssd_xpc_result_set_error(result, error);
+               dnssd_xpc_result_set_flags(result, flags);
+               dnssd_xpc_result_set_interface_index(result, interface_index);
+               dnssd_xpc_result_set_record_name(result, name_str);
+               dnssd_xpc_result_set_record_type(result, answer->rrtype);
+               dnssd_xpc_result_set_record_class(result, answer->rrclass);
+               dnssd_xpc_result_set_record_data(result, rdata_ptr, rdata_len);
+
+#if defined(NECP_CLIENT_ACTION_SIGN)
+               if (me->need_auth && !error && (flags & kDNSServiceFlagsAdd)) {
+                       uint8_t auth_tag[DNSSD_AUTHENTICATION_TAG_SIZE];
+                       const bool success = _dx_authenticate_answer(me->client_uuid, me->hostname, answer->rrtype, rdata_ptr,
+                               auth_tag);
+                       if (success) {
+                               dnssd_xpc_result_set_authentication_tag(result, auth_tag, sizeof(auth_tag));
+                       }
+               }
+#endif
+               xpc_array_append_value(me->base.result_array, result);
+               xpc_release(result);
+       } else {
+               me->base.error = kDNSServiceErr_NoMemory;
+       }
+
+exit:
+       return;
+}
+
+#if defined(NECP_CLIENT_ACTION_SIGN)
+typedef struct {
+       struct necp_client_resolver_answer      hdr;
+       uint8_t                                                         hostname[MAX_ESCAPED_DOMAIN_NAME];
+} dx_necp_answer_t;
+
+check_compile_time(offsetof(dx_necp_answer_t, hdr) == 0);
+check_compile_time(endof_field(struct necp_client_resolver_answer, hostname_length) == offsetof(dx_necp_answer_t, hostname));
+
+static bool
+_dx_authenticate_answer(uuid_t client_id, xpc_object_t hostname, int record_type, const void *record_data,
+       uint8_t out_auth_tag[STATIC_PARAM DNSSD_AUTHENTICATION_TAG_SIZE])
+{
+       static int necp_fd = -1;
+
+       bool success = false;
+       if (necp_fd < 0) {
+               necp_fd = necp_open(0);
+       }
+       require_quiet(necp_fd >= 0, exit);
+
+       dx_necp_answer_t answer;
+       memset(&answer, 0, sizeof(answer));
+
+       struct necp_client_resolver_answer * const hdr = &answer.hdr;
+       uuid_copy(hdr->client_id, client_id);
+
+       hdr->sign_type = NECP_CLIENT_SIGN_TYPE_RESOLVER_ANSWER;
+
+       switch (record_type) {
+               case kDNSServiceType_A:
+                       hdr->address_answer.sa.sa_family        = AF_INET;
+                       hdr->address_answer.sa.sa_len           = sizeof(struct sockaddr_in);
+                       memcpy(&hdr->address_answer.sin.sin_addr.s_addr, record_data, 4);
+                       break;
+
+               case kDNSServiceType_AAAA:
+                       hdr->address_answer.sa.sa_family        = AF_INET6;
+                       hdr->address_answer.sa.sa_len           = sizeof(struct sockaddr_in6);
+                       memcpy(hdr->address_answer.sin6.sin6_addr.s6_addr, record_data, 16);
+                       break;
+
+               default:
+                       goto exit;
+       }
+       const size_t hostname_len = xpc_string_get_length(hostname);
+       require_quiet(hostname_len <= sizeof(answer.hostname), exit);
+
+       hdr->hostname_length = (uint32_t)hostname_len;
+       memcpy(answer.hostname, xpc_string_get_string_ptr(hostname), hdr->hostname_length);
+
+       const int necp_err = necp_client_action(necp_fd, NECP_CLIENT_ACTION_SIGN, (void *)&answer,
+               sizeof(answer.hdr) + hdr->hostname_length, out_auth_tag, DNSSD_AUTHENTICATION_TAG_SIZE);
+       require_noerr_quiet(necp_err, exit);
+
+       success = true;
+
+exit:
+       return success;
+}
+#endif // defined(NECP_CLIENT_ACTION_SIGN)
diff --git a/mDNSMacOSX/dnssd_server.h b/mDNSMacOSX/dnssd_server.h
new file mode 100644 (file)
index 0000000..ff61736
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 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.
+ */
+
+#ifndef __DNSSD_SERVER_H__
+#define __DNSSD_SERVER_H__
+
+#include "mDNSEmbeddedAPI.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+mDNSexport void
+dnssd_server_init(void);
+
+mDNSexport void
+dnssd_server_idle(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __DNSSD_SERVER_H__
diff --git a/mDNSMacOSX/dnssd_xpc.c b/mDNSMacOSX/dnssd_xpc.c
new file mode 100644 (file)
index 0000000..c304c8b
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#include "dnssd_xpc.h"
+
+#if 0
+//======================================================================================================================
+#pragma mark - XPC Dictionary Helper Declarations
+#endif
+
+static int32_t
+_dnssd_xpc_dictionary_get_int32(xpc_object_t dict, const char *key, bool *out_valid);
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64(xpc_object_t dict, const char *key, bool *out_valid);
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64_limited(xpc_object_t dict, const char *key, int64_t min, int64_t max, bool *out_valid);
+
+static uint16_t
+_dnssd_xpc_dictionary_get_uint16(xpc_object_t dict, const char *key, bool *out_valid);
+
+static uint32_t
+_dnssd_xpc_dictionary_get_uint32(xpc_object_t dict, const char *key, bool *out_valid);
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64(xpc_object_t dict, const char *key, bool *out_valid);
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64_limited(xpc_object_t dict, const char *key, uint64_t min, uint64_t max,
+       bool *out_valid);
+
+static xpc_object_t
+_dnssd_xpc_dictionary_get_value(xpc_object_t dict, const char *key, xpc_type_t type);
+
+#if 0
+//======================================================================================================================
+#pragma mark - Top-Level Message Dictionaries
+#endif
+
+#define DNSSD_XPC_MESSAGE_KEY_COMMAND  "command"
+#define DNSSD_XPC_MESSAGE_KEY_ERROR            "error"
+#define DNSSD_XPC_MESSAGE_KEY_ID               "id"
+#define DNSSD_XPC_MESSAGE_KEY_PARAMS   "params"
+#define DNSSD_XPC_MESSAGE_KEY_RESULTS  "results"
+
+//======================================================================================================================
+
+const char *
+dnssd_xpc_message_get_command(xpc_object_t msg)
+{
+       return xpc_dictionary_get_string(msg, DNSSD_XPC_MESSAGE_KEY_COMMAND);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_command(xpc_object_t msg, const char *command)
+{
+       xpc_dictionary_set_string(msg, DNSSD_XPC_MESSAGE_KEY_COMMAND, command);
+}
+
+//======================================================================================================================
+
+DNSServiceErrorType
+dnssd_xpc_message_get_error(xpc_object_t msg, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_int32(msg, DNSSD_XPC_MESSAGE_KEY_ERROR, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_error(xpc_object_t msg, DNSServiceErrorType error)
+{
+       xpc_dictionary_set_int64(msg, DNSSD_XPC_MESSAGE_KEY_ERROR, error);
+}
+
+//======================================================================================================================
+
+uint64_t
+dnssd_xpc_message_get_id(xpc_object_t msg, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint64(msg, DNSSD_XPC_MESSAGE_KEY_ID, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_id(xpc_object_t msg, uint64_t ident)
+{
+       xpc_dictionary_set_uint64(msg, DNSSD_XPC_MESSAGE_KEY_ID, ident);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_message_get_parameters(xpc_object_t msg)
+{
+       return xpc_dictionary_get_dictionary(msg, DNSSD_XPC_MESSAGE_KEY_PARAMS);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_parameters(xpc_object_t msg, xpc_object_t params)
+{
+       xpc_dictionary_set_value(msg, DNSSD_XPC_MESSAGE_KEY_PARAMS, params);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_message_get_results(xpc_object_t msg)
+{
+       return xpc_dictionary_get_array(msg, DNSSD_XPC_MESSAGE_KEY_RESULTS);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_message_set_results(xpc_object_t msg, xpc_object_t results)
+{
+       xpc_dictionary_set_value(msg, DNSSD_XPC_MESSAGE_KEY_RESULTS, results);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Parameter Dictionaries
+#endif
+
+#define DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID           "delegate_id"
+#define DNSSD_XPC_PARAMETERS_KEY_FLAGS                         "flags"
+#define DNSSD_XPC_PARAMETERS_KEY_HOSTNAME                      "hostname"
+#define DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX       "interface_index"
+#define DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS                "need_auth_tags"
+#define DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS                     "protocols"
+
+//======================================================================================================================
+
+pid_t
+dnssd_xpc_parameters_get_delegate_pid(xpc_object_t params, bool *out_valid)
+{
+       return (pid_t)_dnssd_xpc_dictionary_get_int64(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_delegate_pid(xpc_object_t params, pid_t pid)
+{
+       xpc_dictionary_set_int64(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, pid);
+}
+
+//======================================================================================================================
+
+const uint8_t *
+dnssd_xpc_parameters_get_delegate_uuid(xpc_object_t params)
+{
+       return xpc_dictionary_get_uuid(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_delegate_uuid(xpc_object_t params, uuid_t uuid)
+{
+       xpc_dictionary_set_uuid(params, DNSSD_XPC_PARAMETERS_KEY_DELEGATE_ID, uuid);
+}
+
+//======================================================================================================================
+
+DNSServiceFlags
+dnssd_xpc_parameters_get_flags(xpc_object_t params, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_FLAGS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_flags(xpc_object_t params, DNSServiceFlags flags)
+{
+       xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_FLAGS, flags);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_parameters_get_hostname_object(xpc_object_t params)
+{
+       return _dnssd_xpc_dictionary_get_value(params, DNSSD_XPC_PARAMETERS_KEY_HOSTNAME, XPC_TYPE_STRING);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_hostname(xpc_object_t params, const char *hostname)
+{
+       xpc_dictionary_set_string(params, DNSSD_XPC_PARAMETERS_KEY_HOSTNAME, hostname);
+}
+
+//======================================================================================================================
+
+uint32_t
+dnssd_xpc_parameters_get_interface_index(xpc_object_t params, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_interface_index(xpc_object_t params, uint32_t interface_index)
+{
+       xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_INTERFACE_INDEX, interface_index);
+}
+
+//======================================================================================================================
+
+bool
+dnssd_xpc_parameters_get_need_authentication_tags(xpc_object_t params)
+{
+       return xpc_dictionary_get_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_need_authentication_tags(xpc_object_t params, bool need_auth_tags)
+{
+       xpc_dictionary_set_bool(params, DNSSD_XPC_PARAMETERS_KEY_NEED_AUTH_TAGS, need_auth_tags);
+}
+
+//======================================================================================================================
+
+DNSServiceProtocol
+dnssd_xpc_parameters_get_protocols(xpc_object_t params, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint32(params, DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_parameters_set_protocols(xpc_object_t params, DNSServiceProtocol protocols)
+{
+       xpc_dictionary_set_uint64(params, DNSSD_XPC_PARAMETERS_KEY_PROTOCOLS, protocols);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - Result Dictionaries
+#endif
+
+#define DNSSD_XPC_RESULT_KEY_AUTH_TAG                  "auth_tag"
+#define DNSSD_XPC_RESULT_KEY_ERROR                             "error"
+#define DNSSD_XPC_RESULT_KEY_FLAGS                             "flags"
+#define DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX   "interface_index"
+#define DNSSD_XPC_RESULT_KEY_RECORD_CLASS              "rclass"
+#define DNSSD_XPC_RESULT_KEY_RECORD_DATA               "rdata"
+#define DNSSD_XPC_RESULT_KEY_RECORD_NAME               "rname"
+#define DNSSD_XPC_RESULT_KEY_RECORD_TYPE               "rtype"
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_result_get_authentication_tag_object(xpc_object_t result)
+{
+       return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_AUTH_TAG, XPC_TYPE_DATA);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_authentication_tag(xpc_object_t result, const void *auth_tag_ptr, size_t auth_tag_len)
+{
+       xpc_dictionary_set_data(result, DNSSD_XPC_RESULT_KEY_AUTH_TAG, auth_tag_ptr, auth_tag_len);
+}
+
+//======================================================================================================================
+
+DNSServiceErrorType
+dnssd_xpc_result_get_error(xpc_object_t result, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_int32(result, DNSSD_XPC_RESULT_KEY_ERROR, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_error(xpc_object_t result, DNSServiceErrorType error)
+{
+       xpc_dictionary_set_int64(result, DNSSD_XPC_RESULT_KEY_ERROR, error);
+}
+
+//======================================================================================================================
+
+DNSServiceFlags
+dnssd_xpc_result_get_flags(xpc_object_t result, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint32(result, DNSSD_XPC_RESULT_KEY_FLAGS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_flags(xpc_object_t result, DNSServiceFlags flags)
+{
+       xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_FLAGS, flags);
+}
+
+//======================================================================================================================
+
+uint32_t
+dnssd_xpc_result_get_interface_index(xpc_object_t result, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint32(result, DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_interface_index(xpc_object_t result, uint32_t interface_index)
+{
+       xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_INTERFACE_INDEX, interface_index);
+}
+
+//======================================================================================================================
+
+uint16_t
+dnssd_xpc_result_get_record_class(xpc_object_t result, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint16(result, DNSSD_XPC_RESULT_KEY_RECORD_CLASS, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_class(xpc_object_t result, uint16_t class)
+{
+       xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_RECORD_CLASS, class);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_result_get_record_data_object(xpc_object_t result)
+{
+       return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_RECORD_DATA, XPC_TYPE_DATA);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_data(xpc_object_t result, const void *data_ptr, size_t data_len)
+{
+       xpc_dictionary_set_data(result, DNSSD_XPC_RESULT_KEY_RECORD_DATA, data_ptr, data_len);
+}
+
+//======================================================================================================================
+
+xpc_object_t
+dnssd_xpc_result_get_record_name_object(xpc_object_t result)
+{
+       return _dnssd_xpc_dictionary_get_value(result, DNSSD_XPC_RESULT_KEY_RECORD_NAME, XPC_TYPE_STRING);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_name(xpc_object_t result, const char *name)
+{
+       xpc_dictionary_set_string(result, DNSSD_XPC_RESULT_KEY_RECORD_NAME, name);
+}
+
+//======================================================================================================================
+
+uint16_t
+dnssd_xpc_result_get_record_type(xpc_object_t result, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint16(result, DNSSD_XPC_RESULT_KEY_RECORD_TYPE, out_valid);
+}
+
+//======================================================================================================================
+
+void
+dnssd_xpc_result_set_record_type(xpc_object_t result, uint16_t type)
+{
+       xpc_dictionary_set_uint64(result, DNSSD_XPC_RESULT_KEY_RECORD_TYPE, type);
+}
+
+#if 0
+//======================================================================================================================
+#pragma mark - XPC Dictionary Helpers
+#endif
+
+static int32_t
+_dnssd_xpc_dictionary_get_int32(xpc_object_t dict, const char *key, bool *out_valid)
+{
+       return (int32_t)_dnssd_xpc_dictionary_get_int64_limited(dict, key, INT32_MIN, INT32_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64(xpc_object_t dict, const char *key, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_int64_limited(dict, key, INT64_MIN, INT64_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static int64_t
+_dnssd_xpc_dictionary_get_int64_limited(xpc_object_t dict, const char *key, int64_t min, int64_t max, bool *out_valid)
+{
+       int64_t i64;
+       bool    valid;
+
+       xpc_object_t const value = _dnssd_xpc_dictionary_get_value(dict, key, XPC_TYPE_INT64);
+       if (value) {
+               i64 = xpc_int64_get_value(value);
+               if ((i64 >= min) && (i64 <= max)) {
+                       valid   = true;
+               } else {
+                       i64             = 0;
+                       valid   = false;
+               }
+       } else {
+               i64             = 0;
+               valid   = false;
+       }
+       if (out_valid) {
+               *out_valid = valid;
+       }
+       return i64;
+}
+
+//======================================================================================================================
+
+static uint16_t
+_dnssd_xpc_dictionary_get_uint16(xpc_object_t dict, const char *key, bool *out_valid)
+{
+       return (uint16_t)_dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT16_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static uint32_t
+_dnssd_xpc_dictionary_get_uint32(xpc_object_t dict, const char *key, bool *out_valid)
+{
+       return (uint32_t)_dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT32_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64(xpc_object_t dict, const char *key, bool *out_valid)
+{
+       return _dnssd_xpc_dictionary_get_uint64_limited(dict, key, 0, UINT64_MAX, out_valid);
+}
+
+//======================================================================================================================
+
+static uint64_t
+_dnssd_xpc_dictionary_get_uint64_limited(xpc_object_t dict, const char *key, uint64_t min, uint64_t max,
+       bool *out_valid)
+{
+       uint64_t        u64;
+       bool            valid;
+
+       xpc_object_t const value = _dnssd_xpc_dictionary_get_value(dict, key, XPC_TYPE_UINT64);
+       if (value) {
+               u64 = xpc_uint64_get_value(value);
+               if ((u64 >= min) && (u64 <= max)) {
+                       valid   = true;
+               } else {
+                       u64             = 0;
+                       valid   = false;
+               }
+       } else {
+               u64             = 0;
+               valid   = false;
+       }
+       if (out_valid) {
+               *out_valid = valid;
+       }
+       return u64;
+}
+
+//======================================================================================================================
+
+static xpc_object_t
+_dnssd_xpc_dictionary_get_value(xpc_object_t dict, const char *key, xpc_type_t type)
+{
+       xpc_object_t value = xpc_dictionary_get_value(dict, key);
+       return (value && (xpc_get_type(value) == type)) ? value : NULL;
+}
diff --git a/mDNSMacOSX/dnssd_xpc.h b/mDNSMacOSX/dnssd_xpc.h
new file mode 100644 (file)
index 0000000..ed392ae
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef __DNSSD_XPC_H__
+#define __DNSSD_XPC_H__
+
+#include <CoreUtils/CommonServices.h>
+#include <dns_sd.h>
+#include <xpc/xpc.h>
+
+#define DNSSD_MACH_SERVICE_NAME        "com.apple.dnssd.service"
+
+#define DNSSD_COMMAND_GETADDRINFO      "getaddrinfo"
+#define DNSSD_COMMAND_STOP                     "stop"
+
+CU_ASSUME_NONNULL_BEGIN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ *     @brief
+ *             Gets command as a C string from XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @result
+ *             Command, if present. Otherwise, NULL.
+ */
+const char * _Nullable
+dnssd_xpc_message_get_command(xpc_object_t msg);
+
+/*!
+ *     @brief
+ *             Gets error code from XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Error code, if present. Otherwise, 0.
+ */
+DNSServiceErrorType
+dnssd_xpc_message_get_error(xpc_object_t msg, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets command instance ID from XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             ID, if present. Otherwise, 0.
+ */
+uint64_t
+dnssd_xpc_message_get_id(xpc_object_t msg, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets command parameter dictionary from XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @result
+ *             Command parameter dictionary, if present. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_message_get_parameters(xpc_object_t msg);
+
+/*!
+ *     @brief
+ *             Gets result array from XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @result
+ *             Result array, if present. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_message_get_results(xpc_object_t msg);
+
+/*!
+ *     @brief
+ *             Sets command in XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @param command
+ *             Command as a C string.
+ */
+void
+dnssd_xpc_message_set_command(xpc_object_t msg, const char *command);
+
+/*!
+ *     @brief
+ *             Sets error code in XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @param error
+ *             Error code.
+ */
+void
+dnssd_xpc_message_set_error(xpc_object_t msg, DNSServiceErrorType error);
+
+/*!
+ *     @brief
+ *             Sets command instance ID in XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @param ident
+ *             Command instance ID.
+ */
+void
+dnssd_xpc_message_set_id(xpc_object_t msg, uint64_t ident);
+
+/*!
+ *     @brief
+ *             Sets command parameters dictionary in XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ */
+void
+dnssd_xpc_message_set_parameters(xpc_object_t msg, xpc_object_t params);
+
+/*!
+ *     @brief
+ *             Sets command result array in XPC message.
+ *
+ *     @param msg
+ *             XPC message.
+ *
+ *     @param results
+ *             Command result array.
+ */
+void
+dnssd_xpc_message_set_results(xpc_object_t msg, xpc_object_t results);
+
+/*!
+ *     @brief
+ *             Gets delegate ID as a PID from a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Delegate ID as PID, if present. Otherwise, 0.
+ */
+pid_t
+dnssd_xpc_parameters_get_delegate_pid(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets delegate ID as a UUID from a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @result
+ *             Delegate ID as UUID, if present. Otherwise, NULL.
+ */
+const uint8_t * _Nullable
+dnssd_xpc_parameters_get_delegate_uuid(xpc_object_t params);
+
+/*!
+ *     @brief
+ *             Gets flags from a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Flags, if present. Otherwise, 0.
+ */
+DNSServiceFlags
+dnssd_xpc_parameters_get_flags(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets hostname from a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @result
+ *             Hostname, if present, as an XPC string object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_parameters_get_hostname_object(xpc_object_t params);
+
+/*!
+ *     @brief
+ *             Gets interface index from a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @para out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Interface index, if present. Otherwise, 0.
+ */
+uint32_t
+dnssd_xpc_parameters_get_interface_index(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets need_auth_tags boolean value from a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @result
+ *             A boolean value.
+ */
+bool
+dnssd_xpc_parameters_get_need_authentication_tags(xpc_object_t params);
+
+/*!
+ *     @brief
+ *             Gets protocols from a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Protocols, if present. Otherwise, 0.
+ */
+DNSServiceProtocol
+dnssd_xpc_parameters_get_protocols(xpc_object_t params, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Sets delegate ID as a PID in a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param pid
+ *             PID.
+ */
+void
+dnssd_xpc_parameters_set_delegate_pid(xpc_object_t params, pid_t pid);
+
+/*!
+ *     @brief
+ *             Sets delegate ID as a UUID in a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param uuid
+ *             UUID.
+ */
+void
+dnssd_xpc_parameters_set_delegate_uuid(xpc_object_t params, uuid_t _Nonnull uuid);
+
+/*!
+ *     @brief
+ *             Sets flags in a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param flags
+ *             Flags.
+ */
+void
+dnssd_xpc_parameters_set_flags(xpc_object_t params, DNSServiceFlags flags);
+
+/*!
+ *     @brief
+ *             Sets hostname in a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param hostname
+ *             Hostname.
+ */
+void
+dnssd_xpc_parameters_set_hostname(xpc_object_t params, const char *hostname);
+
+/*!
+ *     @brief
+ *             Sets interface index in a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param interface_index
+ *             Interface index.
+ */
+void
+dnssd_xpc_parameters_set_interface_index(xpc_object_t params, uint32_t interface_index);
+
+/*!
+ *     @brief
+ *             Sets whether mDNSResponder should include an authentication tag for each hostname resolution.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param need
+ *             Pass <code>true</code> to enable this behavior. Pass <code>false</code> to disable it.
+ */
+void
+dnssd_xpc_parameters_set_need_authentication_tags(xpc_object_t params, bool need);
+
+/*!
+ *     @brief
+ *             Sets protocols in a command parameters dictionary.
+ *
+ *     @param params
+ *             Command parameters dictionary.
+ *
+ *     @param protocols
+ *             Protocols.
+ */
+void
+dnssd_xpc_parameters_set_protocols(xpc_object_t params, DNSServiceProtocol protocols);
+
+/*!
+ *     @brief
+ *             Gets authentication tag from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @result
+ *             Authentication tag, if present, as an XPC data object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_result_get_authentication_tag_object(xpc_object_t result);
+
+/*!
+ *     @brief
+ *             Gets error code from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Error code, if present. Otherwise, 0.
+ */
+DNSServiceErrorType
+dnssd_xpc_result_get_error(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets flags from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Flags, if present. Otherwise, 0.
+ */
+DNSServiceFlags
+dnssd_xpc_result_get_flags(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets interface index from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Interface index, if present. Otherwise, 0.
+ */
+uint32_t
+dnssd_xpc_result_get_interface_index(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets record class from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Record class, if present. Otherwise, 0.
+ */
+uint16_t
+dnssd_xpc_result_get_record_class(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Gets record data from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @result
+ *             Record data, if present, as an XPC data object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_result_get_record_data_object(xpc_object_t result);
+
+/*!
+ *     @brief
+ *             Gets record name from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @result
+ *             Record name, if present, as an XPC string object. Otherwise, NULL.
+ */
+xpc_object_t _Nullable
+dnssd_xpc_result_get_record_name_object(xpc_object_t result);
+
+/*!
+ *     @brief
+ *             Gets record type from a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param out_valid
+ *             If non-NULL, set to true if value is present and of correct type, otherwise, set to false.
+ *
+ *     @result
+ *             Record type, if present. Otherwise, 0.
+ */
+uint16_t
+dnssd_xpc_result_get_record_type(xpc_object_t result, bool * _Nullable out_valid);
+
+/*!
+ *     @brief
+ *             Sets the authentication tag in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param auth_tag_ptr
+ *             Pointer to the authentication tag.
+ *
+ *     @param auth_tag_len
+ *             Length of the authentication tag.
+ */
+void
+dnssd_xpc_result_set_authentication_tag(xpc_object_t result, const void *auth_tag_ptr, size_t auth_tag_len);
+
+/*!
+ *     @brief
+ *             Sets the error code in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param error
+ *             Error code.
+ */
+void
+dnssd_xpc_result_set_error(xpc_object_t result, DNSServiceErrorType error);
+
+/*!
+ *     @brief
+ *             Sets flags in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param flags
+ *             Flags.
+ */
+void
+dnssd_xpc_result_set_flags(xpc_object_t result, DNSServiceFlags flags);
+
+/*!
+ *     @brief
+ *             Sets interface index in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param interface_index
+ *             Interface index.
+ */
+void
+dnssd_xpc_result_set_interface_index(xpc_object_t result, uint32_t interface_index);
+
+/*!
+ *     @brief
+ *             Sets record class in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param class
+ *             Record class.
+ */
+void
+dnssd_xpc_result_set_record_class(xpc_object_t result, uint16_t class);
+
+/*!
+ *     @brief
+ *             Sets the record data in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param data_ptr
+ *             Pointer to the record data.
+ *
+ *     @param data_len
+ *             Length of the record data.
+ */
+void
+dnssd_xpc_result_set_record_data(xpc_object_t result, const void * _Nullable data_ptr, size_t data_len);
+
+/*!
+ *     @brief
+ *             Sets record name in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param name
+ *             Record name.
+ */
+void
+dnssd_xpc_result_set_record_name(xpc_object_t result, const char *name);
+
+/*!
+ *     @brief
+ *             Sets record type in a command result dictionary.
+ *
+ *     @param result
+ *             The command result dictionary.
+ *
+ *     @param type
+ *             Record type.
+ */
+void
+dnssd_xpc_result_set_record_type(xpc_object_t result, uint16_t type);
+
+#ifdef __cplusplus
+}
+#endif
+
+CU_ASSUME_NONNULL_END
+
+#endif // __DNSSD_XPC_H__
diff --git a/mDNSMacOSX/dnssdutil-entitlements.plist b/mDNSMacOSX/dnssdutil-entitlements.plist
deleted file mode 100644 (file)
index 750f16a..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-       <key>com.apple.security.network.client</key>
-       <true/>
-       <key>com.apple.security.network.server</key>
-       <true/>
-       <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
-       <true/>
-</dict>
-</plist>
index 9c61e48c6f37dfdf15029e201cb08307a1b71fef..25bb05211ddc9cebfbd0396156b31d0e5a78c534 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2007-2019 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.
@@ -19,6 +18,7 @@
 
 #include <CoreFoundation/CoreFoundation.h>
 #include <sys/cdefs.h>
+#include <sys/socket.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <mach/mach.h>
@@ -38,7 +38,7 @@
 #include "helper-server.h"
 #include <xpc/private.h>
 
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
 #define NO_SECURITYFRAMEWORK 1
 #endif
 
@@ -185,7 +185,7 @@ static mDNSBool HelperPrefsGetValueBool(CFStringRef key, mDNSBool defaultVal)
     mDNSBool result = defaultVal;
     
     boolean = CFPreferencesCopyAppValue(key, kmDNSHelperProgramArgs);
-    if (boolean)
+    if (boolean != NULL)
     {
         if (CFGetTypeID(boolean) == CFBooleanGetTypeID())
             result = CFBooleanGetValue(boolean) ? mDNStrue : mDNSfalse;
@@ -263,26 +263,35 @@ static void handle_request(xpc_object_t req)
             
         case p2p_packetfilter:
         {
+            size_t count = 0;
             pfArray_t pfports;
             pfArray_t pfprotocols;
             const char *if_name;
             uint32_t cmd;
-            uint32_t count;
+            xpc_object_t xpc_obj_port_array;
+            size_t port_array_count = 0;
+            xpc_object_t xpc_obj_protocol_array;
+            size_t protocol_array_count = 0;
             
             cmd = xpc_dictionary_get_uint64(req, "pf_opcode");
             if_name = xpc_dictionary_get_string(req, "pf_ifname");
-            count = xpc_dictionary_get_uint64(req, "pf_count");
-            
-            pfports[0]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port0");
-            pfports[1]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port1");
-            pfports[2]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port2");
-            pfports[3]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_port3");
-            
-            pfprotocols[0]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol0");
-            pfprotocols[1]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol1");
-            pfprotocols[2]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol2");
-            pfprotocols[3]  = (uint16_t)xpc_dictionary_get_uint64(req, "pf_protocol3");
-            
+            xpc_obj_port_array = xpc_dictionary_get_value(req, "xpc_obj_array_port");
+            if ((void *)xpc_obj_port_array != NULL)
+                port_array_count = xpc_array_get_count(xpc_obj_port_array);
+            xpc_obj_protocol_array = xpc_dictionary_get_value(req, "xpc_obj_array_protocol");
+            if ((void *)xpc_obj_protocol_array != NULL)
+                protocol_array_count = xpc_array_get_count(xpc_obj_protocol_array);
+            if (port_array_count != protocol_array_count)
+                break;
+            if (port_array_count > PFPortArraySize)
+                break;
+            count = port_array_count;
+
+            for (size_t i = 0; i < count; i++) {
+                pfports[i] = (uint16_t)xpc_array_get_uint64(xpc_obj_port_array, i);
+                pfprotocols[i] = (uint16_t)xpc_array_get_uint64(xpc_obj_protocol_array, i);
+            }
+
             os_log_info(log_handle,"Calling new PacketFilterControl()");
             PacketFilterControl(cmd, if_name, count, pfports, pfprotocols);
             break;
@@ -332,46 +341,28 @@ static void handle_request(xpc_object_t req)
         case set_localaddr_cacheentry:
         {
             int if_index, family;
-            
+            size_t ip_len, eth_len;
+
             if_index = xpc_dictionary_get_uint64(req, "slace_ifindex");
             family   = xpc_dictionary_get_uint64(req, "slace_family");
-            
-            const uint8_t* ip  = xpc_dictionary_get_data(req, "slace_ip", NULL);
-            const uint8_t* eth = xpc_dictionary_get_data(req, "slace_eth", NULL);
-            
-            os_log_info(log_handle, "Calling new SetLocalAddressCacheEntry() if_index[%d] family[%d] ", if_index, family);
 
-            SetLocalAddressCacheEntry(if_index, family, ip, eth, &error_code);
-            
-            /*
-            static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen)
+            const uint8_t * const ip = (const uint8_t *)xpc_dictionary_get_data(req, "slace_ip", &ip_len);
+            if (ip_len != sizeof(v6addr_t))
             {
-                if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
-                {
-                    os_log(log_handle, "inet_ntop failed: %s", strerror(errno));
-                    return -1;
-                }
-                else
-                {
-                    return 0;
-                }
+                error_code = kHelperErr_ParamErr;
+                break;
             }
 
-            ethaddr_t eth = { 0x33, 0x33, 0x00, 0x00, 0x00, 0x01 } ;
-            const uint8_t* slace_ip = NULL;
-            v6addr_t addr_ipv6;
-            size_t ip_len;
-            slace_ip = xpc_dictionary_get_data(req, "slace_ip", &ip_len);
-            if (slace_ip && (ip_len == sizeof(v6addr_t)))
+            const uint8_t * const eth = (const uint8_t *)xpc_dictionary_get_data(req, "slace_eth", &eth_len);
+            if (eth_len != sizeof(ethaddr_t))
             {
-                os_log(log_handle, "mDNSResponderHelper: doing memcpy()");
-                memcpy(&addr_ipv6, slace_ip, ip_len);
+                error_code = kHelperErr_ParamErr;
+                break;
             }
-            char test_ipv6_str[46];
-            v6addr_to_string(addr_ipv6, test_ipv6_str, sizeof(test_ipv6_str));
-            os_log(log_handle, "mDNSResponderHelper: handle_request: set_localaddr_cacheentry: test_ipv6_str is %s", test_ipv6_str);
-            */
-                        
+
+            os_log_info(log_handle, "Calling new SetLocalAddressCacheEntry() if_index[%d] family[%d] ", if_index, family);
+
+            SetLocalAddressCacheEntry(if_index, family, ip, eth, &error_code);
             break;
         }
             
@@ -379,6 +370,7 @@ static void handle_request(xpc_object_t req)
         {
             uint16_t lport, rport, win;
             uint32_t seq, ack;
+            size_t sadd6_len, dadd6_len;
             
             lport = xpc_dictionary_get_uint64(req, "send_keepalive_lport");
             rport = xpc_dictionary_get_uint64(req, "send_keepalive_rport");
@@ -386,9 +378,14 @@ static void handle_request(xpc_object_t req)
             ack   = xpc_dictionary_get_uint64(req, "send_keepalive_ack");
             win   = xpc_dictionary_get_uint64(req, "send_keepalive_win");
             
-            const uint8_t* sadd6 = xpc_dictionary_get_data(req, "send_keepalive_sadd", NULL);
-            const uint8_t* dadd6 = xpc_dictionary_get_data(req, "send_keepalive_dadd", NULL);
-            
+            const uint8_t * const sadd6 = (const uint8_t *)xpc_dictionary_get_data(req, "send_keepalive_sadd", &sadd6_len);
+            const uint8_t * const dadd6 = (const uint8_t *)xpc_dictionary_get_data(req, "send_keepalive_dadd", &dadd6_len);
+            if ((sadd6_len != sizeof(v6addr_t)) || (dadd6_len != sizeof(v6addr_t)))
+            {
+                error_code = kHelperErr_ParamErr;
+                break;
+            }
+
             os_log_info(log_handle, "helper-main: handle_request: send_keepalive: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]",
                            lport, rport, seq, ack, win);
             
@@ -403,14 +400,20 @@ static void handle_request(xpc_object_t req)
             uint32_t seq, ack;
             uint16_t win;
             int32_t  intfid;
+            size_t laddr_len, raddr_len;
             
             lport    = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_lport");
             rport    = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_rport");
             family   = xpc_dictionary_get_uint64(req, "retreive_tcpinfo_family");
-            
-            const uint8_t* laddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_laddr", NULL);
-            const uint8_t* raddr = xpc_dictionary_get_data(req, "retreive_tcpinfo_raddr", NULL);
-            
+
+            const uint8_t * const laddr = (const uint8_t *)xpc_dictionary_get_data(req, "retreive_tcpinfo_laddr", &laddr_len);
+            const uint8_t * const raddr = (const uint8_t *)xpc_dictionary_get_data(req, "retreive_tcpinfo_raddr", &raddr_len);
+            if ((laddr_len != sizeof(v6addr_t)) || (raddr_len != sizeof(v6addr_t)))
+            {
+                error_code = kHelperErr_ParamErr;
+                break;
+            }
+
             os_log_info(log_handle, "helper-main: handle_request: retreive_tcpinfo: lport is[%d] rport is[%d] family is [%d]",
                            lport, rport, family);
             
@@ -430,33 +433,6 @@ static void handle_request(xpc_object_t req)
             break;
         }
             
-        case autotunnel_setkeys:
-        {
-            uint16_t lport, rport;
-            int replace_del;
-            const char *fqdnstr;
-            
-            lport        = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_lport");
-            rport        = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_rport");
-            replace_del  = xpc_dictionary_get_uint64(req, "autotunnelsetkeys_repdel");
-
-            const uint8_t* local_inner  =  xpc_dictionary_get_data(req, "autotunnelsetkeys_localinner", NULL);
-            const uint8_t* local_outer  =  xpc_dictionary_get_data(req, "autotunnelsetkeys_localouter", NULL);
-            const uint8_t* remote_inner =  xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteinner", NULL);
-            const uint8_t* remote_outer =  xpc_dictionary_get_data(req, "autotunnelsetkeys_remoteouter", NULL);
-            
-            fqdnstr = xpc_dictionary_get_string(req, "autotunnelsetkeys_fqdnStr");
-            
-            os_log_info(log_handle, "helper-main: handle_request: autotunnel_setkeys: lport is[%d] rport is[%d] replace_del is [%d]",
-                        lport, rport, replace_del);
-            
-
-            HelperAutoTunnelSetKeys(replace_del, local_inner, local_outer, lport, remote_inner, remote_outer, rport, fqdnstr, &error_code);
-
-            break;
-        }
-
-        
         case keychain_getsecrets:
         {
             unsigned int num_sec  = 0;
@@ -469,13 +445,12 @@ static void handle_request(xpc_object_t req)
             
             if (response)
             {
-                xpc_dictionary_set_uint64(response, "keychain_num_secrets",   num_sec);
+                xpc_dictionary_set_uint64(response, "keychain_num_secrets", num_sec);
                 xpc_dictionary_set_data(response, "keychain_secrets", (void *)secrets, sec_cnt);
-                xpc_dictionary_set_uint64(response, "keychain_secrets_count", sec_cnt);
             }
             
-            os_log_info(log_handle,"helper-main: handle_request: keychain_getsecrets: num_secrets is %d, secrets is %lu, secrets_Cnt is %d",
-                           num_sec, secrets, sec_cnt);
+            os_log_info(log_handle,"helper-main: handle_request: keychain_getsecrets: num_secrets is %u, secrets is %lu, secrets_Cnt is %u",
+                        num_sec, secrets, sec_cnt);
             
             if (secrets)
                 vm_deallocate(mach_task_self(), secrets, sec_cnt);
index c7c3496811312943b36ae36f611a8b1b97687e38..4783ee5ecd7597668b6bde6718dff81d1ecaf6c1 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2007-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2007-2019 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.
@@ -21,7 +20,6 @@
 #include <servers/bootstrap.h>
 #include <IOKit/IOReturn.h>
 #include <CoreFoundation/CoreFoundation.h>
-#include "mDNSDebug.h"
 #include "helper.h"
 #include <dispatch/dispatch.h>
 #include <arpa/inet.h>
@@ -46,7 +44,6 @@
 //*************************************************************************************************************
 // Globals
 static dispatch_queue_t HelperQueue;
-static xpc_connection_t helper_xpc_conn = NULL;
 
 static int64_t maxwait_secs = 5LL;
 
@@ -67,36 +64,52 @@ static void HelperLog(const char *prefix, xpc_object_t o)
 //*************************************************************************************************************
 
 
-mDNSlocal void Init_Connection(const char *servname)
+mDNSlocal xpc_connection_t Create_Connection(void)
 {
-    helper_xpc_conn = xpc_connection_create_mach_service(servname, HelperQueue, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
-    
-    xpc_connection_set_event_handler(helper_xpc_conn, ^(xpc_object_t event)
+    xpc_connection_t connection = xpc_connection_create_mach_service(kHelperService, HelperQueue,
+        XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
+    if (connection)
     {
-        mDNSHELPER_DEBUG("Init_Connection xpc: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
-    });
-    
-    xpc_connection_resume(helper_xpc_conn);
+        xpc_connection_set_event_handler(connection, ^(xpc_object_t event)
+        {
+            mDNSHELPER_DEBUG("Create_Connection xpc: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
+        });
+        xpc_connection_activate(connection);
+    }
+    return connection;
 }
 
-mDNSlocal int SendDict_ToServer(xpc_object_t msg)
+mDNSlocal int SendDict_ToServer(xpc_object_t msg, xpc_object_t *out_reply)
 {
+    xpc_connection_t connection;
+    dispatch_semaphore_t sem = NULL;
+    __block xpc_object_t reply = NULL;
     __block int errorcode = kHelperErr_NoResponse;
     
     HelperLog("SendDict_ToServer Sending msg to Daemon", msg);
     
-    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
-    dispatch_retain(sem); // for the block below
+    connection = Create_Connection();
+    if (!connection)
+    {
+        goto exit;
+    }
+
+    sem = dispatch_semaphore_create(0);
+    if (!sem)
+    {
+        goto exit;
+    }
     
-    xpc_connection_send_message_with_reply(helper_xpc_conn, msg, HelperQueue, ^(xpc_object_t recv_msg)
+    dispatch_retain(sem); // for the block below
+    xpc_connection_send_message_with_reply(connection, msg, HelperQueue, ^(xpc_object_t recv_msg)
     {
-        xpc_type_t type = xpc_get_type(recv_msg);
+        const xpc_type_t type = xpc_get_type(recv_msg);
                                                
         if (type == XPC_TYPE_DICTIONARY)
         {
             HelperLog("SendDict_ToServer Received reply msg from Daemon", recv_msg);
             uint64_t reply_status = xpc_dictionary_get_uint64(recv_msg, kHelperReplyStatus);
-            errorcode = xpc_dictionary_get_int64(recv_msg, kHelperErrCode);
+            errorcode = (int)xpc_dictionary_get_int64(recv_msg, kHelperErrCode);
             
             switch (reply_status)
             {
@@ -107,6 +120,8 @@ mDNSlocal int SendDict_ToServer(xpc_object_t msg)
                     LogMsg("default: Unexpected reply from Helper");
                     break;
             }
+            reply = recv_msg;
+            xpc_retain(reply);
         }
         else
         {
@@ -117,81 +132,40 @@ mDNSlocal int SendDict_ToServer(xpc_object_t msg)
         
         dispatch_semaphore_signal(sem);
         dispatch_release(sem);
-        
     });
     
     if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (maxwait_secs * NSEC_PER_SEC))) != 0)
+    {
         LogMsg("SendDict_ToServer: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait");
-    
-    dispatch_release(sem);
-    
-    mDNSHELPER_DEBUG("SendDict_ToServer returning with errorcode[%d]", errorcode);
-    
-    return errorcode;
-}
 
-mDNSlocal xpc_object_t SendDict_GetReply(xpc_object_t msg)
-{
-    // Create empty dictionary
-    __block xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-    if (!dict) return NULL;
-    xpc_retain(dict);
-
-    HelperLog("SendDict_GetReply Sending msg to Daemon", msg);
+        // If we insist on using a semaphore timeout, then cancel the connection if the timeout is reached.
+        // This forces the reply block to be called if a reply wasn't received to keep things serialized.
+        xpc_connection_cancel(connection);
+        dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
+    }
+    if (out_reply)
+    {
+        *out_reply = reply;
+        reply = NULL;
+    }
     
-    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
-    dispatch_retain(sem); // for the block below
+    mDNSHELPER_DEBUG("SendDict_ToServer returning with errorcode[%d]", errorcode);
     
-    xpc_connection_send_message_with_reply(helper_xpc_conn, msg, HelperQueue, ^(xpc_object_t recv_msg)
+exit:
+    if (connection)
     {
-        xpc_type_t type = xpc_get_type(recv_msg);
-                                               
-        if (type == XPC_TYPE_DICTIONARY)
-        {
-            HelperLog("SendDict_GetReply Received reply msg from Daemon", recv_msg);
-            uint64_t reply_status = xpc_dictionary_get_uint64(recv_msg, kHelperReplyStatus);
-            
-            switch (reply_status)
-            {
-                case kHelperReply_ACK:
-                    mDNSHELPER_DEBUG("NoError: successful reply");
-                    break;
-                default:
-                    LogMsg("default: Unexpected reply from Helper");
-                    break;
-            }
-            // Copy result into dict reply
-            xpc_dictionary_apply(recv_msg, ^bool(const char *key, xpc_object_t value)
-            {
-                xpc_dictionary_set_value(dict, key, value);
-                return true;
-            });
-        }
-        else
-        {
-            LogMsg("SendDict_GetReply Received unexpected reply from daemon [%s]",
-                    xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION));
-            HelperLog("SendDict_GetReply Unexpected Reply contents", recv_msg);
-        }
-        
-        dispatch_semaphore_signal(sem);
-        dispatch_release(sem);
-        xpc_release(dict);
-
-    });
-    
-    if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (maxwait_secs * NSEC_PER_SEC))) != 0)
+        xpc_connection_cancel(connection);
+        xpc_release(connection);
+    }
+    if (sem)
     {
-        LogMsg("SendDict_GetReply: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait");
-        xpc_release(dict);
         dispatch_release(sem);
-
-        return NULL;
     }
-    
-    dispatch_release(sem);
-    
-    return dict;
+    if (reply)
+    {
+        xpc_release(reply);
+    }
+    return errorcode;
 }
 
 //**************************************************************************************************************
@@ -225,7 +199,6 @@ void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new)
     
     
     mDNSHELPER_DEBUG("mDNSPreferencesSetName: XPC IPC Test oldname %s newname %s", names.oldname, names.newname);
-    Init_Connection(kHelperService);
      
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
@@ -235,7 +208,7 @@ void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new)
     xpc_dictionary_set_string(dict, kPrefsOldName, names.oldname);
     xpc_dictionary_set_string(dict, kPrefsNewName, names.newname);
     
-    SendDict_ToServer(dict);
+    SendDict_ToServer(dict, NULL);
     xpc_release(dict);
     dict = NULL;
     
@@ -244,12 +217,11 @@ void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new)
 void mDNSRequestBPF()
 {
      mDNSHELPER_DEBUG("mDNSRequestBPF: Using XPC IPC");
-     Init_Connection(kHelperService);
      
      // Create Dictionary To Send
      xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
      xpc_dictionary_set_uint64(dict, kHelperMode, bpf_request);
-     SendDict_ToServer(dict);
+     SendDict_ToServer(dict, NULL);
      xpc_release(dict);
      dict = NULL;
 
@@ -260,7 +232,6 @@ int mDNSPowerRequest(int key, int interval)
     int err_code = kHelperErr_NotConnected;
     
     mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC calling out to Helper key is [%d] interval is [%d]", key, interval);
-    Init_Connection(kHelperService);
     
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
@@ -268,7 +239,7 @@ int mDNSPowerRequest(int key, int interval)
     xpc_dictionary_set_uint64(dict, "powerreq_key", key);
     xpc_dictionary_set_uint64(dict, "powerreq_interval", interval);
     
-    err_code = SendDict_ToServer(dict);
+    err_code = SendDict_ToServer(dict, NULL);
     xpc_release(dict);
     dict = NULL;
     
@@ -282,8 +253,6 @@ int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, co
     
     mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC calling out to Helper: ifindex is [%d] family is [%d]", ifindex, family);
     
-    Init_Connection(kHelperService);
-    
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
     xpc_dictionary_set_uint64(dict, kHelperMode, set_localaddr_cacheentry);
@@ -294,7 +263,7 @@ int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, co
     xpc_dictionary_set_data(dict, "slace_ip", (uint8_t*)ip, sizeof(v6addr_t));
     xpc_dictionary_set_data(dict, "slace_eth", (uint8_t*)eth, sizeof(ethaddr_t));
     
-    err_code = SendDict_ToServer(dict);
+    err_code = SendDict_ToServer(dict, NULL);
     xpc_release(dict);
     dict = NULL;
     
@@ -306,8 +275,6 @@ int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, co
 void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text
 {
     mDNSHELPER_DEBUG("mDNSNotify() calling out to Helper XPC IPC title[%s] msg[%s]", title, msg);
-
-    Init_Connection(kHelperService);
     
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
@@ -316,7 +283,7 @@ void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 te
     xpc_dictionary_set_string(dict, "notify_title", title);
     xpc_dictionary_set_string(dict, "notify_msg", msg);
     
-    SendDict_ToServer(dict);
+    SendDict_ToServer(dict, NULL);
     xpc_release(dict);
     dict = NULL;
     
@@ -329,32 +296,28 @@ int mDNSKeychainGetSecrets(CFArrayRef *result)
     CFPropertyListRef plist = NULL;
     CFDataRef bytes = NULL;
     unsigned int numsecrets = 0;
-    unsigned int secretsCnt = 0;
+    size_t secretsCnt = 0;
     int error_code = kHelperErr_NotConnected;
     xpc_object_t reply_dict = NULL;
     const void *sec = NULL;
-    size_t secrets_size = 0;
     
     mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper");
     
-    Init_Connection(kHelperService);
-    
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
     xpc_dictionary_set_uint64(dict, kHelperMode, keychain_getsecrets);
 
-    reply_dict = SendDict_GetReply(dict);
+    SendDict_ToServer(dict, &reply_dict);
  
     if (reply_dict != NULL)
     {
         numsecrets = xpc_dictionary_get_uint64(reply_dict, "keychain_num_secrets");
-        sec = xpc_dictionary_get_data(reply_dict, "keychain_secrets", &secrets_size);
-        secretsCnt = xpc_dictionary_get_uint64(reply_dict, "keychain_secrets_count");
+        sec = xpc_dictionary_get_data(reply_dict, "keychain_secrets", &secretsCnt);
         error_code = xpc_dictionary_get_int64(reply_dict,   kHelperErrCode);
     }
  
-    mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper: numsecrets is %d, secretsCnt is %d error_code is %d secret_size is %d",
-           numsecrets, secretsCnt, error_code, secrets_size);
+    mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper: numsecrets is %u, secretsCnt is %u error_code is %d",
+                     numsecrets, (unsigned int)secretsCnt, error_code);
      
     if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)sec, secretsCnt, kCFAllocatorNull)))
     {
@@ -396,72 +359,6 @@ fin:
     return error_code;
 }
 
-
-int mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
-                          v6addr_t local_outer, short local_port, v6addr_t remote_inner,
-                          v6addr_t remote_outer, short remote_port, const char* const prefix, const domainname *const fqdn)
-{
-    
-    int err_code = kHelperErr_NotConnected;
-    
-    mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC calling out to Helper. Parameters are repdel[%d], lport[%d], rport[%d], prefix[%s], fqdn[%##s]",
-                      replacedelete, local_port, remote_port, prefix, fqdn->c);
-    
-    
-    char buf1[INET6_ADDRSTRLEN];
-    char buf2[INET6_ADDRSTRLEN];
-    char buf3[INET6_ADDRSTRLEN];
-    char buf4[INET6_ADDRSTRLEN];
-    
-    buf1[0] = 0;
-    buf2[0] = 0;
-    buf3[0] = 0;
-    buf4[0] = 0;
-    
-    inet_ntop(AF_INET6, local_inner, buf1, sizeof(buf1));
-    inet_ntop(AF_INET6, local_outer, buf2, sizeof(buf2));
-    inet_ntop(AF_INET6, remote_inner, buf3, sizeof(buf3));
-    inet_ntop(AF_INET6, remote_outer, buf4, sizeof(buf4));
-    
-    char fqdnStr[MAX_ESCAPED_DOMAIN_NAME + 10] = { 0 }; // Assume the prefix is no larger than 10 chars
-    if (fqdn)
-    {
-        mDNSPlatformStrCopy(fqdnStr, prefix);
-        ConvertDomainNameToCString(fqdn, fqdnStr + mDNSPlatformStrLen(prefix));
-    }
-    
-    mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC calling out to Helper: Parameters are local_inner is %s, local_outeris %s, remote_inner is %s, remote_outer is %s",
-                      buf1, buf2, buf3, buf4);
-    
-    Init_Connection(kHelperService);
-    
-    // Create Dictionary To Send
-    xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
-    xpc_dictionary_set_uint64(dict, kHelperMode, autotunnel_setkeys);
-    
-    xpc_dictionary_set_data(dict, "autotunnelsetkeys_localinner",  (uint8_t*)local_inner,  sizeof(v6addr_t));
-    xpc_dictionary_set_data(dict, "autotunnelsetkeys_localouter",  (uint8_t*)local_outer,  sizeof(v6addr_t));
-    xpc_dictionary_set_data(dict, "autotunnelsetkeys_remoteinner", (uint8_t*)remote_inner, sizeof(v6addr_t));
-    xpc_dictionary_set_data(dict, "autotunnelsetkeys_remoteouter", (uint8_t*)remote_outer, sizeof(v6addr_t));
-    
-    xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_lport",  local_port);
-    xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_rport",  remote_port);
-    xpc_dictionary_set_uint64(dict, "autotunnelsetkeys_repdel", replacedelete);
-
-    // xpc_dictionary_set_string(dict, "autotunnelsetkeys_prefix",  prefix);
-    xpc_dictionary_set_string(dict, "autotunnelsetkeys_fqdnStr", fqdnStr);
-    
-    err_code = SendDict_ToServer(dict);
-    
-    xpc_release(dict);
-    dict = NULL;
-
-    mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: Using XPC IPC returning error_code %d", err_code);
-    
-    mDNSHELPER_DEBUG("mDNSAutoTunnelSetKeys: this should NOT be done in mDNSResponder/Helper. For future we shall be using <rdar://problem/13792729>");
-    return err_code;
-}
-
 void mDNSSendWakeupPacket(unsigned int ifid, char *eth_addr, char *ip_addr, int iteration)
 {
     // (void) ip_addr; // unused
@@ -470,8 +367,6 @@ void mDNSSendWakeupPacket(unsigned int ifid, char *eth_addr, char *ip_addr, int
     mDNSHELPER_DEBUG("mDNSSendWakeupPacket: Entered ethernet address[%s],ip_address[%s], interface_id[%d], iteration[%d]",
            eth_addr, ip_addr, ifid, iteration);
     
-    Init_Connection(kHelperService);
-    
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
     xpc_dictionary_set_uint64(dict, kHelperMode, send_wakepkt);
@@ -481,7 +376,7 @@ void mDNSSendWakeupPacket(unsigned int ifid, char *eth_addr, char *ip_addr, int
     xpc_dictionary_set_string(dict, "ip_address", ip_addr);
     xpc_dictionary_set_uint64(dict, "swp_iteration", iteration);
     
-    SendDict_ToServer(dict);
+    SendDict_ToServer(dict, NULL);
     xpc_release(dict);
     dict = NULL;
 
@@ -499,7 +394,6 @@ void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pf
     mDNSPlatformMemCopy(pfa.protocolArray, protocolArray, sizeof(pfArray_t));
 
     mDNSHELPER_DEBUG("mDNSPacketFilterControl: XPC IPC, ifname %s", ifname);
-    Init_Connection(kHelperService);
     
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
@@ -508,18 +402,20 @@ void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pf
     xpc_dictionary_set_uint64(dict, "pf_opcode", command);
     if (ifname)
         xpc_dictionary_set_string(dict, "pf_ifname", ifname);
-    xpc_dictionary_set_uint64(dict, "pf_count", count);
-
-    xpc_dictionary_set_uint64(dict, "pf_port0", pfa.portArray[0]);
-    xpc_dictionary_set_uint64(dict, "pf_port1", pfa.portArray[1]);
-    xpc_dictionary_set_uint64(dict, "pf_port2", pfa.portArray[2]);
-    xpc_dictionary_set_uint64(dict, "pf_port3", pfa.portArray[3]);
-    
-    xpc_dictionary_set_uint64(dict, "pf_protocol0", pfa.protocolArray[0]);
-    xpc_dictionary_set_uint64(dict, "pf_protocol1", pfa.protocolArray[1]);
-    xpc_dictionary_set_uint64(dict, "pf_protocol2", pfa.protocolArray[2]);
-    xpc_dictionary_set_uint64(dict, "pf_protocol3", pfa.protocolArray[3]);
-    SendDict_ToServer(dict);
+
+    xpc_object_t xpc_obj_portArray = xpc_array_create(NULL, 0);
+    xpc_object_t xpc_obj_protocolArray = xpc_array_create(NULL, 0);
+
+    for (size_t i = 0; i < count && i < PFPortArraySize; i++) {
+        xpc_array_set_uint64(xpc_obj_portArray, XPC_ARRAY_APPEND, pfa.portArray[i]);
+        xpc_array_set_uint64(xpc_obj_protocolArray, XPC_ARRAY_APPEND, pfa.protocolArray[i]);
+    }
+    xpc_dictionary_set_value(dict, "xpc_obj_array_port", xpc_obj_portArray);
+    xpc_dictionary_set_value(dict, "xpc_obj_array_protocol", xpc_obj_protocolArray);
+    xpc_release(xpc_obj_portArray);
+    xpc_release(xpc_obj_protocolArray);
+    
+    SendDict_ToServer(dict, NULL);
     xpc_release(dict);
     dict = NULL;
     
@@ -544,8 +440,6 @@ void mDNSSendKeepalive(const v6addr_t sadd, const v6addr_t dadd, uint16_t lport,
     inet_ntop(AF_INET6, dadd, buf2, sizeof(buf2));
     mDNSHELPER_DEBUG("mDNSSendKeepalive: Using XPC IPC calling out to Helper: sadd is %s, dadd is %s", buf1, buf2);
     
-    Init_Connection(kHelperService);
-    
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
     xpc_dictionary_set_uint64(dict, kHelperMode, send_keepalive);
@@ -559,7 +453,7 @@ void mDNSSendKeepalive(const v6addr_t sadd, const v6addr_t dadd, uint16_t lport,
     xpc_dictionary_set_uint64(dict, "send_keepalive_ack", ack);
     xpc_dictionary_set_uint64(dict, "send_keepalive_win", win);
     
-    SendDict_ToServer(dict);
+    SendDict_ToServer(dict, NULL);
     xpc_release(dict);
     dict = NULL;
     
@@ -582,8 +476,6 @@ int mDNSRetrieveTCPInfo(int family, v6addr_t laddr, uint16_t lport, v6addr_t rad
     inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2));
     mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo:: Using XPC IPC calling out to Helper: laddr is %s, raddr is %s", buf1, buf2);
     
-    Init_Connection(kHelperService);
-    
     // Create Dictionary To Send
     xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
     xpc_dictionary_set_uint64(dict, kHelperMode, retreive_tcpinfo);
@@ -595,7 +487,7 @@ int mDNSRetrieveTCPInfo(int family, v6addr_t laddr, uint16_t lport, v6addr_t rad
     xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_lport", lport);
     xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_rport", rport);
     
-    reply_dict = SendDict_GetReply(dict);
+    SendDict_ToServer(dict, &reply_dict);
     
     if (reply_dict != NULL)
     {
index 7b6cb89748d606e5fba21821187a93fa98629a6a..dae2cc4d788ffee057340fa94eedfe22fd07df94 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2007-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2007-2019 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.
@@ -50,7 +49,6 @@
 #include "mDNSEmbeddedAPI.h"
 #include "dns_sd.h"
 #include "dnssd_ipc.h"
-#include "libpfkey.h"
 #include "helper.h"
 #include "helper-server.h"
 #include "P2PPacketFilter.h"
 #define RTF_IFSCOPE 0x1000000
 #endif
 
-#if TARGET_OS_EMBEDDED
-#ifndef MDNS_NO_IPSEC
-#define MDNS_NO_IPSEC 1
-#endif
-
+#if TARGET_OS_IPHONE
 #define NO_CFUSERNOTIFICATION 1
 #define NO_SECURITYFRAMEWORK 1
 #endif
@@ -713,9 +707,6 @@ enum DNSKeyFormat
     formatNotDNSKey,
     formatDdnsTypeItem,
     formatDnsPrefixedServiceItem,
-#if MDNSRESPONDER_BTMM_SUPPORT
-    formatBtmmPrefixedServiceItem
-#endif
 };
 
 // On Mac OS X on Intel, the four-character string seems to be stored backwards, at least sometimes.
@@ -725,9 +716,6 @@ enum DNSKeyFormat
 
 
 #ifndef NO_SECURITYFRAMEWORK
-#if MDNSRESPONDER_BTMM_SUPPORT
-static const char btmmprefix[] = "btmmdns:";
-#endif
 static const char dnsprefix[] = "dns:";
 static const char ddns[] = "ddns";
 static const char ddnsrev[] = "sndd";
@@ -785,10 +773,6 @@ static enum DNSKeyFormat getDNSKeyFormat(SecKeychainItemRef item, SecKeychainAtt
     }
     if (attributes->attr[1].length >= sizeof(dnsprefix)-1 && 0 == strncasecmp(attributes->attr[1].data, dnsprefix, sizeof(dnsprefix)-1))
         format = formatDnsPrefixedServiceItem;
-#if MDNSRESPONDER_BTMM_SUPPORT
-    else if (attributes->attr[1].length >= sizeof(btmmprefix)-1 && 0 == strncasecmp(attributes->attr[1].data, btmmprefix, sizeof(btmmprefix)-1))
-        format = formatBtmmPrefixedServiceItem;
-#endif
     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))
@@ -830,9 +814,6 @@ static CFPropertyListRef copyKeychainItemInfo(SecKeychainItemRef item, SecKeycha
             data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
             break;
         case formatDnsPrefixedServiceItem:
-#if MDNSRESPONDER_BTMM_SUPPORT
-        case formatBtmmPrefixedServiceItem:
-#endif
             data = CFDataCreate(kCFAllocatorDefault, attributes->attr[1].data, attributes->attr[1].length);
             break;
         default:
@@ -1487,968 +1468,3 @@ void RetrieveTCPInfo(int family, const v6addr_t laddr, uint16_t lport, const v6a
     *err    = KERN_SUCCESS;
     
 }
-
-#ifndef MDNS_NO_IPSEC
-
-static const char configHeader[] = "# BackToMyMac\n";
-static const char g_racoon_config_dir[] = "/var/run/racoon/";
-static const char g_racoon_config_dir_old[] = "/etc/racoon/remote/";
-
-static int MacOSXSystemBuildNumber(char* letter_out, int* minor_out)
-{
-    int major = 0, minor = 0;
-    char letter = 0, buildver[256]="<Unknown>";
-    CFDictionaryRef vers = _CFCopySystemVersionDictionary();
-    if (vers)
-    {
-        CFStringRef cfbuildver = CFDictionaryGetValue(vers, _kCFSystemVersionBuildVersionKey);
-        if (cfbuildver) CFStringGetCString(cfbuildver, buildver, sizeof(buildver), kCFStringEncodingUTF8);
-        sscanf(buildver, "%d%c%d", &major, &letter, &minor);
-        CFRelease(vers);
-    }
-    else
-        os_log_info(log_handle, "_CFCopySystemVersionDictionary failed");
-    
-    if (!major) { major=16; letter = 'A'; minor = 300; os_log_info(log_handle, "Note: No Major Build Version number found; assuming 16A300"); }
-    if (letter_out) *letter_out = letter;
-    if (minor_out) *minor_out = minor;
-    return(major);
-}
-
-static int UseOldRacoon()
-{
-    static int g_oldRacoon = -1;
-    
-    if (g_oldRacoon == -1)
-    {
-        char letter = 0;
-        int minor = 0;
-        g_oldRacoon = (MacOSXSystemBuildNumber(&letter, &minor) < 10);
-        os_log_debug(log_handle, "%s", g_oldRacoon ? "old" : "new");
-    }
-    
-    return g_oldRacoon;
-}
-
-static int RacoonSignal()
-{
-    return UseOldRacoon() ? SIGHUP : SIGUSR1;
-}
-
-static int notifyRacoon(void)
-{
-    os_log_debug(log_handle,"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)
-    {
-        os_log_debug(log_handle,"open \"%s\" failed, and that's OK: %s", racoon_pid_path,
-              strerror(errno));
-        return kHelperErr_RacoonNotificationFailed;
-    }
-    n = read(fd, buf, sizeof(buf)-1);
-    close(fd);
-    if (1 > n)
-    {
-        os_log_debug(log_handle,"read of \"%s\" failed: %s", racoon_pid_path,
-              n == 0 ? "empty file" : strerror(errno));
-        return kHelperErr_RacoonNotificationFailed;
-    }
-    buf[n] = '\0';
-    m = strtoul(buf, &p, 10);
-    if (*p != '\0' && !isspace(*p))
-    {
-        os_log_debug(log_handle,"invalid PID \"%s\" (around '%c')", buf, *p);
-        return kHelperErr_RacoonNotificationFailed;
-    }
-    if (2 > m)
-    {
-        os_log_debug(log_handle,"refusing to kill PID %lu", m);
-        return kHelperErr_RacoonNotificationFailed;
-    }
-    if (0 != kill(m, RacoonSignal()))
-    {
-        os_log_debug(log_handle,"Could not signal racoon (%lu): %s", m, strerror(errno));
-        return kHelperErr_RacoonNotificationFailed;
-    }
-    
-    os_log_debug(log_handle, "Sent racoon (%lu) signal %d", m, RacoonSignal());
-    return 0;
-}
-
-static const char* GetRacoonConfigDir()
-{
-    return UseOldRacoon() ? g_racoon_config_dir_old : g_racoon_config_dir;
-}
-/*
-static const char* GetOldRacoonConfigDir()
-{
-    return UseOldRacoon() ? NULL : g_racoon_config_dir_old;
-}
-*/
-
-static void closefds(int from)
-{
-    int fd = 0;
-    struct dirent entry, *entryp = NULL;
-    DIR *dirp = opendir("/dev/fd");
-    
-    if (dirp == NULL)
-    {
-        /* fall back to the erroneous getdtablesize method */
-        for (fd = from; fd < getdtablesize(); ++fd)
-            close(fd);
-        return;
-    }
-    while (0 == readdir_r(dirp, &entry, &entryp) && NULL != entryp)
-    {
-        fd = atoi(entryp->d_name);
-        if (fd >= from && fd != dirfd(dirp))
-            close(fd);
-    }
-    closedir(dirp);
-}
-
-
-static int startRacoonOld(void)
-{
-    os_log_debug(log_handle,"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);
-        os_log_info(log_handle, "execve of \"%s\" failed: %s",
-                racoon_args[0], strerror(errno));
-        exit(2);
-    }
-    os_log_info(log_handle,"racoon (pid=%lu) started",
-            (unsigned long)pid);
-    n = waitpid(pid, &status, 0);
-    if (-1 == n)
-    {
-        os_log(log_handle, "Unexpected waitpid failure: %s",
-                strerror(errno));
-        return kHelperErr_RacoonStartFailed;
-    }
-    else if (pid != n)
-    {
-        os_log(log_handle, "Unexpected waitpid return value %d", (int)n);
-        return kHelperErr_RacoonStartFailed;
-    }
-    else if (WIFSIGNALED(status))
-    {
-        os_log(log_handle,
-                "racoon (pid=%lu) terminated due to signal %d",
-                (unsigned long)pid, WTERMSIG(status));
-        return kHelperErr_RacoonStartFailed;
-    }
-    else if (WIFSTOPPED(status))
-    {
-        os_log(log_handle,
-                "racoon (pid=%lu) has stopped due to signal %d",
-                (unsigned long)pid, WSTOPSIG(status));
-        return kHelperErr_RacoonStartFailed;
-    }
-    else if (0 != WEXITSTATUS(status))
-    {
-        os_log(log_handle,
-                "racoon (pid=%lu) exited with status %d",
-                (unsigned long)pid, WEXITSTATUS(status));
-        return kHelperErr_RacoonStartFailed;
-    }
-    os_log_debug(log_handle, "racoon (pid=%lu) daemonized normally", (unsigned long)pid);
-    return 0;
-}
-
-// constant and structure for the racoon control socket
-#define VPNCTL_CMD_PING 0x0004
-typedef struct vpnctl_hdr_struct
-{
-    u_int16_t msg_type;
-    u_int16_t flags;
-    u_int32_t cookie;
-    u_int32_t reserved;
-    u_int16_t result;
-    u_int16_t len;
-} vpnctl_hdr;
-
-static int startRacoon(void)
-{
-    os_log_debug(log_handle,"entry");
-    int fd = socket(PF_UNIX, SOCK_STREAM, 0);
-    if (0 > fd)
-    {
-        os_log(log_handle,"Could not create endpoint for racoon control socket: %d %s",
-                errno, strerror(errno));
-        return kHelperErr_RacoonStartFailed;
-    }
-    
-    struct sockaddr_un saddr;
-    memset(&saddr, 0, sizeof(saddr));
-    saddr.sun_family = AF_UNIX;
-    saddr.sun_len = sizeof(saddr);
-    static const char racoon_control_sock_path[] = "/var/run/vpncontrol.sock";
-    strcpy(saddr.sun_path, racoon_control_sock_path);
-    int result = connect(fd, (struct sockaddr*) &saddr, saddr.sun_len);
-    if (0 > result)
-    {
-        os_log(log_handle, "Could not connect racoon control socket %s: %d %s",
-                racoon_control_sock_path, errno, strerror(errno));
-        return kHelperErr_RacoonStartFailed;
-    }
-    
-    u_int32_t btmm_cookie = 0x4d4d5442;
-    vpnctl_hdr h = { htons(VPNCTL_CMD_PING), 0, btmm_cookie, 0, 0, 0 };
-    size_t bytes = 0;
-    ssize_t ret = 0;
-    
-    while (bytes < sizeof(vpnctl_hdr))
-    {
-        ret = write(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
-        if (ret == -1)
-        {
-            os_log(log_handle, "Could not write to racoon control socket: %d %s", errno, strerror(errno));
-            return kHelperErr_RacoonStartFailed;
-        }
-        bytes += ret;
-    }
-    
-    int nfds = fd + 1;
-    fd_set fds;
-    int counter = 0;
-    struct timeval tv;
-    bytes = 0;
-    h.cookie = 0;
-    
-    for (counter = 0; counter < 100; counter++)
-    {
-        FD_ZERO(&fds);
-        FD_SET(fd, &fds);
-        tv = (struct timeval){ 0, 10000 }; // 10 milliseconds * 100 iterations = 1 second max wait time
-        
-        result = select(nfds, &fds, (fd_set*)NULL, (fd_set*)NULL, &tv);
-        if (result > 0)
-        {
-            if (FD_ISSET(fd, &fds))
-            {
-                ret = read(fd, ((unsigned char*)&h)+bytes, sizeof(vpnctl_hdr) - bytes);
-                
-                if (ret == -1)
-                {
-                    os_log(log_handle,"Could not read from racoon control socket: %d %s", errno, strerror(errno));
-                    break;
-                }
-                bytes += ret;
-                if (bytes >= sizeof(vpnctl_hdr)) break;
-            }
-            else
-            {
-                os_log_debug(log_handle, "select returned but fd_isset not on expected fd");
-            }
-        }
-        else if (result < 0)
-        {
-            const int select_errno = errno;
-            os_log_debug(log_handle, "select returned %d errno %d %s", result, select_errno, strerror(select_errno));
-            if (select_errno != EINTR) break;
-        }
-    }
-    
-    close(fd);
-    
-    if (bytes < sizeof(vpnctl_hdr) || h.cookie != btmm_cookie)
-        return kHelperErr_RacoonStartFailed;
-    
-    os_log_debug(log_handle, "racoon started");
-    return 0;
-}
-
-static int kickRacoon(void)
-{
-    if ( 0 == notifyRacoon() )
-        return 0;
-    return UseOldRacoon() ? startRacoonOld() : startRacoon();
-}
-
-typedef enum _mDNSTunnelPolicyWhich
-{
-    kmDNSTunnelPolicySetup,
-    kmDNSTunnelPolicyTeardown,
-    kmDNSTunnelPolicyGenerate
-} mDNSTunnelPolicyWhich;
-
-// For kmDNSTunnelPolicySetup, you can setup IPv6-in-IPv6 tunnel or IPv6-in-IPv4 tunnel
-// kmDNSNoTunnel is used for other Policy types
-typedef enum _mDNSTunnelType
-{
-    kmDNSNoTunnel,
-    kmDNSIPv6IPv4Tunnel,
-    kmDNSIPv6IPv6Tunnel
-} mDNSTunnelType;
-
-static const uint8_t kWholeV6Mask = 128;
-
-static unsigned int routeSeq = 1;
-
-static int setupTunnelRoute(const v6addr_t local, const 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)))
-    {
-        os_log(log_handle,"socket(PF_ROUTE, ...) failed: %s", strerror(errno));
-        
-        err = kHelperErr_RoutingSocketCreationFailed;
-        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))
-    {
-        const int errno_ = errno;
-        
-        os_log_info(log_handle,"write to routing socket failed: %s", strerror(errno_));
-        if (EEXIST != errno_)
-        {
-            err = kHelperErr_RouteAdditionFailed;
-            goto fin;
-        }
-    }
-    
-fin:
-    if (0 <= s)
-        close(s);
-    return err;
-}
-
-static int teardownTunnelRoute(const 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)))
-    {
-        os_log(log_handle, "socket(PF_ROUTE, ...) failed: %s", strerror(errno));
-        err = kHelperErr_RoutingSocketCreationFailed;
-        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))
-    {
-        const int errno_ = errno;
-        
-        os_log_debug(log_handle,"write to routing socket failed: %s", strerror(errno_));
-        
-        if (ESRCH != errno_)
-        {
-            err = kHelperErr_RouteDeletionFailed;
-            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))
-    {
-        os_log(log_handle, "v4addr_to_string() inet_ntop failed: %s", strerror(errno));
-        return kHelperErr_InvalidNetworkAddress;
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-static int v6addr_to_string(const v6addr_t addr, char *buf, size_t buflen)
-{
-    if (NULL == inet_ntop(AF_INET6, addr, buf, buflen))
-    {
-        os_log(log_handle, "v6addr_to_string inet_ntop failed: %s", strerror(errno));
-        return kHelperErr_InvalidNetworkAddress;
-    }
-    else
-    {
-        return 0;
-    }
-}
-
-static int ensureExistenceOfRacoonConfigDir(const char* const racoon_config_dir)
-{
-    struct stat s;
-    int ret = stat(racoon_config_dir, &s);
-    if (ret != 0)
-    {
-        if (errno != ENOENT)
-        {
-            os_log(log_handle, "stat of \"%s\" failed (%d): %s",
-                    racoon_config_dir, ret, strerror(errno));
-            return -1;
-        }
-        else
-        {
-            ret = mkdir(racoon_config_dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
-            if (ret != 0)
-            {
-                os_log(log_handle, "mkdir \"%s\" failed: %s",
-                        racoon_config_dir, strerror(errno));
-                return -1;
-            }
-            else
-            {
-                os_log_info(log_handle, "created directory \"%s\"", racoon_config_dir);
-            }
-        }
-    }
-    else if (!(s.st_mode & S_IFDIR))
-    {
-        os_log(log_handle, "\"%s\" is not a directory!",
-                racoon_config_dir);
-        return -1;
-    }
-    
-    return 0;
-}
-
-
-
-/* Caller owns object returned in `policy' */
-static int generateTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type, int in,
-                     v4addr_t src, uint16_t src_port,
-                     v4addr_t dst, uint16_t dst_port,
-                     const v6addr_t src6, const v6addr_t dst6,
-                     ipsec_policy_t *policy, size_t *len)
-{
-    char srcs[INET_ADDRSTRLEN], dsts[INET_ADDRSTRLEN];
-    char srcs6[INET6_ADDRSTRLEN], dsts6[INET6_ADDRSTRLEN];
-    char buf[512];
-    char *inOut = in ? "in" : "out";
-    ssize_t n = 0;
-    int err = 0;
-    
-    *policy = NULL;
-    *len = 0;
-    
-    switch (which)
-    {
-        case kmDNSTunnelPolicySetup:
-            if (type == kmDNSIPv6IPv4Tunnel)
-            {
-                if (0 != (err = v4addr_to_string(src, srcs, sizeof(srcs))))
-                    goto fin;
-                if (0 != (err = v4addr_to_string(dst, dsts, sizeof(dsts))))
-                    goto fin;
-                n = snprintf(buf, sizeof(buf),
-                             "%s ipsec esp/tunnel/%s[%u]-%s[%u]/require",
-                             inOut, srcs, src_port, dsts, dst_port);
-            }
-            else if (type == kmDNSIPv6IPv6Tunnel)
-            {
-                if (0 != (err = v6addr_to_string(src6, srcs6, sizeof(srcs6))))
-                    goto fin;
-                if (0 != (err = v6addr_to_string(dst6, dsts6, sizeof(dsts6))))
-                    goto fin;
-                n = snprintf(buf, sizeof(buf),
-                             "%s ipsec esp/tunnel/%s-%s/require",
-                             inOut, srcs6, dsts6);
-            }
-            break;
-        case kmDNSTunnelPolicyTeardown:
-            n = strlcpy(buf, inOut, sizeof(buf));
-            break;
-        case kmDNSTunnelPolicyGenerate:
-            n = snprintf(buf, sizeof(buf), "%s generate", inOut);
-            break;
-        default:
-            err = kHelperErr_IPsecPolicyCreationFailed;
-            goto fin;
-    }
-    
-    if (n >= (int)sizeof(buf))
-    {
-        err = kHelperErr_ResultTooLarge;
-        goto fin;
-    }
-    
-    os_log_info(log_handle, "policy=\"%s\"", buf);
-    
-    if (NULL == (*policy = (ipsec_policy_t)ipsec_set_policy(buf, n)))
-    {
-        os_log_info(log_handle, "Could not create IPsec policy from \"%s\"", buf);
-        err = kHelperErr_IPsecPolicyCreationFailed;
-        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;
-    
-    os_log_debug(log_handle, "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)
-    {
-        os_log(log_handle, "Could not set IPsec policy: %s", ipsec_strerror());
-        err = kHelperErr_IPsecPolicySetFailed;
-        goto fin;
-    }
-    else
-    {
-        err = 0;
-    }
-    
-    os_log_debug(log_handle, "succeeded");
-    
-fin:
-    return err;
-}
-
-static int removeSA(int s, struct sockaddr *src, struct sockaddr *dst)
-{
-    int err = 0;
-    
-    os_log_debug(log_handle, "entry");
-    
-    err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, src, dst);
-    if (0 > err)
-    {
-        os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
-        err = kHelperErr_IPsecRemoveSAFailed;
-        goto fin;
-    }
-    err = pfkey_send_delete_all(s, SADB_SATYPE_ESP, IPSEC_MODE_ANY, dst, src);
-    if (0 > err)
-    {
-        os_log(log_handle, "Could not remove IPsec SA: %s", ipsec_strerror());
-        err = kHelperErr_IPsecRemoveSAFailed;
-        goto fin;
-    }
-    else
-        err = 0;
-    
-    os_log_debug(log_handle, "succeeded");
-    
-fin:
-    return err;
-}
-
-static int doTunnelPolicy(mDNSTunnelPolicyWhich which, mDNSTunnelType type,
-               const v6addr_t loc_inner, uint8_t loc_bits,
-               v4addr_t loc_outer, uint16_t loc_port,
-               const v6addr_t rmt_inner, uint8_t rmt_bits,
-               v4addr_t rmt_outer, uint16_t rmt_port,
-               const v6addr_t loc_outer6, const v6addr_t rmt_outer6)
-{
-    struct sockaddr_in6 sin6_loc;
-    struct sockaddr_in6 sin6_rmt;
-    ipsec_policy_t policy = NULL;
-    size_t len = 0;
-    int s = -1;
-    int err = 0;
-    
-    os_log_debug(log_handle,"entry");
-    if (0 > (s = pfkey_open()))
-    {
-        os_log(log_handle, "Could not create IPsec policy socket: %s", ipsec_strerror());
-        err = kHelperErr_IPsecPolicySocketCreationFailed;
-        goto fin;
-    }
-    
-    memset(&sin6_loc, 0, sizeof(sin6_loc));
-    sin6_loc.sin6_len = sizeof(sin6_loc);
-    sin6_loc.sin6_family = AF_INET6;
-    sin6_loc.sin6_port = htons(0);
-    memcpy(&sin6_loc.sin6_addr, loc_inner, sizeof(sin6_loc.sin6_addr));
-    
-    memset(&sin6_rmt, 0, sizeof(sin6_rmt));
-    sin6_rmt.sin6_len = sizeof(sin6_rmt);
-    sin6_rmt.sin6_family = AF_INET6;
-    sin6_rmt.sin6_port = htons(0);
-    memcpy(&sin6_rmt.sin6_addr, rmt_inner, sizeof(sin6_rmt.sin6_addr));
-    
-    int setup = which != kmDNSTunnelPolicyTeardown;
-    
-    if (0 != (err = generateTunnelPolicy(which, type, 1,
-                                         rmt_outer, rmt_port,
-                                         loc_outer, loc_port,
-                                         rmt_outer6, loc_outer6,
-                                         &policy, &len)))
-        goto fin;
-    
-    if (0 != (err = sendPolicy(s, setup,
-                               (struct sockaddr *)&sin6_rmt, rmt_bits,
-                               (struct sockaddr *)&sin6_loc, loc_bits,
-                               policy, len)))
-        goto fin;
-    
-    if (NULL != policy)
-    {
-        free(policy);
-        policy = NULL;
-    }
-    
-    if (0 != (err = generateTunnelPolicy(which, type, 0,
-                                         loc_outer, loc_port,
-                                         rmt_outer, rmt_port,
-                                         loc_outer6, rmt_outer6,
-                                         &policy, &len)))
-        goto fin;
-    if (0 != (err = sendPolicy(s, setup,
-                               (struct sockaddr *)&sin6_loc, loc_bits,
-                               (struct sockaddr *)&sin6_rmt, rmt_bits,
-                               policy, len)))
-        goto fin;
-    
-    if (which == kmDNSTunnelPolicyTeardown)
-    {
-        if (rmt_port)       // Outer tunnel is IPv4
-        {
-            if (loc_outer && rmt_outer)
-            {
-                struct sockaddr_in sin_loc;
-                struct sockaddr_in sin_rmt;
-                memset(&sin_loc, 0, sizeof(sin_loc));
-                sin_loc.sin_len = sizeof(sin_loc);
-                sin_loc.sin_family = AF_INET;
-                memcpy(&sin_loc.sin_addr, loc_outer, sizeof(sin_loc.sin_addr));
-                
-                memset(&sin_rmt, 0, sizeof(sin_rmt));
-                sin_rmt.sin_len = sizeof(sin_rmt);
-                sin_rmt.sin_family = AF_INET;
-                memcpy(&sin_rmt.sin_addr, rmt_outer, sizeof(sin_rmt.sin_addr));
-                if (0 != (err = removeSA(s, (struct sockaddr *)&sin_loc, (struct sockaddr *)&sin_rmt)))
-                    goto fin;
-            }
-        }
-        else
-        {
-            if (loc_outer6 && rmt_outer6)
-            {
-                struct sockaddr_in6 sin6_lo;
-                struct sockaddr_in6 sin6_rm;
-                
-                memset(&sin6_lo, 0, sizeof(sin6_lo));
-                sin6_lo.sin6_len = sizeof(sin6_lo);
-                sin6_lo.sin6_family = AF_INET6;
-                memcpy(&sin6_lo.sin6_addr, loc_outer6, sizeof(sin6_lo.sin6_addr));
-                
-                memset(&sin6_rm, 0, sizeof(sin6_rm));
-                sin6_rm.sin6_len = sizeof(sin6_rm);
-                sin6_rm.sin6_family = AF_INET6;
-                memcpy(&sin6_rm.sin6_addr, rmt_outer6, sizeof(sin6_rm.sin6_addr));
-                if (0 != (err = removeSA(s, (struct sockaddr *)&sin6_lo, (struct sockaddr *)&sin6_rm)))
-                    goto fin;
-            }
-        }
-    }
-    
-    os_log_debug(log_handle,"succeeded");
-    
-fin:
-    if (s >= 0)
-        pfkey_close(s);
-    if (NULL != policy)
-        free(policy);
-    return err;
-}
-
-#endif /* ndef MDNS_NO_IPSEC */
-
-int HelperAutoTunnelSetKeys(int replacedelete, const v6addr_t loc_inner, const v6addr_t loc_outer6, uint16_t loc_port, const v6addr_t rmt_inner,
-                            const v6addr_t rmt_outer6, uint16_t rmt_port, const char *id, int *err)
-{
-#ifndef MDNS_NO_IPSEC
-    static const char config[] =
-    "%s"
-    "remote %s [%u] {\n"
-    "  disconnect_on_idle idle_timeout 600 idle_direction idle_outbound;\n"
-    "  exchange_mode aggressive;\n"
-    "  doi ipsec_doi;\n"
-    "  situation identity_only;\n"
-    "  verify_identifier off;\n"
-    "  generate_policy on;\n"
-    "  my_identifier user_fqdn \"%s\";\n"
-    "  shared_secret keychain \"%s\";\n"
-    "  nonce_size 16;\n"
-    "  lifetime time 15 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 sha256;\n"
-    "    authentication_method pre_shared_key;\n"
-    "    dh_group 2;\n"
-    "    lifetime time 15 min;\n"
-    "  }\n"
-    "  proposal {\n"
-    "    encryption_algorithm aes;\n"
-    "    hash_algorithm sha1;\n"
-    "    authentication_method pre_shared_key;\n"
-    "    dh_group 2;\n"
-    "    lifetime time 15 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_sha256,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_sha256,hmac_sha1;\n"
-    "  compression_algorithm deflate;\n"
-    "}\n";
-    char path[PATH_MAX] = "";
-    char li[INET6_ADDRSTRLEN], lo[INET_ADDRSTRLEN], lo6[INET6_ADDRSTRLEN],
-    ri[INET6_ADDRSTRLEN], ro[INET_ADDRSTRLEN], ro6[INET6_ADDRSTRLEN];
-    FILE *fp = NULL;
-    int fd = -1;
-    char tmp_path[PATH_MAX] = "";
-    v4addr_t loc_outer, rmt_outer;
-    
-    os_log_debug(log_handle,"HelperAutoTunnelSetKeys: entry");
-    *err = kHelperErr_NoErr;
-
-    char buf1[INET6_ADDRSTRLEN];
-    char buf2[INET6_ADDRSTRLEN];
-    char buf3[INET6_ADDRSTRLEN];
-    char buf4[INET6_ADDRSTRLEN];
-    
-    buf1[0] = 0;
-    buf2[0] = 0;
-    buf3[0] = 0;
-    buf4[0] = 0;
-    
-    inet_ntop(AF_INET6, loc_inner,  buf1, sizeof(buf1));
-    inet_ntop(AF_INET6, loc_outer6, buf2, sizeof(buf2));
-    inet_ntop(AF_INET6, rmt_inner,  buf3, sizeof(buf3));
-    inet_ntop(AF_INET6, rmt_outer6, buf4, sizeof(buf4));
-    
-    os_log_info(log_handle, "HelperAutoTunnelSetKeys: Parameters are local_inner is %s, local_outer is %s, remote_inner is %s, remote_outer is %s id is %s",
-                     buf1, buf2, buf3, buf4, id);
-    
-    switch ((enum mDNSAutoTunnelSetKeysReplaceDelete)replacedelete)
-    {
-        case kmDNSAutoTunnelSetKeysReplace:
-        case kmDNSAutoTunnelSetKeysDelete:
-            break;
-        default:
-            *err = kHelperErr_InvalidTunnelSetKeysOperation;
-            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;
-    
-    os_log_debug(log_handle, "loc_inner=%s rmt_inner=%s", li, ri);
-    
-    if (!rmt_port)
-    {
-        loc_outer[0] = loc_outer[1] = loc_outer[2] = loc_outer[3] = 0;
-        rmt_outer[0] = rmt_outer[1] = rmt_outer[2] = rmt_outer[3] = 0;
-        
-        if (0 != (*err = v6addr_to_string(loc_outer6, lo6, sizeof(lo6))))
-            goto fin;
-        if (0 != (*err = v6addr_to_string(rmt_outer6, ro6, sizeof(ro6))))
-            goto fin;
-        
-        os_log_debug(log_handle, "IPv6 outer tunnel: loc_outer6=%s rmt_outer6=%s", lo6, ro6);
-        
-        if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.conf", GetRacoonConfigDir(), ro6))
-        {
-            *err = kHelperErr_ResultTooLarge;
-            goto fin;
-        }
-    }
-    else
-    {
-        loc_outer[0] = loc_outer6[0];
-        loc_outer[1] = loc_outer6[1];
-        loc_outer[2] = loc_outer6[2];
-        loc_outer[3] = loc_outer6[3];
-        
-        rmt_outer[0] = rmt_outer6[0];
-        rmt_outer[1] = rmt_outer6[1];
-        rmt_outer[2] = rmt_outer6[2];
-        rmt_outer[3] = rmt_outer6[3];
-        
-        if (0 != (*err = v4addr_to_string(loc_outer, lo, sizeof(lo))))
-            goto fin;
-        if (0 != (*err = v4addr_to_string(rmt_outer, ro, sizeof(ro))))
-            goto fin;
-        
-        os_log_debug(log_handle, "IPv4 outer tunnel: loc_outer=%s loc_port=%u rmt_outer=%s rmt_port=%u",
-                    lo, loc_port, ro, rmt_port);
-        
-        if ((int)sizeof(path) <= snprintf(path, sizeof(path), "%s%s.%u.conf", GetRacoonConfigDir(), ro, rmt_port))
-        {
-            *err = kHelperErr_ResultTooLarge;
-            goto fin;
-        }
-    }
-    
-    if (kmDNSAutoTunnelSetKeysReplace == replacedelete)
-    {
-        if (0 > ensureExistenceOfRacoonConfigDir(GetRacoonConfigDir()))
-        {
-            *err = kHelperErr_RacoonConfigCreationFailed;
-            goto fin;
-        }
-        if ((int)sizeof(tmp_path) <=
-            snprintf(tmp_path, sizeof(tmp_path), "%s.XXXXXX", path))
-        {
-            *err = kHelperErr_ResultTooLarge;
-            goto fin;
-        }
-        if (0 > (fd = mkstemp(tmp_path)))
-        {
-            os_log(log_handle, "mkstemp \"%s\" failed: %s", tmp_path, strerror(errno));
-            *err = kHelperErr_RacoonConfigCreationFailed;
-            goto fin;
-        }
-        if (NULL == (fp = fdopen(fd, "w")))
-        {
-            os_log(log_handle, "fdopen: %s", strerror(errno));
-            *err = kHelperErr_RacoonConfigCreationFailed;
-            goto fin;
-        }
-        
-        fd = -1;
-        fprintf(fp, config, configHeader, (!rmt_port ? ro6 : ro), rmt_port, id, id, ri, li, li, ri);
-        fclose(fp);
-        fp = NULL;
-        
-        if (0 > rename(tmp_path, path))
-        {
-            os_log(log_handle, "rename \"%s\" \"%s\" failed: %s", tmp_path, path, strerror(errno));
-            *err = kHelperErr_RacoonConfigCreationFailed;
-            goto fin;
-        }
-    }
-    else
-    {
-        if (0 != unlink(path))
-            os_log_debug(log_handle, "unlink \"%s\" failed: %s", path, strerror(errno));
-    }
-    
-    if (0 != (*err = doTunnelPolicy(kmDNSTunnelPolicyTeardown, kmDNSNoTunnel,
-                                    loc_inner, kWholeV6Mask, loc_outer, loc_port,
-                                    rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
-        goto fin;
-    if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
-        0 != (*err = doTunnelPolicy(kmDNSTunnelPolicySetup, (!rmt_port ? kmDNSIPv6IPv6Tunnel : kmDNSIPv6IPv4Tunnel),
-                                    loc_inner, kWholeV6Mask, loc_outer, loc_port,
-                                    rmt_inner, kWholeV6Mask, rmt_outer, rmt_port, loc_outer6, rmt_outer6)))
-        goto fin;
-    
-    if (0 != (*err = teardownTunnelRoute(rmt_inner)))
-        goto fin;
-    
-    if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
-        0 != (*err = setupTunnelRoute(loc_inner, rmt_inner)))
-        goto fin;
-    
-    if (kmDNSAutoTunnelSetKeysReplace == replacedelete &&
-        0 != (*err = kickRacoon()))
-        goto fin;
-    
-    os_log_debug(log_handle, "succeeded");
-    
-fin:
-    if (NULL != fp)
-        fclose(fp);
-    if (0 <= fd)
-        close(fd);
-    unlink(tmp_path);
-#else
-    (void)replacedelete; (void)loc_inner; (void)loc_outer6; (void)loc_port; (void)rmt_inner;
-    (void)rmt_outer6; (void)rmt_port; (void)id;
-    
-    *err = kHelperErr_IPsecDisabled;
-#endif /* MDNS_NO_IPSEC */
-    update_idle_timer();
-    return KERN_SUCCESS;
-}
-
-
-
-
index eedf7380e27f2ae6559856c5bdf1fc35b415641f..3133f91698fd3eaff3da8a22bd63b5decd9f5f99 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2007-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2019 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.
@@ -49,8 +49,6 @@ typedef enum
     send_keepalive = 8,
     retreive_tcpinfo = 9,
     keychain_getsecrets = 10,
-    autotunnel_setkeys = 11,
-    request_other,
 } HelperModes;
 
 typedef enum
@@ -81,6 +79,7 @@ typedef enum
     kHelperErr_RouteAdditionFailed = -17,
     kHelperErr_RacoonStartFailed = -18,
     kHelperErr_RacoonNotificationFailed = -19,
+    kHelperErr_ParamErr = -20,
 } HelperErrorCodes;
 
 
@@ -96,13 +95,6 @@ enum mDNSUpDown
     kmDNSDown
 };
 
-enum mDNSAutoTunnelSetKeysReplaceDelete
-{
-    kmDNSAutoTunnelSetKeysReplace = 1,
-    kmDNSAutoTunnelSetKeysDelete
-};
-
-
 // helper parses the system keychain and returns the information to mDNSResponder.
 // It returns four attributes. Attributes are defined after how they show up in
 // keychain access utility (the actual attribute name to retrieve these are different).
@@ -128,9 +120,6 @@ extern int  mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_
 extern void mDNSNotify(const char *title, const char *msg);     // Both strings are UTF-8 text
 extern void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new);
 extern int  mDNSKeychainGetSecrets(CFArrayRef *secrets);
-extern int  mDNSAutoTunnelSetKeys(int replacedelete, v6addr_t local_inner,
-                                  v6addr_t local_outer, short local_port, v6addr_t remote_inner,
-                                  v6addr_t remote_outer, short remote_port, const char *const prefix, const domainname *const fqdn);
 extern void mDNSSendWakeupPacket(unsigned ifid, char *eth_addr, char *ip_addr, int iteration);
 extern void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray);
 extern void mDNSSendKeepalive(const v6addr_t sadd, const v6addr_t dadd, uint16_t lport, uint16_t rport, unsigned seq, unsigned ack, uint16_t win);
diff --git a/mDNSMacOSX/ipsec_strerror.h b/mDNSMacOSX/ipsec_strerror.h
deleted file mode 100644 (file)
index b15fc28..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2015 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.
- */
-
-/*     $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
deleted file mode 100644 (file)
index 24f1b08..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2015 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.
- */
-
-/*     $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 126edd03cb9ed1206c30352c586a9b0dfc9007f5..2c7ee9519bda7e81cf1dac578d2690c5f0008202 100644 (file)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
- * Copyright (c) 2002-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
 #if TARGET_OS_IPHONE
 #include <MobileWiFi/WiFiManagerClient.h> // For WiFiManagerClientRef etc, declarations.
 #include <dlfcn.h>
-#include <os/variant_private.h>           // For os_variant_has_internal_diagnostics().
 #endif // TARGET_OS_IPHONE
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
+#include "system_utilities.h"               // For os_variant_has_internal_diagnostics().
+#endif
+
 // Include definition of opaque_presence_indication for KEV_DL_NODE_PRESENCE handling logic.
 #include <Kernel/IOKit/apple80211/apple80211_var.h>
 
-#if MDNSRESPONDER_BTMM_SUPPORT
-#include <AWACS.h>
-#endif
-
 #if APPLE_OSX_mDNSResponder
 #include <ne_session.h> // for ne_session_set_socket_attributes()
 #endif
 
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
 #include <IOKit/platform/IOPlatformSupportPrivate.h>
-#endif // APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#endif
 
 #ifdef UNIT_TEST
 #include "unittest.h"
@@ -153,10 +152,6 @@ static CFStringRef NetworkChangedKey_DNS;
 static CFStringRef NetworkChangedKey_StateInterfacePrefix;
 static CFStringRef NetworkChangedKey_DynamicDNS       = CFSTR("Setup:/Network/DynamicDNS");
 static CFStringRef NetworkChangedKey_PowerSettings    = CFSTR("State:/IOKit/PowerManagement/CurrentSettings");
-#if MDNSRESPONDER_BTMM_SUPPORT
-static CFStringRef NetworkChangedKey_BackToMyMac      = CFSTR("Setup:/Network/BackToMyMac");
-static CFStringRef NetworkChangedKey_BTMMConnectivity = CFSTR("State:/Network/Connectivity");
-#endif
 
 static char HINFO_HWstring_buffer[32];
 static char *HINFO_HWstring = "Device";
@@ -166,25 +161,22 @@ mDNSexport int WatchDogReportingThreshold = 250;
 
 dispatch_queue_t SSLqueue;
 
-#if TARGET_OS_EMBEDDED
-#define kmDNSResponderManagedPrefsID CFSTR("/Library/Managed Preferences/mobile/com.apple.mDNSResponder.plist")
-#endif
-
 #if APPLE_OSX_mDNSResponder
 static mDNSu8 SPMetricPortability   = 99;
 static mDNSu8 SPMetricMarginalPower = 99;
 static mDNSu8 SPMetricTotalPower    = 99;
 static mDNSu8 SPMetricFeatures      = 1; /* The current version supports TCP Keep Alive Feature */
-mDNSexport domainname ActiveDirectoryPrimaryDomain;
-mDNSexport int ActiveDirectoryPrimaryDomainLabelCount;
-mDNSexport mDNSAddr ActiveDirectoryPrimaryDomainServer;
 #endif // APPLE_OSX_mDNSResponder
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+domainname ActiveDirectoryPrimaryDomain;
+static int ActiveDirectoryPrimaryDomainLabelCount;
+static mDNSAddr ActiveDirectoryPrimaryDomainServer;
+#endif
+
 // Don't send triggers too often. We arbitrarily limit it to three minutes.
 #define DNS_TRIGGER_INTERVAL (180 * mDNSPlatformOneSecond)
 
-// Used by AutoTunnel
-const char btmmprefix[] = "btmmdns:";
 const char dnsprefix[] = "dns:";
 
 // String Array used to write list of private domains to Dynamic Store
@@ -205,13 +197,15 @@ static CFArrayRef privateDnsArray = NULL;
 // 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.
 
-#if BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
 #define MulticastInterface(i) ((i)->m->BonjourEnabled && ((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
 #else
 #define MulticastInterface(i) (((i)->ifa_flags & IFF_MULTICAST) && !((i)->ifa_flags & IFF_POINTOPOINT))
 #endif
 #define SPSInterface(i)       ((i)->ifinfo.McastTxRx && !((i)->ifa_flags & IFF_LOOPBACK) && !(i)->D2DInterface)
 
+mDNSlocal void SetNetworkChanged(mDNSs32 delay);
+
 mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg)  // Both strings are UTF-8 text
 {
     // Unless ForceAlerts is defined, we only show these bug report alerts on machines that have a 17.x.x.x address
@@ -250,7 +244,7 @@ mDNSexport void NotifyOfElusiveBug(const char *title, const char *msg)  // Both
 }
 
 // Write a syslog message and display an alert, then if ForceAlerts is set, generate a stack trace
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING >= 1
+#if MDNS_MALLOC_DEBUGGING >= 1
 mDNSexport void LogMemCorruption(const char *format, ...)
 {
     char buffer[512];
@@ -286,26 +280,11 @@ mDNSexport void LogFatalError(const char *format, ...)
 // Returns true if it is an AppleTV based hardware running iOS, false otherwise
 mDNSlocal mDNSBool IsAppleTV(void)
 {
-#if TARGET_OS_EMBEDDED
-    static mDNSBool sInitialized = mDNSfalse;
-    static mDNSBool sIsAppleTV   = mDNSfalse;
-    CFStringRef deviceClass = NULL;
-
-    if(!sInitialized)
-    {
-        deviceClass = (CFStringRef) MGCopyAnswer(kMGQDeviceClass, NULL);
-        if(deviceClass)
-        {
-            if(CFEqual(deviceClass, kMGDeviceClassAppleTV))
-                sIsAppleTV = mDNStrue;
-            CFRelease(deviceClass);
-        }
-        sInitialized = mDNStrue;
-    }
-    return(sIsAppleTV);
+#if TARGET_OS_TV
+    return mDNStrue;
 #else 
     return mDNSfalse;
-#endif // TARGET_OS_EMBEDDED
+#endif
 }
 
 mDNSlocal struct ifaddrs *myGetIfAddrs(int refresh)
@@ -494,6 +473,102 @@ mDNSexport NetworkInterfaceInfoOSX *IfindexToInterfaceInfoOSX(mDNSInterfaceID if
     return mDNSNULL;
 }
 
+mDNSexport mdns_interface_monitor_t GetInterfaceMonitorForIndex(uint32_t ifIndex)
+{
+    mDNS *const m = &mDNSStorage;
+
+    // We assume that interface should always be real interface, and should never be 0.
+    if (ifIndex == 0) return NULL;
+
+    if (!m->p->InterfaceMonitors)
+    {
+        m->p->InterfaceMonitors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
+        if (!m->p->InterfaceMonitors)
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Failed to create InterfaceMonitors array");
+            return NULL;
+        }
+    }
+
+    // Search for interface monitor given the interface index.
+    mdns_interface_monitor_t monitor;
+    for (CFIndex i = 0, n = CFArrayGetCount(m->p->InterfaceMonitors); i < n; i++)
+    {
+        monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, i);
+        if (mdns_interface_monitor_get_interface_index(monitor) == ifIndex) return monitor;
+    }
+
+    // If we come here, it means the interface is a new interface that needs to be monitored.
+    monitor = mdns_interface_monitor_create(ifIndex);
+    if (!monitor)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Failed to create an interface monitor for index %u", ifIndex);
+        return NULL;
+    }
+    CFArrayAppendValue(m->p->InterfaceMonitors, monitor);
+
+    // Put the monitor into serial queue.
+    mdns_interface_monitor_set_queue(monitor, dispatch_get_main_queue());
+
+    // When the interface configuration is changed, this block will be called.
+    mdns_interface_monitor_set_update_handler(monitor,
+    ^(mdns_interface_flags_t changeFlags)
+    {
+        const mdns_interface_flags_t relevantFlags =
+            mdns_interface_flag_expensive   |
+            mdns_interface_flag_constrained |
+            mdns_interface_flag_clat46;
+        if ((changeFlags & relevantFlags) == 0) return;
+
+        KQueueLock();
+        const CFRange range = CFRangeMake(0, CFArrayGetCount(m->p->InterfaceMonitors));
+        if (CFArrayContainsValue(m->p->InterfaceMonitors, range, monitor))
+        {
+            m->p->if_interface_changed = mDNStrue;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "Monitored interface changed: %@", monitor);
+#endif
+            // Let mDNSResponder update its network configuration.
+            mDNS_Lock(m);
+            SetNetworkChanged((mDNSPlatformOneSecond + 39) / 40);   // 25 ms delay
+            mDNS_Unlock(m);
+        }
+        KQueueUnlock("interface monitor update handler");
+    });
+
+    mdns_interface_monitor_set_event_handler(monitor,
+    ^(mdns_event_t event, OSStatus error)
+    {
+        switch (event)
+        {
+            case mdns_event_invalidated:
+                mdns_release(monitor);
+                break;
+
+            case mdns_event_error:
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR, "Interface monitor for index %u error: %ld",
+                    mdns_interface_monitor_get_interface_index(monitor), (long) error);
+                KQueueLock();
+                if (m->p->InterfaceMonitors)
+                {
+                    const CFRange range = CFRangeMake(0, CFArrayGetCount(m->p->InterfaceMonitors));
+                    const CFIndex i = CFArrayGetFirstIndexOfValue(m->p->InterfaceMonitors, range, monitor);
+                    if (i >= 0) CFArrayRemoveValueAtIndex(m->p->InterfaceMonitors, i);
+                }
+                KQueueUnlock("interface monitor event handler");
+                mdns_interface_monitor_invalidate(monitor);
+                break;
+
+            default:
+                break;
+        }
+    });
+    mdns_interface_monitor_activate(monitor);
+
+    return monitor;
+}
+
 mDNSexport mDNSInterfaceID mDNSPlatformInterfaceIDfromInterfaceIndex(mDNS *const m, mDNSu32 ifindex)
 {
     (void) m;
@@ -522,7 +597,6 @@ mDNSexport mDNSu32 mDNSPlatformInterfaceIndexfromInterfaceID(mDNS *const m, mDNS
     NetworkInterfaceInfoOSX *i;
     if (id == mDNSInterface_Any      ) return(0);
     if (id == mDNSInterface_LocalOnly) return(kDNSServiceInterfaceIndexLocalOnly);
-    if (id == mDNSInterface_Unicast  ) return(0);
     if (id == mDNSInterface_P2P      ) return(kDNSServiceInterfaceIndexP2P);
     if (id == mDNSInterface_BLE      ) return(kDNSServiceInterfaceIndexBLE);
 
@@ -597,7 +671,6 @@ mDNSlocal void setTrafficClass(int socketfd, mDNSBool useBackgroundTrafficClass)
 }
 
 #ifdef UNIT_TEST
-// Run the unit test main
 UNITTEST_SETSOCKOPT
 #else
 mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType, mDNSAddr_Type addrType)
@@ -610,7 +683,7 @@ mDNSlocal int mDNSPlatformGetSocktFd(void *sockCxt, mDNSTransport_Type transType
     else if (transType == mDNSTransport_TCP)
     {
         TCPSocket* sock = (TCPSocket*) sockCxt;
-        return (addrType == mDNSAddrType_IPv4) ? sock->ss.sktv4 : sock->ss.sktv6;
+        return sock->fd;
     }
     else
     {
@@ -663,6 +736,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
     int s = -1, err;
     mStatus result = mStatus_NoError;
     int sendto_errno;
+    const DNSMessage *const dns_msg = msg;
 
     if (InterfaceID)
     {
@@ -699,7 +773,9 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
             if (displayed < 1000)
             {
                 displayed++;
-                LogInfo("IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets");
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[Q%u] IP_BOUND_IF socket option not defined -- cannot specify interface for unicast packets",
+                          mDNSVal16(dns_msg->h.id));
             }
         #endif
         }
@@ -711,15 +787,28 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
             // a different machine that does not support it
             if (err < 0)
             {
-                if (errno != ENOPROTOOPT) LogInfo("mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d", errno);
+                if (errno != ENOPROTOOPT)
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[Q%u] mDNSPlatformSendUDP: setsockopt: IP_MUTLTICAST_IFINDEX returned %d",
+                              mDNSVal16(dns_msg->h.id), errno);
+                }
                 err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
                 if (err < 0 && !m->NetworkChanged)
-                    LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[Q%u] setsockopt - IP_MULTICAST_IF error " PRI_IPv4_ADDR " %d errno %d (" PUB_S ")",
+                              mDNSVal16(dns_msg->h.id), &info->ifa_v4addr, err, errno, strerror(errno));
+                }
             }
         #else
             err = setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &info->ifa_v4addr, sizeof(info->ifa_v4addr));
             if (err < 0 && !m->NetworkChanged)
-                LogMsg("setsockopt - IP_MULTICAST_IF error %.4a %d errno %d (%s)", &info->ifa_v4addr, err, errno, strerror(errno));
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                          "[Q%u] setsockopt - IP_MULTICAST_IF error " PRI_IPv4_ADDR " %d errno %d (" PUB_S ")",
+                          mDNSVal16(dns_msg->h.id), &info->ifa_v4addr, err, errno, strerror(errno));
+            }
         #endif
         }
     }
@@ -741,9 +830,17 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
                 const int setsockopt_errno = errno;
                 char name[IFNAMSIZ];
                 if (if_indextoname(info->scope_id, name) != NULL)
-                    LogMsg("setsockopt - IPV6_MULTICAST_IF error %d errno %d (%s)", err, setsockopt_errno, strerror(setsockopt_errno));
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[Q%u] setsockopt - IPV6_MULTICAST_IF error %d errno %d (" PUB_S ")",
+                              mDNSVal16(dns_msg->h.id), err, setsockopt_errno, strerror(setsockopt_errno));
+                }
                 else
-                    LogInfo("setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface", info->scope_id);
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[Q%u] setsockopt - IPV6_MUTLICAST_IF scopeid %d, not a valid interface",
+                              mDNSVal16(dns_msg->h.id), info->scope_id);
+                }
             }
         }
 #ifdef IPV6_BOUND_IF
@@ -752,26 +849,36 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
             if (!mDNSAddrIsDNSMulticast(dst))
             {
                 if (info->scope_id == 0)
-                    LogInfo("IPV6_BOUND_IF socket option not set -- info %p (%s) scope_id is zero", info, ifa_name);
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                              "[Q%u] IPV6_BOUND_IF socket option not set -- info %p (" PUB_S ") scope_id is zero",
+                              mDNSVal16(dns_msg->h.id), info, ifa_name);
+                }
                 else
+                {
                     setsockopt(s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+                }
             }
         }
 #endif
     }
-
     else
     {
-        LogFatalError("mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT,
+                  "[Q%u] mDNSPlatformSendUDP: dst is not an IPv4 or IPv6 address!", mDNSVal16(dns_msg->h.id));
         return mStatus_BadParamErr;
     }
 
     if (s >= 0)
+    {
         verbosedebugf("mDNSPlatformSendUDP: sending on InterfaceID %p %5s/%ld to %#a:%d skt %d",
                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s);
+    }
     else
+    {
         verbosedebugf("mDNSPlatformSendUDP: NOT sending on InterfaceID %p %5s/%ld (socket of this type not available)",
                       InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort));
+    }
 
     // Note: When sending, mDNSCore may often ask us to send both a v4 multicast packet and then a v6 multicast packet
     // If we don't have the corresponding type of socket available, then return mStatus_Invalid
@@ -791,8 +898,9 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
     if (err < 0)
     {
         static int MessageCount = 0;
-        LogInfo("mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
-                s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                  "[Q%u] mDNSPlatformSendUDP -> sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u",
+                  mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
         if (!mDNSAddressIsAllDNSLinkGroup(dst))
         {
             if ((sendto_errno == EHOSTUNREACH) || (sendto_errno == ENETUNREACH)) return(mStatus_HostUnreachErr);
@@ -805,17 +913,26 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
         // Don't report EADDRNOTAVAIL ("Can't assign requested address") if we're in the middle of a network configuration change
         if (sendto_errno == EADDRNOTAVAIL && m->NetworkChanged) return(mStatus_TransientErr);
         if (sendto_errno == EHOSTUNREACH || sendto_errno == EADDRNOTAVAIL || sendto_errno == ENETDOWN)
-            LogInfo("mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu",
-                    s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                      "[Q%u] mDNSPlatformSendUDP sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u",
+                      mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow));
+        }
         else
         {
             MessageCount++;
-            if (MessageCount < 50)  // Cap and ensure NO spamming of LogMsgs
-                LogMsg("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
-                       s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
-            else  // If logging is enabled, remove the cap and log aggressively
-                LogInfo("mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p %5s/%d to %#a:%d skt %d error %d errno %d (%s) %lu MessageCount is %d",
-                        s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
+            if (MessageCount < 50) // Cap and ensure NO spamming of LogMsgs
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                          "[Q%u] mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u MessageCount is %d",
+                          mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
+            }
+            else // If logging is enabled, remove the cap and log aggressively
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[Q%u] mDNSPlatformSendUDP: sendto(%d) failed to send packet on InterfaceID %p " PUB_S "/%d to " PRI_IP_ADDR ":%d skt %d error %d errno %d (" PUB_S ") %u MessageCount is %d",
+                          mDNSVal16(dns_msg->h.id), s, InterfaceID, ifa_name, dst->type, dst, mDNSVal16(dstPort), s, err, sendto_errno, strerror(sendto_errno), (mDNSu32)(m->timenow), MessageCount);
+            }
         }
 
         result = mStatus_UnknownErr;
@@ -824,7 +941,7 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
     return(result);
 }
 
-mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
+mDNSexport ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
                              struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char ifname[IF_NAMESIZE], mDNSu8 *ttl)
 {
     static unsigned int numLogMessages = 0;
@@ -852,22 +969,20 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
         if (errno != EWOULDBLOCK && numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned error %d errno %d", s, n, errno);
         return(-1);
     }
+    if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
+    {
+        if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %d msg.msg_controllen %d < sizeof(struct cmsghdr) %lu, errno %d",
+                                           s, n, msg.msg_controllen, sizeof(struct cmsghdr), errno);
+        return(-1);
+    }
     if (msg.msg_flags & MSG_CTRUNC)
     {
         if (numLogMessages++ < 100) LogMsg("mDNSMacOSX.c: recvmsg(%d) msg.msg_flags & MSG_CTRUNC", s);
         return(-1);
     }
+
     *fromlen = msg.msg_namelen;
 
-    if (msg.msg_controllen < (int)sizeof(struct cmsghdr))
-    {
-        if (numLogMessages++ < 100)
-        {
-            LogMsg("mDNSMacOSX.c: recvmsg(%d) returned %ld msg.msg_controllen %lu < sizeof(struct cmsghdr) %lu",
-                s, (long)n, (unsigned long)msg.msg_controllen, (unsigned long)sizeof(struct cmsghdr));
-        }
-        goto exit;
-    }
     // Parse each option out of the ancillary data.
     for (cmPtr = CMSG_FIRSTHDR(&msg); cmPtr; cmPtr = CMSG_NXTHDR(&msg, cmPtr))
     {
@@ -901,11 +1016,10 @@ mDNSlocal ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
             *ttl = *(int*)CMSG_DATA(cmPtr);
     }
 
-exit:
     return(n);
 }
 
-// What is this for, and why does it use xor instead of a simple quality check? -- SC
+// What is this for, and why does it use xor instead of a simple equality check? -- SC
 mDNSlocal mDNSInterfaceID FindMyInterface(const mDNSAddr *addr)
 {
     NetworkInterfaceInfo *intf;
@@ -947,7 +1061,7 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
 {
     KQSocketSet *const ss = (KQSocketSet *)context;
     mDNS *const m = ss->m;
-    int err = 0, count = 0, closed = 0;
+    int err = 0, count = 0, closed = 0, recvfrom_errno = 0;
 
     if (filter != EVFILT_READ)
         LogMsg("myKQSocketCallBack: Why is filter %d not EVFILT_READ (%d)?", filter, EVFILT_READ);
@@ -983,7 +1097,11 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
         char packetifname[IF_NAMESIZE] = "";
         mDNSu8 ttl;
         err = myrecvfrom(s1, &m->imsg, sizeof(m->imsg), (struct sockaddr *)&from, &fromlen, &destAddr, packetifname, &ttl);
-        if (err < 0) break;
+        if (err < 0)
+        {
+            recvfrom_errno = errno;
+            break;
+        }
 
         if ((destAddr.type == mDNSAddrType_IPv4 && (destAddr.ip.v4.b[0] & 0xF0) == 0xE0) ||
             (destAddr.type == mDNSAddrType_IPv6 && (destAddr.ip.v6.b[0]         == 0xFF))) m->p->num_mcasts++;
@@ -1036,8 +1154,8 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
             InterfaceID = FindMyInterface(&destAddr);
         }
 
-//             LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
-//                     &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
+//      LogMsg("myKQSocketCallBack got packet from %#a to %#a on interface %#a/%s",
+//          &senderAddr, &destAddr, &ss->info->ifinfo.ip, ss->info->ifinfo.ifname);
 
         // mDNSCoreReceive may close the socket we're reading from.  We must break out of our
         // loop when that happens, or we may try to read from an invalid FD.  We do this by
@@ -1063,14 +1181,14 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
     // If a client application's sockets are marked as defunct
     // sockets we have delegated to it with SO_DELEGATED will also go defunct.
     // We get an ENOTCONN error for defunct sockets and should just close the socket in that case.
-    if (err < 0 && errno == ENOTCONN)
+    if (err < 0 && recvfrom_errno == ENOTCONN)
     {
         LogInfo("myKQSocketCallBack: ENOTCONN, closing socket");
         close(s1);
         return;
     }
 
-    if (err < 0 && (errno != EWOULDBLOCK || count == 0))
+    if (err < 0 && (recvfrom_errno != EWOULDBLOCK || count == 0))
     {
         // Something is busted here.
         // kqueue says there is a packet, but myrecvfrom says there is not.
@@ -1078,11 +1196,10 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
         // 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;
-        const int save_errno = errno;
         int so_error = -1;
         int so_nread = -1;
         int fionread = -1;
-        socklen_t solen = sizeof(int);
+        socklen_t solen;
         fd_set readfds;
         struct timeval timeout;
         int selectresult;
@@ -1091,15 +1208,17 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
         timeout.tv_sec  = 0;
         timeout.tv_usec = 0;
         selectresult = select(s1+1, &readfds, NULL, NULL, &timeout);
+        solen = (socklen_t)sizeof(so_error);
         if (getsockopt(s1, SOL_SOCKET, SO_ERROR, &so_error, &solen) == -1)
             LogMsg("myKQSocketCallBack getsockopt(SO_ERROR) error %d", errno);
+        solen = (socklen_t)sizeof(so_nread);
         if (getsockopt(s1, SOL_SOCKET, SO_NREAD, &so_nread, &solen) == -1)
             LogMsg("myKQSocketCallBack getsockopt(SO_NREAD) error %d", errno);
         if (ioctl(s1, FIONREAD, &fionread) == -1)
             LogMsg("myKQSocketCallBack ioctl(FIONREAD) error %d", errno);
         if (numLogMessages++ < 100)
             LogMsg("myKQSocketCallBack recvfrom skt %d error %d errno %d (%s) select %d (%spackets waiting) so_error %d so_nread %d fionread %d count %d",
-                   s1, err, save_errno, strerror(save_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
+                   s1, err, recvfrom_errno, strerror(recvfrom_errno), selectresult, FD_ISSET(s1, &readfds) ? "" : "*NO* ", so_error, so_nread, fionread, count);
         if (numLogMessages > 5)
             NotifyOfElusiveBug("Flaw in Kernel (select/recvfrom mismatch)",
                                "Congratulations, you've reproduced an elusive bug.\r"
@@ -1113,7 +1232,10 @@ mDNSexport void myKQSocketCallBack(int s1, short filter, void *context, mDNSBool
 mDNSlocal void doTcpSocketCallback(TCPSocket *sock)
 {
     mDNSBool c = !sock->connected;
-    sock->connected = mDNStrue;
+    if (!sock->connected && sock->err == mStatus_NoError)
+    {
+        sock->connected = mDNStrue;
+    }
     sock->callback(sock, sock->context, c, sock->err);
     // Note: the callback may call CloseConnection here, which frees the context structure!
 }
@@ -1181,14 +1303,14 @@ mDNSlocal OSStatus tlsSetupSock(TCPSocket *sock, SSLProtocolSide pside, SSLConne
 
     // We already checked for NULL in hostname and this should never happen. Hence, returning -1
     // (error not in OSStatus space) is okay.
-    if (!sock->hostname.c[0]) 
+    if (!sock->hostname || !sock->hostname->c[0]) 
     {
         LogMsg("ERROR: tlsSetupSock: hostname NULL"); 
         err = -1;
         goto fail;
     }
 
-    ConvertDomainNameToCString(&sock->hostname, domname_cstr);
+    ConvertDomainNameToCString(sock->hostname, domname_cstr);
     err = SSLSetPeerDomainName(sock->tlsContext, domname_cstr, strlen(domname_cstr));
     if (err) 
     { 
@@ -1275,7 +1397,7 @@ mDNSlocal void *doSSLHandshake(TCPSocket *sock)
     }
     else
     {
-        if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, sock->kqEntry);
+        if (sock->fd != -1) KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
         else LogMsg("doSSLHandshake: sock->fd is -1");
 
         if (err == errSSLWouldBlock)
@@ -1309,7 +1431,7 @@ mDNSlocal void spawnSSLHandshake(TCPSocket* sock)
 
     if (sock->handshake != handshake_required) LogMsg("spawnSSLHandshake: handshake status not required: %d", sock->handshake);
     sock->handshake = handshake_in_progress;
-    KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, sock->kqEntry);
+    KQueueSet(sock->fd, EV_DELETE, EVFILT_READ, &sock->kqEntry);
 
     // Dispatch it on a separate queue to help avoid blocking other threads/queues, and
     // to limit the number of threads used for SSLHandshake
@@ -1329,35 +1451,87 @@ mDNSlocal void tcpKQSocketCallback(__unused int fd, short filter, void *context,
     //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);
+    {
+        // sock->connected gets set by doTcpSocketCallback(), which may be called from here, or may be called
+        // from the TLS connect code.   If we asked for a writability test, we are connecting
+        // (sock->connected == mDNSFalse).
+        if (sock->connected)
+        {
+            LogInfo("ERROR: TCPConnectCallback called with write event when socket is connected.");
+        }
+        else
+        {
+            int result = 0;
+            socklen_t len = (socklen_t)sizeof(result);
+            if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
+            {
+                LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
+                        sock->fd, errno, strerror(errno));
+                sock->err = mStatus_ConnFailed;
+            }
+            else
+            {
+                if (result != 0)
+                {
+                    sock->err = mStatus_ConnFailed;
+                    if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
+                    {
+                        LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+                                sock->fd, result, strerror(result));
+                    }
+                    else
+                    {
+                        LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+                               sock->fd, result, strerror(result));
+                    }
+                }
+            }
+        }
+        KQueueSet(sock->fd, EV_DELETE, EVFILT_WRITE, &sock->kqEntry);
 
+        // If we set the EVFILT_READ event in mDNSPlatformTCPConnect, it's possible to get a read event
+        // before the write event--apparently the socket is both readable and writable once that happens,
+        // even if the connect fails.   If we set it here, after we've gotten a successful connection, then
+        // we shouldn't run into that problem.
+        if (sock->err == mStatus_NoError &&
+            KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
+        {
+            // And of course if that fails, we can't use the connection even though we have it.
+            LogMsg("ERROR: tcpKQSocketCallback - KQueueSet failed");
+            sock->err = mStatus_TransientErr;
+        }
+    }
+    
     if (sock->flags & kTCPSocketFlags_UseTLS)
     {
 #ifndef NO_SECURITYFRAMEWORK
-        if (!sock->setup) 
-        { 
-            sock->setup = mDNStrue; 
-            sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
-            if (sock->err)
+        // Don't try to set up TLS if the connect failed.
+        if (sock->err == mStatus_NoError) {
+            if (!sock->setup) 
             {
-                LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
+                sock->setup = mDNStrue; 
+                sock->err = tlsSetupSock(sock, kSSLClientSide, kSSLStreamType);
+                if (sock->err)
+                {
+                    LogMsg("ERROR: tcpKQSocketCallback: tlsSetupSock failed with error code: %d", sock->err);
+                    return;
+                }
+            }
+            if (sock->handshake == handshake_required) 
+            { 
+                spawnSSLHandshake(sock); 
                 return;
             }
-        }
-        if (sock->handshake == handshake_required) 
-        { 
-            spawnSSLHandshake(sock); 
-            return;
-        }
-        else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
-        {
-            return;
-        }
-        else if (sock->handshake != handshake_completed)
-        {
-            if (!sock->err) 
-                sock->err = mStatus_UnknownErr;
-            LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
+            else if (sock->handshake == handshake_in_progress || sock->handshake == handshake_to_be_closed)
+            {
+                return;
+            }
+            else if (sock->handshake != handshake_completed)
+            {
+                if (!sock->err) 
+                    sock->err = mStatus_UnknownErr;
+                LogMsg("tcpKQSocketCallback called with unexpected SSLHandshake status: %d", sock->handshake);
+            }
         }
 #else  /* NO_SECURITYFRAMEWORK */ 
         sock->err = mStatus_UnsupportedErr;
@@ -1446,6 +1620,7 @@ mDNSexport void KQueueUnlock(const char const *task)
     (void)task; //unused
 }
 #else
+
 mDNSexport int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *const entryRef)
 {
     struct kevent new_event;
@@ -1466,7 +1641,10 @@ mDNSexport void KQueueUnlock(const char* task)
     mDNSs32 end = mDNSPlatformRawTime();
     (void)task;
     if (end - m->p->BigMutexStartTime >= WatchDogReportingThreshold)
-        LogInfo("WARNING: %s took %dms to complete", task, end - m->p->BigMutexStartTime);
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_WARNING,
+            "WARNING: " PUB_S " took %d ms to complete", task, end - m->p->BigMutexStartTime);
+    }
 
     pthread_mutex_unlock(&m->p->BigMutex);
 
@@ -1499,102 +1677,67 @@ mDNSexport void mDNSPlatformCloseFD(KQueueEntry *kq, int fd)
 #endif
 }
 
-mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, u_short sa_family, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
+mDNSlocal mStatus SetupTCPSocket(TCPSocket *sock, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
 {
-    KQSocketSet *cp = &sock->ss;
-    int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
-    KQueueEntry *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
-    const int on = 1;  // "on" for setsockopt
-    mStatus err;
+    int skt;
 
-    int skt = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
-    if (skt < 3) { if (errno != EAFNOSUPPORT) LogMsg("SetupTCPSocket: socket error %d errno %d (%s)", skt, errno, strerror(errno));return(skt); }
-
-    // for TCP sockets, the traffic class is set once and not changed
-    setTrafficClass(skt, useBackgroundTrafficClass);
-
-    if (sa_family == AF_INET)
+    skt = -1;
+    if (!mDNSPosixTCPSocketSetup(&skt, addrtype, port, &sock->port))
     {
-        // Bind it
-        struct sockaddr_in addr;
-        mDNSPlatformMemZero(&addr, sizeof(addr));
-        addr.sin_family = AF_INET;
-        addr.sin_port = port->NotAnInteger;
-        err = bind(skt, (struct sockaddr*) &addr, sizeof(addr));
-        if (err < 0) { LogMsg("ERROR: bind %s", strerror(errno)); close(skt); return err; }
-
-        // Receive interface identifiers
-        err = setsockopt(skt, IPPROTO_IP, IP_RECVIF, &on, sizeof(on));
-        if (err < 0) { LogMsg("setsockopt IP_RECVIF - %s", strerror(errno)); close(skt); return err; }
-
-        mDNSPlatformMemZero(&addr, sizeof(addr));
-        socklen_t len = sizeof(addr);
-        err = getsockname(skt, (struct sockaddr*) &addr, &len);
-        if (err < 0) { LogMsg("getsockname - %s", strerror(errno)); close(skt); return err; }
-
-        port->NotAnInteger = addr.sin_port;
+        if (skt != -1) close(skt);
+        return mStatus_UnknownErr;
     }
-    else
-    {
-        // Bind it
-        struct sockaddr_in6 addr6;
-        mDNSPlatformMemZero(&addr6, sizeof(addr6));
-        addr6.sin6_family = AF_INET6;
-        addr6.sin6_port = port->NotAnInteger;
-        err = bind(skt, (struct sockaddr*) &addr6, sizeof(addr6));
-        if (err < 0) { LogMsg("ERROR: bind6 %s", strerror(errno)); close(skt); return err; }
-
-        // We want to receive destination addresses and receive interface identifiers
-        err = setsockopt(skt, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on));
-        if (err < 0) { LogMsg("ERROR: setsockopt IPV6_RECVPKTINFO %s", strerror(errno)); close(skt); return err; }
-
-        mDNSPlatformMemZero(&addr6, sizeof(addr6));
-        socklen_t len = sizeof(addr6);
-        err = getsockname(skt, (struct sockaddr *) &addr6, &len);
-        if (err < 0) { LogMsg("getsockname6 - %s", strerror(errno)); close(skt); return err; }
-
-        port->NotAnInteger = addr6.sin6_port;
+            
+    // for TCP sockets, the traffic class is set once and not changed
+    setTrafficClass(skt, useBackgroundTrafficClass);
 
-    }
-    *s = skt;
-    k->KQcallback = tcpKQSocketCallback;
-    k->KQcontext  = sock;
-    k->KQtask     = "mDNSPlatformTCPSocket";
+    sock->fd = skt;
+    sock->kqEntry.KQcallback = tcpKQSocketCallback;
+    sock->kqEntry.KQcontext  = sock;
+    sock->kqEntry.KQtask     = "mDNSPlatformTCPSocket";
 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
-    k->readSource = mDNSNULL;
-    k->writeSource = mDNSNULL;
-    k->fdClosed = mDNSfalse;
+    sock->kqEntry.readSource = mDNSNULL;
+    sock->kqEntry.writeSource = mDNSNULL;
+    sock->kqEntry.fdClosed = mDNSfalse;
 #endif
     return mStatus_NoError;
 }
 
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *port, mDNSBool useBackgroundTrafficClass)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrtype, mDNSIPPort *port, domainname *hostname, mDNSBool useBackgroundTrafficClass)
 {
     mStatus err;
+    mDNSu32 lowWater = 16384;
+    size_t len = sizeof (TCPSocket);
+    if (hostname) {
+        len += sizeof (domainname);
+    }
 
-    TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPSocket", sizeof(TCPSocket));
+    TCPSocket *sock = (TCPSocket *) callocL("TCPSocket/mDNSPlatformTCPSocket", len);
     if (!sock) { LogMsg("mDNSPlatformTCPSocket: memory allocation failure"); return(mDNSNULL); }
 
-    mDNSPlatformMemZero(sock, sizeof(TCPSocket));
-
-    sock->ss.m     = &mDNSStorage;
-    sock->ss.sktv4 = -1;
-    sock->ss.sktv6 = -1;
-    err = SetupTCPSocket(sock, AF_INET, port, useBackgroundTrafficClass);
-
-    if (!err)
+    if (hostname)
     {
-        err = SetupTCPSocket(sock, AF_INET6, port, useBackgroundTrafficClass);
-        if (err) { mDNSPlatformCloseFD(&sock->ss.kqsv4, sock->ss.sktv4); sock->ss.sktv4 = -1; }
+        sock->hostname = (domainname *)(sock + 1); // Allocated together so can be freed together
+        debugf("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
+        AssignDomainName(sock->hostname, hostname);
     }
+
+    err = SetupTCPSocket(sock, addrtype, port, useBackgroundTrafficClass);
+
     if (err)
     {
         LogMsg("mDNSPlatformTCPSocket: socket error %d errno %d (%s)", sock->fd, errno, strerror(errno));
         freeL("TCPSocket/mDNSPlatformTCPSocket", sock);
         return(mDNSNULL);
     }
-    // sock->fd is used as the default fd  if the caller does not call mDNSPlatformTCPConnect
-    sock->fd                = sock->ss.sktv4;
+
+    if (setsockopt(sock->fd, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater) < 0)
+    {
+        LogMsg("mDNSPlatformTCPSocket: TCP_NOTSENT_LOWAT returned %d", errno);
+               mDNSPlatformTCPCloseConnection(sock);
+        return mDNSNULL;
+    }
+    
     sock->callback          = mDNSNULL;
     sock->flags             = flags;
     sock->context           = mDNSNULL;
@@ -1607,11 +1750,8 @@ mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort *po
     return sock;
 }
 
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
+mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID, TCPConnectionCallback callback, void *context)
 {
-    KQSocketSet *cp = &sock->ss;
-    int         *s        = (dst->type == mDNSAddrType_IPv4) ? &cp->sktv4 : &cp->sktv6;
-    KQueueEntry *k        = (dst->type == mDNSAddrType_IPv4) ? &cp->kqsv4 : &cp->kqsv6;
     mStatus err = mStatus_NoError;
     struct sockaddr_storage ss;
 
@@ -1622,8 +1762,6 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst,
     sock->handshake         = handshake_required;
     sock->err               = mStatus_NoError;
 
-    if (hostname) { debugf("mDNSPlatformTCPConnect: hostname %##s", hostname->c); AssignDomainName(&sock->hostname, hostname); }
-
     if (dst->type == mDNSAddrType_IPv4)
     {
         struct sockaddr_in *saddr = (struct sockaddr_in *)&ss;
@@ -1645,20 +1783,13 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst,
 
     // Watch for connect complete (write is ready)
     // EV_ONESHOT doesn't seem to work, so we add the filter with EV_ADD, and explicitly delete it in tcpKQSocketCallback using EV_DELETE
-    if (KQueueSet(*s, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, k))
-    {
-        LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
-        return errno;
-    }
-
-    // Watch for incoming data
-    if (KQueueSet(*s, EV_ADD, EVFILT_READ, k))
+    if (KQueueSet(sock->fd, EV_ADD /* | EV_ONESHOT */, EVFILT_WRITE, &sock->kqEntry))
     {
         LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
         return errno;
     }
 
-    if (fcntl(*s, F_SETFL, fcntl(*s, F_GETFL, 0) | O_NONBLOCK) < 0) // set non-blocking
+    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;
@@ -1668,14 +1799,14 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst,
     // on this interface
     //
     // Note: If we are in Active Directory domain, we may try TCP (if the response can't fit in
-    // UDP). mDNSInterface_Unicast indicates this case and not a valid interface.
-    if (InterfaceID && InterfaceID != mDNSInterface_Unicast)
+    // UDP).
+    if (InterfaceID)
     {
         NetworkInterfaceInfoOSX *info = IfindexToInterfaceInfoOSX(InterfaceID);
         if (dst->type == mDNSAddrType_IPv4)
         {
         #ifdef IP_BOUND_IF
-            if (info) setsockopt(*s, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+            if (info) setsockopt(sock->fd, IPPROTO_IP, IP_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
             else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
         #else
             (void)InterfaceID; // Unused
@@ -1685,7 +1816,7 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst,
         else
         {
         #ifdef IPV6_BOUND_IF
-            if (info) setsockopt(*s, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
+            if (info) setsockopt(sock->fd, IPPROTO_IPV6, IPV6_BOUND_IF, &info->scope_id, sizeof(info->scope_id));
             else { LogMsg("mDNSPlatformTCPConnect: Invalid interface index %p", InterfaceID); return mStatus_BadParamErr; }
         #else
             (void)InterfaceID; // Unused
@@ -1697,10 +1828,9 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst,
     // mDNSPlatformReadTCP/WriteTCP (unlike the UDP counterpart) does not provide the destination address
     // from which we can infer the destination address family. Hence we need to remember that here.
     // Instead of remembering the address family, we remember the right fd.
-    sock->fd = *s;
-    sock->kqEntry = k;
+    sock->fd = sock->fd;
     // initiate connection wth peer
-    if (connect(*s, (struct sockaddr *)&ss, ss.ss_len) < 0)
+    if (connect(sock->fd, (struct sockaddr *)&ss, ss.ss_len) < 0)
     {
         if (errno == EINPROGRESS) return mStatus_ConnPending;
         if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
@@ -1712,18 +1842,54 @@ mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst,
 
     LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
     // kQueue should notify us, but this LogMsg is to help track down if it doesn't
+    // Experimentation shows that even a connection to a local listener returns EINPROGRESS, so this
+    // will likely never happen.
+
     return err;
 }
 
+// Replace the existing socket callback with a new one, or establish a callback where none was present.
+mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
+{
+    sock->callback = callback;
+    sock->context = context;
+
+    // dnsextd currently reaches into the TCPSocket structure layer to do its own thing; this won't work for
+    // any code (e.g., the Discovery Proxy or Discovery Relay) that actually uses the mDNSPlatform layer as
+    // an opaque layer.   So for that code, we have this.   dnsextd should probably be platformized if it's
+    // still relevant.
+    if (!sock->callback) {
+        // Watch for incoming data
+        if (KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry))
+        {
+            LogMsg("ERROR: mDNSPlatformTCPConnect - KQueueSet failed");
+            return mStatus_UnknownErr;
+        }
+    }
+    
+    sock->kqEntry.KQcallback = tcpKQSocketCallback;
+    sock->kqEntry.KQcontext  = sock;
+    sock->kqEntry.KQtask     = "mDNSPlatformTCPSocket";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+    sock->kqEntry.readSource = mDNSNULL;
+    sock->kqEntry.writeSource = mDNSNULL;
+    sock->kqEntry.fdClosed = mDNSfalse;
+#endif
+    return mStatus_NoError;
+}
+
 // Why doesn't mDNSPlatformTCPAccept actually call accept() ?
+// mDNSPlatformTCPAccept is only called by dnsextd.c.   It's called _after_ accept has returned
+// a connected socket.   The purpose appears to be to allocate and initialize the TCPSocket structure
+// and set up TLS, if required for this connection.   dnsextd appears to be the only thing in mDNSResponder
+// that accepts incoming TLS connections.
 mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
 {
     mStatus err = mStatus_NoError;
 
-    TCPSocket *sock = mallocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(TCPSocket));
+    TCPSocket *sock = (TCPSocket *) callocL("TCPSocket/mDNSPlatformTCPAccept", sizeof(*sock));
     if (!sock) return(mDNSNULL);
 
-    mDNSPlatformMemZero(sock, sizeof(*sock));
     sock->fd = fd;
     sock->flags = flags;
 
@@ -1749,6 +1915,69 @@ exit:
     return(sock);
 }
 
+mDNSlocal void tcpListenCallback(int fd, __unused short filter, void *context, __unused mDNSBool encounteredEOF)
+{
+    TCPListener *listener = context;
+    TCPSocket *sock;
+    
+    sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
+                                 listener->callback, listener->context);
+    
+    if (sock != mDNSNULL)
+    {
+        KQueueSet(sock->fd, EV_ADD, EVFILT_READ, &sock->kqEntry);
+        sock->kqEntry.KQcallback = tcpKQSocketCallback;
+        sock->kqEntry.KQcontext  = sock;
+        sock->kqEntry.KQtask     = "mDNSPlatformTCPListen";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+        sock->kqEntry.readSource = mDNSNULL;
+        sock->kqEntry.writeSource = mDNSNULL;
+        sock->kqEntry.fdClosed = mDNSfalse;
+#endif
+    }
+}
+
+mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+                                              TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+                                              TCPAcceptedCallback callback, void *context)
+{
+    TCPListener *ret;
+    int fd = -1;
+
+    if (!mDNSPosixTCPListen(&fd, addrtype, port, addr, reuseAddr, queueLength)) {
+        if (fd != -1) {
+            close(fd);
+        }
+        return mDNSNULL;
+    }
+    
+    // Allocate a listener structure
+    ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
+    if (ret == mDNSNULL)
+    {
+        LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
+        close(fd);
+        return mDNSNULL;
+    }
+    ret->fd = fd;
+    ret->callback = callback;
+    ret->context = context;
+    ret->socketFlags = socketFlags;
+
+    // Watch for incoming data
+    KQueueSet(ret->fd, EV_ADD, EVFILT_READ, &ret->kqEntry);
+    ret->kqEntry.KQcallback = tcpListenCallback;
+    ret->kqEntry.KQcontext  = ret;
+    ret->kqEntry.KQtask     = "mDNSPlatformTCPListen";
+#ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
+    ret->kqEntry.readSource = mDNSNULL;
+    ret->kqEntry.writeSource = mDNSNULL;
+    ret->kqEntry.fdClosed = mDNSfalse;
+#endif
+    return ret;
+}
+
 mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
 {
     mDNSu16 port;
@@ -1797,13 +2026,12 @@ mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
             sock->tlsContext = NULL;
         }
 #endif /* NO_SECURITYFRAMEWORK */
-        if (sock->ss.sktv4 != -1) 
-            shutdown(sock->ss.sktv4, 2);
-        if (sock->ss.sktv6 != -1) 
-            shutdown(sock->ss.sktv6, 2);
-        CloseSocketSet(&sock->ss);
-        sock->fd = -1;
-
+        if (sock->fd != -1) {
+            shutdown(sock->fd, 2);
+            mDNSPlatformCloseFD(&sock->kqEntry, sock->fd);
+            sock->fd = -1;
+        }
+        
         freeL("TCPSocket/mDNSPlatformTCPCloseConnection", sock);
     }
 }
@@ -1813,6 +2041,12 @@ mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long bu
     ssize_t nread = 0;
     *closed = mDNSfalse;
 
+    // We can get here if the caller set up a TCP connection but didn't check the status when it got the
+    // callback.
+    if (!sock->connected) {
+        return mStatus_DefunctConnection;
+    }
+    
     if (sock->flags & kTCPSocketFlags_UseTLS)
     {
 #ifndef NO_SECURITYFRAMEWORK
@@ -1833,37 +2067,7 @@ mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long bu
     }
     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); 
-                assert(CLOSEDcount < 1000);
-                // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error msg multiple times,
-                // crash mDNSResponder using assert() and restart fresh. See advantages below:
-                // 1.Better User Experience 
-                // 2.CrashLogs frequency can be monitored 
-                // 3.StackTrace can be used for more info
-            }
-        }
-        // 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); }
-        }
+        nread = mDNSPosixReadTCP(sock->fd, buf, buflen, closed);
     }
 
     return nread;
@@ -1873,6 +2077,10 @@ mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned
 {
     int nsent;
 
+    if (!sock->connected) {
+        return mStatus_DefunctConnection;
+    }
+
     if (sock->flags & kTCPSocketFlags_UseTLS)
     {
 #ifndef NO_SECURITYFRAMEWORK
@@ -1892,14 +2100,8 @@ mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned
     }
     else
     {
-        nsent = send(sock->fd, msg, len, 0);
-        if (nsent < 0)
-        {
-            if (errno == EAGAIN) nsent = 0;
-            else { LogMsg("ERROR: mDNSPlatformWriteTCP - send %s", strerror(errno)); nsent = -1; }
-        }
+        nsent = mDNSPosixWriteTCP(sock->fd, msg, len);
     }
-
     return nsent;
 }
 
@@ -1908,11 +2110,41 @@ 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(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
+// This function checks to see if the socket is writable.   It will be writable if the kernel TCP output
+// buffer is less full than TCP_NOTSENT_LOWAT.   This should be half or less of the actual kernel buffer
+// size.   This check is done in cases where data should be written if there's space, for example in the
+// Discovery Relay code, where we may be receiving mDNS messages at arbitrary times, and generally there
+// should be buffer space to relay them, but in exceptional cases there might not be.   In this case it's
+
+mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
 {
-    int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
+    int kfd = kqueue();
+    struct kevent kin, kout;
+    int count;
+    struct timespec ts;
+    
+    if (kfd < 0)
+    {
+        LogMsg("ERROR: kqueue failed: %m");
+        return mDNSfalse;
+    }
+    ts.tv_sec = 0;
+    ts.tv_nsec = 0;
+    EV_SET(&kin, sock->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+    count = kevent(kfd, &kin, 1, &kout, 1, &ts);
+    close(kfd);
+    if (count == 1 && (int)kout.ident == sock->fd && kout.filter == EVFILT_WRITE)
+    {
+        return mDNStrue;
+    }
+    return mDNSfalse;
+}
+
+// If mDNSIPPort port is non-zero, then it's a multicast socket on the specified interface
+// If mDNSIPPort port is zero, then it's a randomly assigned port number, used for sending unicast queries
+mDNSlocal mStatus SetupSocket(KQSocketSet *cp, const mDNSIPPort port, u_short sa_family, mDNSIPPort *const outport)
+{
+    int         *s        = (sa_family == AF_INET) ? &cp->sktv4 : &cp->sktv6;
     KQueueEntry *k        = (sa_family == AF_INET) ? &cp->kqsv4 : &cp->kqsv6;
     const int on = 1;
     const int twofivefive = 255;
@@ -2079,9 +2311,8 @@ mDNSexport UDPSocket *mDNSPlatformUDPSocket(const mDNSIPPort requestedport)
     mDNSIPPort port = requestedport;
     mDNSBool randomizePort = mDNSIPPortIsZero(requestedport);
     int i = 10000; // Try at most 10000 times to get a unique random port
-    UDPSocket *p = mallocL("UDPSocket", sizeof(UDPSocket));
+    UDPSocket *p = (UDPSocket *) callocL("UDPSocket", sizeof(*p));
     if (!p) { LogMsg("mDNSPlatformUDPSocket: memory exhausted"); return(mDNSNULL); }
-    mDNSPlatformMemZero(p, sizeof(UDPSocket));
     p->ss.port  = zeroIPPort;
     p->ss.m     = &mDNSStorage;
     p->ss.sktv4 = -1;
@@ -2628,13 +2859,17 @@ mDNSlocal void mDNSGet_RemoteMAC(int family, v6addr_t raddr)
     // the values and schedule a task to update the MAC address in the TCP Keepalive record.
     if (kr == 0)
     {
-        addrMapping = mDNSPlatformMemAllocate(sizeof(IPAddressMACMapping));
+        addrMapping = (IPAddressMACMapping *) mDNSPlatformMemAllocateClear(sizeof(*addrMapping));
+        // This memory allocation is not checked for failure
+        // It also shoudn’t need to be a memory allocation at all -- why not just use a stack variable? -- SC
         snprintf(addrMapping->ethaddr, sizeof(addrMapping->ethaddr), "%02x:%02x:%02x:%02x:%02x:%02x",
                      eth[0], eth[1], eth[2], eth[3], eth[4], eth[5]);
+        // Why is the address represented using text? The UpdateRMAC routine just parses it back into a six-byte MAC address. -- SC
         if (family == AF_INET)
         {
             addrMapping->ipaddr.type = mDNSAddrType_IPv4;
             mDNSPlatformMemCopy(addrMapping->ipaddr.ip.v4.b, raddr, sizeof(v6addr_t));
+            // This is the wrong size. It’s using sizeof(v6addr_t) for an IPv4 address -- SC
         }
         else
         {
@@ -2915,10 +3150,10 @@ mDNSexport void mDNSPlatformReceiveBPF_fd(int fd)
             LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCIMMEDIATE failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
 
         //if (ioctl(fd, BIOCPROMISC, &opt_one) < 0)
-        //     LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+        //  LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCPROMISC failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
 
         //if (ioctl(fd, BIOCSHDRCMPLT, &opt_one) < 0)
-        //     LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
+        //  LogMsg("mDNSPlatformReceiveBPF_fd: %d %s BIOCSHDRCMPLT failed %d (%s)", fd, i->ifinfo.ifname, errno, strerror(errno));
 
         /*  <rdar://problem/10287386>
          *  make socket non blocking see comments in bpf_callback_common for more info
@@ -3074,34 +3309,49 @@ mDNSexport void  mDNSPlatformTLSTearDownCerts(void)
 #endif /* NO_SECURITYFRAMEWORK */
 }
 
+
+mDNSlocal void mDNSDomainLabelFromCFString(CFStringRef cfs, domainlabel *const namelabel);
+
 // 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);
+
+    if (cfs == mDNSNULL) {
+        return;
     }
+
+    mDNSDomainLabelFromCFString(cfs, namelabel);
+
+    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);
+
+    if (cfs == mDNSNULL) {
+        return;
     }
+
+    mDNSDomainLabelFromCFString(cfs, namelabel);
+
+    CFRelease(cfs);
+}
+
+mDNSlocal void mDNSDomainLabelFromCFString(CFStringRef cfs, domainlabel *const namelabel)
+{
+    CFIndex num_of_bytes_write = 0;
+    CFStringGetBytes(cfs, CFRangeMake(0, CFStringGetLength(cfs)), kCFStringEncodingUTF8, 0, FALSE, namelabel->c + 1, sizeof(*namelabel) - 1, &num_of_bytes_write);
+    namelabel->c[0] = num_of_bytes_write;
 }
 
 mDNSexport mDNSBool DictionaryIsEnabled(CFDictionaryRef dict)
 {
     mDNSs32 val;
     CFNumberRef state = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("Enabled"));
-    if (!state) return mDNSfalse;
+    if (state == NULL) return mDNSfalse;
     if (!CFNumberGetValue(state, kCFNumberSInt32Type, &val))
     { LogMsg("ERROR: DictionaryIsEnabled - CFNumberGetValue"); return mDNSfalse; }
     return val ? mDNStrue : mDNSfalse;
@@ -3240,7 +3490,8 @@ mDNSlocal mDNSBool  CheckInterfaceSupport(NetworkInterfaceInfo *const intf, cons
     {
         io_name_t n1;
         IOObjectGetClass(service, n1);
-        LogSPS("CheckInterfaceSupport: No %s for interface %s/%s kr %d", key, intf->ifname, n1, kr);
+        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
+            "CheckInterfaceSupport: No " PUB_S " for interface " PUB_S "/" PUB_S " kr 0x%X", key, intf->ifname, n1, kr);
         ret = mDNSfalse;
     }
 
@@ -3249,17 +3500,24 @@ mDNSlocal mDNSBool  CheckInterfaceSupport(NetworkInterfaceInfo *const intf, cons
 }
 
 
+#if !TARGET_OS_WATCH
 mDNSlocal  mDNSBool InterfaceSupportsKeepAlive(NetworkInterfaceInfo *const intf)
 {
     return CheckInterfaceSupport(intf, mDNS_IOREG_KA_KEY);
 }
+#endif
 
 mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
 {
+#if TARGET_OS_WATCH
+    (void) i;   // unused
+    return(mDNSfalse);
+#else
     // We only use Sleep Proxy Service on multicast-capable interfaces, except loopback and D2D.
     if (!MulticastInterface(i) || (i->ifa_flags & IFF_LOOPBACK) || i->D2DInterface)
     {
-        LogSPS("NetWakeInterface: returning false for %s", i->ifinfo.ifname);
+        LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_DEBUG,
+            "NetWakeInterface: returning false for " PUB_S, i->ifinfo.ifname);
         return(mDNSfalse);
     }
 
@@ -3293,14 +3551,17 @@ mDNSlocal mDNSBool NetWakeInterface(NetworkInterfaceInfoOSX *i)
 
     close(s);
 
-    // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET;   // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
+    // ifr.ifr_wake_flags = IF_WAKE_ON_MAGIC_PACKET;    // For testing with MacBook Air, using a USB dongle that doesn't actually support Wake-On-LAN
 
-    LogSPS("NetWakeInterface: %-6s %#-14a %s WOMP", i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
+    LogRedact(MDNS_LOG_CATEGORY_SPS, MDNS_LOG_INFO,
+        "NetWakeInterface: " PUB_S " " PRI_IP_ADDR " " PUB_S " WOMP",
+        i->ifinfo.ifname, &i->ifinfo.ip, (ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) ? "supports" : "no");
 
     return((ifr.ifr_wake_flags & IF_WAKE_ON_MAGIC_PACKET) != 0);
+#endif  // TARGET_OS_WATCH
 }
 
-mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
+mDNSlocal u_int64_t getExtendedFlags(const char *ifa_name)
 {
     int sockFD;
     struct ifreq ifr;
@@ -3317,7 +3578,7 @@ mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
 
     if (ioctl(sockFD, SIOCGIFEFLAGS, (caddr_t)&ifr) == -1)
     {
-        LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed, errno = %d (%s)", errno, strerror(errno));
+        LogMsg("getExtendedFlags: SIOCGIFEFLAGS failed for %s, errno = %d (%s)", ifa_name, errno, strerror(errno));
         ifr.ifr_eflags = 0;
     }
 
@@ -3325,15 +3586,23 @@ mDNSlocal u_int64_t getExtendedFlags(char * ifa_name)
     return ifr.ifr_eflags;
 }
 
-#if TARGET_OS_OSX 
-// IFRTYPE_FUNCTIONAL_INTCOPROC type interfaces on macOS do not support Bonjour discovery.
-mDNSlocal mDNSBool isCoprocessorInterface(int sockFD, char * ifa_name)
+mDNSlocal mDNSBool isExcludedInterface(int sockFD, char * ifa_name)
 {
     struct ifreq ifr;
 
+    // llw0 interface is excluded from Bonjour discover.
+    // There currently is no interface attributed based way to identify this interface
+    // until rdar://problem/47933782 is addressed.
+    if (strncmp(ifa_name, "llw", 3) == 0)
+    {
+        LogMsg("isExcludedInterface: excluding %s", ifa_name);
+        return mDNStrue;
+    }
+
+    // Coprocessor interfaces are also excluded.
     if (sockFD < 0)
     {
-        LogMsg("isCoprocessorInterface: invalid socket FD passed: %d", sockFD);
+        LogMsg("isExcludedInterface: invalid socket FD passed: %d", sockFD);
         return mDNSfalse;
     }
 
@@ -3342,23 +3611,19 @@ mDNSlocal mDNSBool isCoprocessorInterface(int sockFD, char * ifa_name)
 
     if (ioctl(sockFD, SIOCGIFFUNCTIONALTYPE, (caddr_t)&ifr) == -1)
     {
-        LogMsg("isCoprocessorInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
+        LogMsg("isExcludedInterface: SIOCGIFFUNCTIONALTYPE failed, errno = %d (%s)", errno, strerror(errno));
         return mDNSfalse;
     }
 
     if (ifr.ifr_functional_type == IFRTYPE_FUNCTIONAL_INTCOPROC)
     {
-        LogMsg("isCoprocessorInterface: %s marked as coprocessor interface", ifa_name);
+        LogMsg("isExcludedInterface: excluding coprocessor interface %s", ifa_name);
         return mDNStrue;
     }
     else
         return mDNSfalse;
 }
 
-#else   // TARGET_OS_OSX
-#define isCoprocessorInterface(A, B)    mDNSfalse
-#endif   // TARGET_OS_OSX
-
 #if TARGET_OS_IPHONE
 
 // Function pointers for the routines we use in the MobileWiFi framework.
@@ -3524,6 +3789,7 @@ mDNSlocal mDNSBool IsCarPlaySSID(char *ifa_name)
 // 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(struct ifaddrs *ifa, mDNSs32 utc)
 {
     mDNS *const m = &mDNSStorage;
@@ -3586,10 +3852,9 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs
             return(*p);
         }
 
-    NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *)mallocL("NetworkInterfaceInfoOSX", sizeof(*i));
+    NetworkInterfaceInfoOSX *i = (NetworkInterfaceInfoOSX *) callocL("NetworkInterfaceInfoOSX", sizeof(*i));
     debugf("AddInterfaceToList: Making   new   interface %lu %.6a with address %#a at %p", scope_id, &bssid, &ip, i);
     if (!i) return(mDNSNULL);
-    mDNSPlatformMemZero(i, sizeof(NetworkInterfaceInfoOSX));
     i->ifinfo.InterfaceID = (mDNSInterfaceID)(uintptr_t)scope_id;
     i->ifinfo.ip          = ip;
     i->ifinfo.mask        = mask;
@@ -3622,1144 +3887,43 @@ mDNSlocal NetworkInterfaceInfoOSX *AddInterfaceToList(struct ifaddrs *ifa, mDNSs
     i->D2DInterface    = ((eflags & IFEF_LOCALNET_PRIVATE) || (strncmp(i->ifinfo.ifname, "p2p", 3) == 0)) ? mDNStrue: mDNSfalse;
     if (i->D2DInterface)
         LogInfo("AddInterfaceToList: D2DInterface set for %s", ifa->ifa_name);
-
-    i->isExpensive     = (eflags & IFEF_EXPENSIVE) ? mDNStrue: mDNSfalse;
     i->isAWDL          = (eflags & IFEF_AWDL)      ? mDNStrue: mDNSfalse;
-    if (eflags & IFEF_AWDL)
-    {
-        // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
-        // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
-        // Bonjour requests over the AWDL interface.
-        i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
-        AWDLInterfaceID = i->ifinfo.InterfaceID;
-        LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
-    }
-    else
-    {
-        i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
-    }
-    i->AppearanceTime  = utc;       // Brand new interface; AppearanceTime is now
-    i->LastSeen        = utc;
-    i->ifa_flags       = ifa->ifa_flags;
-    i->scope_id        = scope_id;
-    i->BSSID           = bssid;
-    i->sa_family       = ifa->ifa_addr->sa_family;
-    i->BPF_fd          = -1;
-    i->BPF_mcfd        = -1;
-    i->BPF_len         = 0;
-    i->Registered      = mDNSNULL;
-
-    // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
-    i->ifinfo.McastTxRx   = MulticastInterface(i);
-    // Do this AFTER i->BSSID has been set up
-    i->ifinfo.NetWake  = (eflags & IFEF_EXPENSIVE)? mDNSfalse :  NetWakeInterface(i);
-    GetMAC(&i->ifinfo.MAC, scope_id);
-    if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
-        LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
-
-    *p = i;
-    return(i);
-}
-
-#if APPLE_OSX_mDNSResponder
-
-#if COMPILER_LIKES_PRAGMA_MARK
-#pragma mark -
-#pragma mark - AutoTunnel
-#endif
-
-#define kRacoonPort 4500
-
-static DomainAuthInfo* AnonymousRacoonConfig = mDNSNULL;
-
-#ifndef NO_SECURITYFRAMEWORK
-
-static CFMutableDictionaryRef domainStatusDict = NULL;
-
-mDNSlocal mStatus CheckQuestionForStatus(const DNSQuestion *const q)
-{
-    if (q->LongLived)
-    {
-        if (q->servAddr.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsOnes(q->servAddr.ip.v4))
-            return mStatus_NoSuchRecord;
-        else if (q->state == LLQ_Poll)
-            return mStatus_PollingMode;
-        else if (q->state != LLQ_Established && !q->DuplicateOf)
-            return mStatus_TransientErr;
-    }
-
-    return mStatus_NoError;
-}
-
-mDNSlocal mStatus UpdateLLQStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
-{
-    mStatus status = mStatus_NoError;
-    DNSQuestion* q, *worst_q = mDNSNULL;
-    for (q = mDNSStorage.Questions; q; q=q->next)
-        if (q->AuthInfo == info)
-        {
-            mStatus newStatus = CheckQuestionForStatus(q);
-            if      (newStatus == mStatus_NoSuchRecord) { status = newStatus; worst_q = q; break; }
-            else if (newStatus == mStatus_PollingMode)  { status = newStatus; worst_q = q; }
-            else if (newStatus == mStatus_TransientErr && status == mStatus_NoError) { status = newStatus; worst_q = q; }
-        }
-
-    if      (status == mStatus_NoError) mDNS_snprintf(buffer, bufsz, "Success");
-    else if (status == mStatus_NoSuchRecord) mDNS_snprintf(buffer, bufsz, "GetZoneData %s: %##s", worst_q->nta ? "not yet complete" : "failed", worst_q->qname.c);
-    else if (status == mStatus_PollingMode) mDNS_snprintf(buffer, bufsz, "Query polling %##s", worst_q->qname.c);
-    else if (status == mStatus_TransientErr) mDNS_snprintf(buffer, bufsz, "Query not yet established %##s", worst_q->qname.c);
-    return status;
-}
-
-mDNSlocal mStatus UpdateRRStatus(char *buffer, int bufsz, const DomainAuthInfo *const info)
-{
-    AuthRecord *r;
-
-    if (info->deltime) return mStatus_NoError;
-    for (r = mDNSStorage.ResourceRecords; r; r = r->next)
-    {
-        // This function is called from UpdateAutoTunnelDomainStatus which in turn may be called from
-        // a callback e.g., CheckNATMappings. GetAuthInfoFor_internal does not like that (reentrancy being 1),
-        // hence we inline the code here. We just need the lock to walk the list of AuthInfos which the caller
-        // has already checked
-        const domainname *n = r->resrec.name;
-        while (n->c[0])
-        {
-            DomainAuthInfo *ptr;
-            for (ptr = mDNSStorage.AuthInfoList; ptr; ptr = ptr->next)
-                if (SameDomainName(&ptr->domain, n))
-                {
-                    if (ptr == info && (r->updateError == mStatus_BadSig || r->updateError == mStatus_BadKey || r->updateError == mStatus_BadTime))
-                    {
-                        mDNS_snprintf(buffer, bufsz, "Resource record update failed for %##s", r->resrec.name);
-                        return r->updateError;
-                    }
-                }
-            n = (const domainname *)(n->c + 1 + n->c[0]);
-        }
-    }
-    return mStatus_NoError;
-}
-
-#endif // ndef NO_SECURITYFRAMEWORK
-
-// MUST be called with lock held
-mDNSlocal void UpdateAutoTunnelDomainStatus(const DomainAuthInfo *const info)
-{
-#ifdef NO_SECURITYFRAMEWORK
-    (void)info;
-#else
-    // Note that in the LLQNAT, the clientCallback being non-zero means it's in use,
-    // whereas in the AutoTunnelNAT, the clientContext being non-zero means it's in use
-    mDNS *const m = &mDNSStorage;
-    const NATTraversalInfo *const llq = m->LLQNAT.clientCallback ? &m->LLQNAT : mDNSNULL;
-    const NATTraversalInfo *const tun = m->AutoTunnelNAT.clientContext ? &m->AutoTunnelNAT : mDNSNULL;
-    char buffer[1024];
-    CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-    CFStringRef domain = NULL;
-    CFStringRef tmp = NULL;
-    CFNumberRef num = NULL;
-    mStatus status = mStatus_NoError;
-    mStatus llqStatus = mStatus_NoError;
-    char llqBuffer[1024];
-
-    mDNS_CheckLock(m);
-
-    if (!domainStatusDict)
-    {
-        domainStatusDict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
-        if (!domainStatusDict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary domainStatusDict"); return; }
-    }
-
-    if (!dict) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFDictionary dict"); return; }
-
-    mDNS_snprintf(buffer, sizeof(buffer), "%##s", info->domain.c);
-    domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
-    if (!domain) { LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString domain"); return; }
-
-    if (info->deltime)
-    {
-        if (CFDictionaryContainsKey(domainStatusDict, domain))
-        {
-            CFDictionaryRemoveValue(domainStatusDict, domain);
-            if (!m->ShutdownTime) mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
-        }
-        CFRelease(domain);
-        CFRelease(dict);
-
-        return;
-    }
-
-    mDNS_snprintf(buffer, sizeof(buffer), "%#a", &m->Router);
-    tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
-    if (!tmp)
-        LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString RouterAddress");
-    else
-    {
-        CFDictionarySetValue(dict, CFSTR("RouterAddress"), tmp);
-        CFRelease(tmp);
-    }
-
-    if (llq)
-    {
-        mDNSu32 port = mDNSVal16(llq->ExternalPort);
-
-        num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
-        if (!num)
-            LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQExternalPort");
-        else
-        {
-            CFDictionarySetValue(dict, CFSTR("LLQExternalPort"), num);
-            CFRelease(num);
-        }
-
-        if (llq->Result)
-        {
-            num = CFNumberCreate(NULL, kCFNumberSInt32Type, &llq->Result);
-            if (!num)
-                LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LLQNPMStatus");
-            else
-            {
-                CFDictionarySetValue(dict, CFSTR("LLQNPMStatus"), num);
-                CFRelease(num);
-            }
-        }
-    }
-
-    if (tun)
-    {
-        mDNSu32 port = mDNSVal16(tun->ExternalPort);
-
-        num = CFNumberCreate(NULL, kCFNumberSInt32Type, &port);
-        if (!num)
-            LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelExternalPort");
-        else
-        {
-            CFDictionarySetValue(dict, CFSTR("AutoTunnelExternalPort"), num);
-            CFRelease(num);
-        }
-
-        mDNS_snprintf(buffer, sizeof(buffer), "%.4a", &tun->ExternalAddress);
-        tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
-        if (!tmp)
-            LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString ExternalAddress");
-        else
-        {
-            CFDictionarySetValue(dict, CFSTR("ExternalAddress"), tmp);
-            CFRelease(tmp);
-        }
-
-        if (tun->Result)
-        {
-            num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tun->Result);
-            if (!num)
-                LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber AutoTunnelNPMStatus");
-            else
-            {
-                CFDictionarySetValue(dict, CFSTR("AutoTunnelNPMStatus"), num);
-                CFRelease(num);
-            }
-        }
-    }
-    if (tun || llq)
-    {
-        mDNSu32 code = m->LastNATMapResultCode;
-
-        num = CFNumberCreate(NULL, kCFNumberSInt32Type, &code);
-        if (!num)
-            LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber LastNATMapResultCode");
-        else
-        {
-            CFDictionarySetValue(dict, CFSTR("LastNATMapResultCode"), num);
-            CFRelease(num);
-        }
-    }
-
-    mDNS_snprintf(buffer, sizeof(buffer), "Success");
-    llqStatus = UpdateLLQStatus(llqBuffer, sizeof(llqBuffer), info);
-    status = UpdateRRStatus(buffer, sizeof(buffer), info);
-
-    // If we have a bad signature error updating a RR, it overrides any error as it needs to be
-    // reported so that it can be fixed automatically (or the user needs to be notified)
-    if (status != mStatus_NoError)
-    {
-        LogInfo("UpdateAutoTunnelDomainStatus: RR Status %d, %s", status, buffer);
-    }
-    else if (m->Router.type == mDNSAddrType_None)
-    {
-        status = mStatus_NoRouter;
-        mDNS_snprintf(buffer, sizeof(buffer), "No network connection - none");
-    }
-    else if (m->Router.type == mDNSAddrType_IPv4 && mDNSIPv4AddressIsZero(m->Router.ip.v4))
-    {
-        status = mStatus_NoRouter;
-        mDNS_snprintf(buffer, sizeof(buffer), "No network connection - v4 zero");
-    }
-    else if (mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress))
-    {
-        status = mStatus_ServiceNotRunning;
-        mDNS_snprintf(buffer, sizeof(buffer), "No inner address");
-    }
-    else if (!llq && !tun)
-    {
-        status = mStatus_NotInitializedErr;
-        mDNS_snprintf(buffer, sizeof(buffer), "Neither LLQ nor AutoTunnel NAT port mapping is currently active");
-    }
-    else if (llqStatus == mStatus_NoSuchRecord)
-    {
-        status = llqStatus;
-        mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
-    }
-    else if ((llq && llq->Result == mStatus_DoubleNAT) || (tun && tun->Result == mStatus_DoubleNAT))
-    {
-        status = mStatus_DoubleNAT;
-        mDNS_snprintf(buffer, sizeof(buffer), "Double NAT: Router is reporting a private address");
-    }
-    else if ((llq && llq->Result == mStatus_NATPortMappingDisabled) ||
-             (tun && tun->Result == mStatus_NATPortMappingDisabled) ||
-             (m->LastNATMapResultCode == NATErr_Refused && ((llq && !llq->Result && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && !tun->Result && mDNSIPPortIsZero(tun->ExternalPort)))))
-    {
-        status = mStatus_NATPortMappingDisabled;
-        mDNS_snprintf(buffer, sizeof(buffer), "PCP/NAT-PMP is disabled on the router");
-    }
-    else if ((llq && llq->Result) || (tun && tun->Result))
-    {
-        status = mStatus_NATTraversal;
-        mDNS_snprintf(buffer, sizeof(buffer), "Error obtaining NAT port mapping from router");
-    }
-    else if ((llq && mDNSIPPortIsZero(llq->ExternalPort)) || (tun && mDNSIPPortIsZero(tun->ExternalPort)))
-    {
-        status = mStatus_NATTraversal;
-        mDNS_snprintf(buffer, sizeof(buffer), "Unable to obtain NAT port mapping from router");
-    }
-    else
-    {
-        status = llqStatus;
-        mDNS_snprintf(buffer, sizeof(buffer), "%s", llqBuffer);
-        LogInfo("UpdateAutoTunnelDomainStatus: LLQ Status %d, %s", status, buffer);
-    }
-
-    num = CFNumberCreate(NULL, kCFNumberSInt32Type, &status);
-    if (!num)
-        LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFNumber StatusCode");
-    else
-    {
-        CFDictionarySetValue(dict, CFSTR("StatusCode"), num);
-        CFRelease(num);
-    }
-
-    tmp = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
-    if (!tmp)
-        LogMsg("UpdateAutoTunnelDomainStatus: Could not create CFString StatusMessage");
-    else
-    {
-        CFDictionarySetValue(dict, CFSTR("StatusMessage"), tmp);
-        CFRelease(tmp);
-    }
-
-    if (!CFDictionaryContainsKey(domainStatusDict, domain) ||
-        !CFEqual(dict, (CFMutableDictionaryRef)CFDictionaryGetValue(domainStatusDict, domain)))
-    {
-        CFDictionarySetValue(domainStatusDict, domain, dict);
-        if (!m->ShutdownTime)
-        {
-            LogInfo("UpdateAutoTunnelDomainStatus: %s status %d", status ? "failure" : "success", status);
-            mDNSDynamicStoreSetConfig(kmDNSBackToMyMacConfig, mDNSNULL, domainStatusDict);
-        }
-    }
-
-    CFRelease(domain);
-    CFRelease(dict);
-
-    debugf("UpdateAutoTunnelDomainStatus: %s", buffer);
-#endif // def NO_SECURITYFRAMEWORK
-}
-
-// MUST be called with lock held
-mDNSexport void UpdateAutoTunnelDomainStatuses(const mDNS *const m)
-{
-#ifdef NO_SECURITYFRAMEWORK
-        (void) m;
-#else
-    mDNS_CheckLock(m);
-    DomainAuthInfo* info;
-    for (info = m->AuthInfoList; info; info = info->next)
-        if (info->AutoTunnel && !info->deltime)
-            UpdateAutoTunnelDomainStatus(info);
-#endif // def NO_SECURITYFRAMEWORK
-}
-
-mDNSlocal void UpdateAnonymousRacoonConfig(mDNS *m)     // Determine whether we need racoon to accept incoming connections
-{
-    DomainAuthInfo *info;
-
-    for (info = m->AuthInfoList; info; info = info->next)
-        if (info->AutoTunnel && !info->deltime && (!mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || !mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr)))
-            break;
-
-    if (info != AnonymousRacoonConfig)
-    {
-        AnonymousRacoonConfig = info;
-        LogInfo("UpdateAnonymousRacoonConfig need not be done in mDNSResponder");
-    }
-}
-
-mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result);
-
-// Caller must hold the lock
-mDNSlocal mDNSBool DeregisterAutoTunnelRecord(mDNS *m, DomainAuthInfo *info, AuthRecord* record)
-{
-    mDNS_CheckLock(m);
-
-    LogInfo("DeregisterAutoTunnelRecord %##s %##s", &info->domain.c, record->namestorage.c);
 
-    if (record->resrec.RecordType > kDNSRecordTypeDeregistering)
-    {
-        mStatus err = mDNS_Deregister_internal(m, record, mDNS_Dereg_normal);
-        if (err)
-        {
-            record->resrec.RecordType = kDNSRecordTypeUnregistered;
-            LogMsg("DeregisterAutoTunnelRecord error %d deregistering %##s %##s", err, info->domain.c, record->namestorage.c);
-            return mDNSfalse;
-        }
-        else LogInfo("DeregisterAutoTunnelRecord: Deregistered");
-    }
-    else LogInfo("DeregisterAutoTunnelRecord: Not deregistering, state:%d", record->resrec.RecordType);
-
-    return mDNStrue;
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
-{
-    if (!DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelHostRecord))
-    {
-        info->AutoTunnelHostRecord.namestorage.c[0] = 0;
-        m->NextSRVUpdate = NonZeroTime(m->timenow);
-    }
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelHostRecord(mDNS *m, DomainAuthInfo *info)
-{
-    mStatus err;
-    mDNSBool NATProblem = mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result;
-
-    mDNS_CheckLock(m);
-
-    if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(info->AutoTunnelInnerAddress) || (m->SleepState != SleepState_Awake && NATProblem))
-    {
-        LogInfo("UpdateAutoTunnelHostRecord: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) address(%.16a) sleepstate(%d)",
-                info->domain.c, info->AutoTunnelServiceStarted, info->deltime, &info->AutoTunnelInnerAddress, m->SleepState);
-        DeregisterAutoTunnelHostRecord(m, info);
-    }
-    else if (info->AutoTunnelHostRecord.resrec.RecordType == kDNSRecordTypeUnregistered)
-    {
-        mDNS_SetupResourceRecord(&info->AutoTunnelHostRecord, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
-                                 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
-        info->AutoTunnelHostRecord.namestorage.c[0] = 0;
-        AppendDomainLabel(&info->AutoTunnelHostRecord.namestorage, &m->hostlabel);
-        AppendDomainName (&info->AutoTunnelHostRecord.namestorage, &info->domain);
-        info->AutoTunnelHostRecord.resrec.rdata->u.ipv6 = info->AutoTunnelInnerAddress;
-        info->AutoTunnelHostRecord.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
-        err = mDNS_Register_internal(m, &info->AutoTunnelHostRecord);
-        if (err) LogMsg("UpdateAutoTunnelHostRecord error %d registering %##s", err, info->AutoTunnelHostRecord.namestorage.c);
-        else
-        {
-            // Make sure we trigger the registration of all SRV records in regState_NoTarget again
-            m->NextSRVUpdate = NonZeroTime(m->timenow);
-            LogInfo("UpdateAutoTunnelHostRecord registering %##s", info->AutoTunnelHostRecord.namestorage.c);
-        }
-    }
-    else LogInfo("UpdateAutoTunnelHostRecord: Type %d", info->AutoTunnelHostRecord.resrec.RecordType);
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
-{
-    LogInfo("DeregisterAutoTunnelServiceRecords %##s", info->domain.c);
-
-    DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelTarget);
-    DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelService);
-    UpdateAutoTunnelHostRecord(m, info);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelServiceRecords(mDNS *m, DomainAuthInfo *info)
-{
-    mDNS_CheckLock(m);
-
-    if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result)
-    {
-        LogInfo("UpdateAutoTunnelServiceRecords: Dereg %##s : AutoTunnelServiceStarted(%d) deltime(%d) ExtPort(%d) NATResult(%d)", info->domain.c, info->AutoTunnelServiceStarted, info->deltime, mDNSVal16(m->AutoTunnelNAT.ExternalPort), m->AutoTunnelNAT.Result);
-        DeregisterAutoTunnelServiceRecords(m, info);
-    }
-    else
-    {
-        if (info->AutoTunnelTarget.resrec.RecordType == kDNSRecordTypeUnregistered)
-        {
-            // 1. Set up our address record for the external tunnel address
-            // (Constructed name, not generally user-visible, used as target in IKE tunnel's SRV record)
-            mDNS_SetupResourceRecord(&info->AutoTunnelTarget, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL,
-                                     kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
-            AssignDomainName (&info->AutoTunnelTarget.namestorage, (const domainname*) "\x0B" "_autotunnel");
-            AppendDomainLabel(&info->AutoTunnelTarget.namestorage, &m->hostlabel);
-            AppendDomainName (&info->AutoTunnelTarget.namestorage, &info->domain);
-            info->AutoTunnelTarget.resrec.rdata->u.ipv4 = m->AutoTunnelNAT.ExternalAddress;
-            info->AutoTunnelTarget.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
-            mStatus err = mDNS_Register_internal(m, &info->AutoTunnelTarget);
-            if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelTarget.namestorage.c);
-            else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelTarget.namestorage.c);
-        }
-        else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Target state(%d)", info->AutoTunnelTarget.resrec.RecordType);
-
-        if (info->AutoTunnelService.resrec.RecordType == kDNSRecordTypeUnregistered)
-        {
-            // 2. Set up IKE tunnel's SRV record: _autotunnel._udp.AutoTunnelHost SRV 0 0 port AutoTunnelTarget
-            mDNS_SetupResourceRecord(&info->AutoTunnelService, mDNSNULL, mDNSInterface_Any, kDNSType_SRV,  kHostNameTTL,
-                                     kDNSRecordTypeUnregistered, AuthRecordAny, 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;
-            info->AutoTunnelService.resrec.rdata->u.srv.port     = m->AutoTunnelNAT.ExternalPort;
-            AssignDomainName(&info->AutoTunnelService.resrec.rdata->u.srv.target, &info->AutoTunnelTarget.namestorage);
-            info->AutoTunnelService.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
-            mStatus err = mDNS_Register_internal(m, &info->AutoTunnelService);
-            if (err) LogMsg("UpdateAutoTunnelServiceRecords error %d registering %##s", err, info->AutoTunnelService.namestorage.c);
-            else LogInfo("UpdateAutoTunnelServiceRecords registering %##s", info->AutoTunnelService.namestorage.c);
-        }
-        else LogInfo("UpdateAutoTunnelServiceRecords: NOOP Service state(%d)", info->AutoTunnelService.resrec.RecordType);
-
-        UpdateAutoTunnelHostRecord(m, info);
-
-        LogInfo("AutoTunnel server listening for connections on %##s[%.4a]:%d:%##s[%.16a]",
-                info->AutoTunnelTarget.namestorage.c,     &m->AdvertisedV4.ip.v4, mDNSVal16(m->AutoTunnelNAT.IntPort),
-                info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
-
-    }
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
-{
-    DeregisterAutoTunnelRecord(m, info, &info->AutoTunnelDeviceInfo);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnelDeviceInfoRecord(mDNS *m, DomainAuthInfo *info)
-{
-    mDNS_CheckLock(m);
-
-    if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime)
-        DeregisterAutoTunnelDeviceInfoRecord(m, info);
-    else if (info->AutoTunnelDeviceInfo.resrec.RecordType == kDNSRecordTypeUnregistered)
-    {
-        mDNS_SetupResourceRecord(&info->AutoTunnelDeviceInfo, mDNSNULL, mDNSInterface_Any, kDNSType_TXT,  kStandardTTL, kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
-        ConstructServiceName(&info->AutoTunnelDeviceInfo.namestorage, &m->nicelabel, &DeviceInfoName, &info->domain);
-
-        info->AutoTunnelDeviceInfo.resrec.rdlength = initializeDeviceInfoTXT(m, info->AutoTunnelDeviceInfo.resrec.rdata->u.data);
-        info->AutoTunnelDeviceInfo.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
-        mStatus err = mDNS_Register_internal(m, &info->AutoTunnelDeviceInfo);
-        if (err) LogMsg("UpdateAutoTunnelDeviceInfoRecord error %d registering %##s", err, info->AutoTunnelDeviceInfo.namestorage.c);
-        else LogInfo("UpdateAutoTunnelDeviceInfoRecord registering %##s", info->AutoTunnelDeviceInfo.namestorage.c);
-    }
-    else
-        LogInfo("UpdateAutoTunnelDeviceInfoRecord: not in Unregistered state: %d",info->AutoTunnelDeviceInfo.resrec.RecordType);
-}
-
-// Caller must hold the lock
-mDNSlocal void DeregisterAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
-{
-    LogInfo("DeregisterAutoTunnel6Record %##s", info->domain.c);
-
-    DeregisterAutoTunnelRecord(m, info, &info->AutoTunnel6Record);
-    UpdateAutoTunnelHostRecord(m, info);
-    UpdateAutoTunnelDomainStatus(info);
-}
-
-// Caller must hold the lock
-mDNSlocal void UpdateAutoTunnel6Record(mDNS *m, DomainAuthInfo *info)
-{
-    mDNS_CheckLock(m);
-
-    if (!info->AutoTunnelServiceStarted || info->deltime || m->ShutdownTime || mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr) || m->SleepState != SleepState_Awake)
-        DeregisterAutoTunnel6Record(m, info);
-    else if (info->AutoTunnel6Record.resrec.RecordType == kDNSRecordTypeUnregistered)
-    {
-        mDNS_SetupResourceRecord(&info->AutoTunnel6Record, mDNSNULL, mDNSInterface_Any, kDNSType_AAAA, kHostNameTTL,
-                                 kDNSRecordTypeUnregistered, AuthRecordAny, AutoTunnelRecordCallback, info);
-        AssignDomainName (&info->AutoTunnel6Record.namestorage, (const domainname*) "\x0C" "_autotunnel6");
-        AppendDomainLabel(&info->AutoTunnel6Record.namestorage, &m->hostlabel);
-        AppendDomainName (&info->AutoTunnel6Record.namestorage, &info->domain);
-        info->AutoTunnel6Record.resrec.rdata->u.ipv6 = m->AutoTunnelRelayAddr;
-        info->AutoTunnel6Record.resrec.RecordType = kDNSRecordTypeKnownUnique;
-
-        mStatus err = mDNS_Register_internal(m, &info->AutoTunnel6Record);
-        if (err) LogMsg("UpdateAutoTunnel6Record error %d registering %##s", err, info->AutoTunnel6Record.namestorage.c);
-        else LogInfo("UpdateAutoTunnel6Record registering %##s", info->AutoTunnel6Record.namestorage.c);
-
-        UpdateAutoTunnelHostRecord(m, info);
-
-        LogInfo("AutoTunnel6 server listening for connections on %##s[%.16a] :%##s[%.16a]",
-                info->AutoTunnel6Record.namestorage.c,    &m->AutoTunnelRelayAddr,
-                info->AutoTunnelHostRecord.namestorage.c, &info->AutoTunnelInnerAddress);
-
-    }
-    else LogInfo("UpdateAutoTunnel6Record NOOP state(%d)",info->AutoTunnel6Record.resrec.RecordType);
-}
-
-mDNSlocal void AutoTunnelRecordCallback(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
-    DomainAuthInfo *info = (DomainAuthInfo *)rr->RecordContext;
-    if (result == mStatus_MemFree)
-    {
-        LogInfo("AutoTunnelRecordCallback MemFree %s", ARDisplayString(m, rr));
-        
-        mDNS_Lock(m);
-        
-        // Reset the host record namestorage to force high-level PTR/SRV/TXT to deregister
-        if (rr == &info->AutoTunnelHostRecord)
-        {
-            rr->namestorage.c[0] = 0;
-            m->NextSRVUpdate = NonZeroTime(m->timenow);
-            LogInfo("AutoTunnelRecordCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
-        }
-        if (m->ShutdownTime)
-        {
-            LogInfo("AutoTunnelRecordCallback: Shutdown, returning");
-            mDNS_Unlock(m);        
-            return;
-        }
-        if (rr == &info->AutoTunnelHostRecord)
-        {
-            LogInfo("AutoTunnelRecordCallback: calling UpdateAutoTunnelHostRecord");
-            UpdateAutoTunnelHostRecord(m,info);
-        }
-        else if (rr == &info->AutoTunnelDeviceInfo)
-        {
-            LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelDeviceInfoRecord");
-            UpdateAutoTunnelDeviceInfoRecord(m,info);
-        }
-        else if (rr == &info->AutoTunnelService || rr == &info->AutoTunnelTarget)
-        {
-            LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnelServiceRecords");
-            UpdateAutoTunnelServiceRecords(m,info);
-        }
-        else if (rr == &info->AutoTunnel6Record)
-        {
-            LogInfo("AutoTunnelRecordCallback: Calling UpdateAutoTunnel6Record");
-            UpdateAutoTunnel6Record(m,info);
-        }
-
-        mDNS_Unlock(m);        
-    }
-}
-
-mDNSlocal void AutoTunnelNATCallback(mDNS *m, NATTraversalInfo *n)
-{
-    DomainAuthInfo *info;
-
-    LogInfo("AutoTunnelNATCallback Result %d %.4a Internal %d External %d",
-            n->Result, &n->ExternalAddress, mDNSVal16(n->IntPort), mDNSVal16(n->ExternalPort));
-
-    mDNS_Lock(m);
-    
-    m->NextSRVUpdate = NonZeroTime(m->timenow);
-    LogInfo("AutoTunnelNATCallback: NextSRVUpdate in %d %d", m->NextSRVUpdate - m->timenow, m->timenow);
-
-    for (info = m->AuthInfoList; info; info = info->next)
-        if (info->AutoTunnel)
-            UpdateAutoTunnelServiceRecords(m, info);
-
-    UpdateAnonymousRacoonConfig(m);     // Determine whether we need racoon to accept incoming connections
-
-    UpdateAutoTunnelDomainStatuses(m);
-
-    mDNS_Unlock(m);
-}
-
-mDNSlocal void AutoTunnelHostNameChanged(mDNS *m, DomainAuthInfo *info)
-{
-    LogInfo("AutoTunnelHostNameChanged %#s.%##s", m->hostlabel.c, info->domain.c);
-
-    mDNS_Lock(m);
-    // We forcibly deregister the records that are based on the hostname.
-    // When deregistration of each completes, the MemFree callback will make the
-    // appropriate Update* call to use the new name to reregister.
-    DeregisterAutoTunnelHostRecord(m, info);
-    DeregisterAutoTunnelDeviceInfoRecord(m, info);
-    DeregisterAutoTunnelServiceRecords(m, info);
-    DeregisterAutoTunnel6Record(m, info);
-    m->NextSRVUpdate = NonZeroTime(m->timenow);
-    mDNS_Unlock(m);
-}
-
-// Must be called with the lock held
-mDNSexport void StartServerTunnel(DomainAuthInfo *const info)
-{
-    mDNS *const m = &mDNSStorage;
-    if (info->deltime) return;
-    
-    if (info->AutoTunnelServiceStarted)
-    {
-        // On wake from sleep, this function will be called when determining SRV targets,
-        // and needs to re-register the host record for the target to be set correctly
-        UpdateAutoTunnelHostRecord(m, info);
-        return;
-    }
-    
-    info->AutoTunnelServiceStarted = mDNStrue;
-
-    // Now that we have a service in this domain, we need to try to register the
-    // AutoTunnel records, because the relay connection & NAT-T may have already been
-    // started for another domain. If the relay connection is not up or the NAT-T has not
-    // yet succeeded, the Update* functions are smart enough to not register the records.
-    // Note: This should be done after we set AutoTunnelServiceStarted, as that variable is used to
-    // decide whether to register the AutoTunnel records in the calls below.
-    UpdateAutoTunnelServiceRecords(m, info);
-    UpdateAutoTunnel6Record(m, info);
-    UpdateAutoTunnelDeviceInfoRecord(m, info);
-    UpdateAutoTunnelHostRecord(m, info);
-
-    // If the global AutoTunnel NAT-T is not yet started, start it.
-    if (!m->AutoTunnelNAT.clientContext)
-    {
-        m->AutoTunnelNAT.clientCallback   = AutoTunnelNATCallback;
-        m->AutoTunnelNAT.clientContext    = (void*)1; // Means AutoTunnelNAT Traversal is active;
-        m->AutoTunnelNAT.Protocol         = NATOp_MapUDP;
-        m->AutoTunnelNAT.IntPort          = IPSECPort;
-        m->AutoTunnelNAT.RequestedPort    = IPSECPort;
-        m->AutoTunnelNAT.NATLease         = 0;
-        mStatus err = mDNS_StartNATOperation_internal(m, &m->AutoTunnelNAT);
-        if (err) LogMsg("StartServerTunnel: error %d starting NAT mapping", err);
-    }
-}
-
-mDNSlocal mStatus AutoTunnelSetKeys(ClientTunnel *tun, mDNSBool AddNew)
-{
-    mDNSv6Addr loc_outer6;
-    mDNSv6Addr rmt_outer6;
-
-    // When we are tunneling over IPv6 Relay address, the port number is zero
-    if (mDNSIPPortIsZero(tun->rmt_outer_port))
-    {
-        loc_outer6 = tun->loc_outer6;
-        rmt_outer6 = tun->rmt_outer6;
-    }
-    else
-    {
-        loc_outer6 = zerov6Addr;
-        loc_outer6.b[0] = tun->loc_outer.b[0];
-        loc_outer6.b[1] = tun->loc_outer.b[1];
-        loc_outer6.b[2] = tun->loc_outer.b[2];
-        loc_outer6.b[3] = tun->loc_outer.b[3];
-
-        rmt_outer6 = zerov6Addr;
-        rmt_outer6.b[0] = tun->rmt_outer.b[0];
-        rmt_outer6.b[1] = tun->rmt_outer.b[1];
-        rmt_outer6.b[2] = tun->rmt_outer.b[2];
-        rmt_outer6.b[3] = tun->rmt_outer.b[3];
-    }
-
-    return(mDNSAutoTunnelSetKeys(AddNew ? kmDNSAutoTunnelSetKeysReplace : kmDNSAutoTunnelSetKeysDelete, tun->loc_inner.b, loc_outer6.b, kRacoonPort, tun->rmt_inner.b, rmt_outer6.b, mDNSVal16(tun->rmt_outer_port), btmmprefix, SkipLeadingLabels(&tun->dstname, 1)));
-}
-
-// If the EUI-64 part of the IPv6 ULA matches, then that means the two addresses point to the same machine
-#define mDNSSameClientTunnel(A,B) ((A)->l[2] == (B)->l[2] && (A)->l[3] == (B)->l[3])
-
-mDNSlocal void ReissueBlockedQuestionWithType(domainname *d, mDNSBool success, mDNSu16 qtype)
-{
-    mDNS *const m = &mDNSStorage;
-    DNSQuestion *q = m->Questions;
-    while (q)
-    {
-        if (q->NoAnswer == NoAnswer_Suspended && q->qtype == qtype && q->AuthInfo && q->AuthInfo->AutoTunnel && SameDomainName(&q->qname, d))
-        {
-            LogInfo("Restart %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-            mDNSQuestionCallback *tmp = q->QuestionCallback;
-            q->QuestionCallback = AutoTunnelCallback;   // Set QuestionCallback to suppress another call back to AddNewClientTunnel
-            mDNS_StopQuery(m, q);
-            mDNS_StartQuery(m, q);
-            q->QuestionCallback = tmp;                  // Restore QuestionCallback back to the real value
-            if (!success) q->NoAnswer = NoAnswer_Fail;
-            // When we call mDNS_StopQuery, it's possible for other subordinate questions like the GetZoneData query to be cancelled too.
-            // In general we have to assume that the question list might have changed in arbitrary ways.
-            // This code is itself called from a question callback, so the m->CurrentQuestion mechanism is
-            // already in use. The safest solution is just to go back to the start of the list and start again.
-            // In principle this sounds like an n^2 algorithm, but in practice we almost always activate
-            // just one suspended question, so it's really a 2n algorithm.
-            q = m->Questions;
-        }
-        else
-            q = q->next;
-    }
-}
-
-mDNSlocal void ReissueBlockedQuestions(domainname *d, mDNSBool success)
-{
-    // 1. We deliberately restart AAAA queries before A queries, because in the common case where a BTTM host has
-    //    a v6 address but no v4 address, we prefer the caller to get the positive AAAA response before the A NXDOMAIN.
-    // 2. In the case of AAAA queries, if our tunnel setup failed, then we return a deliberate failure indication to the caller --
-    //    even if the name does have a valid AAAA record, we don't want clients trying to connect to it without a properly encrypted tunnel.
-    // 3. For A queries we never fabricate failures -- if a BTTM service is really using raw IPv4, then it doesn't need the IPv6 tunnel.
-    ReissueBlockedQuestionWithType(d, success, kDNSType_AAAA);
-    ReissueBlockedQuestionWithType(d, mDNStrue, kDNSType_A);
-}
-
-mDNSlocal void UnlinkAndReissueBlockedQuestions(ClientTunnel *tun, mDNSBool success)
-{
-    mDNS *const m = &mDNSStorage;
-    ClientTunnel **p = &m->TunnelClients;
-    while (*p != tun && *p) p = &(*p)->next;
-    if (*p) *p = tun->next;
-    ReissueBlockedQuestions(&tun->dstname, success);
-    LogInfo("UnlinkAndReissueBlockedQuestions: Disposing ClientTunnel %p", tun);
-    freeL("ClientTunnel", tun);
-}
-
-mDNSlocal mDNSBool TunnelClientDeleteMatching(ClientTunnel *tun, mDNSBool v6Tunnel)
-{
-    mDNS *const m = &mDNSStorage;
-    ClientTunnel **p;
-    mDNSBool needSetKeys = mDNStrue;
-
-    p = &tun->next;
-    while (*p)
-    {
-        // Is this a tunnel to the same host that we are trying to setup now?
-        if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
-        else
-        {
-            ClientTunnel *old = *p;
-            if (v6Tunnel)
-            {
-                if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
-                LogInfo("TunnelClientDeleteMatching: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                if (old->q.ThisQInterval >= 0)
-                {
-                    LogInfo("TunnelClientDeleteMatching: Stopping query on IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                    mDNS_StopQuery(m, &old->q);
-                }
-                else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
-                         !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner)   ||
-                         !mDNSSameIPv6Address(old->loc_outer6, tun->loc_outer6) ||
-                         !mDNSSameIPv6Address(old->rmt_outer6, tun->rmt_outer6))
-                {
-                    // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
-                    // the other parameters of the tunnel are different
-                    LogInfo("TunnelClientDeleteMatching: Deleting existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                    AutoTunnelSetKeys(old, mDNSfalse);
-                }
-                else
-                {
-                    // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
-                    // as "tun" and "old" are identical
-                    LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c,
-                            &old->rmt_inner);
-                    needSetKeys = mDNSfalse;
-                }
-            }
-            else
-            {
-                if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue; }
-                LogInfo("TunnelClientDeleteMatching: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                if (old->q.ThisQInterval >= 0)
-                {
-                    LogInfo("TunnelClientDeleteMatching: Stopping query on IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                    mDNS_StopQuery(m, &old->q);
-                }
-                else if (!mDNSSameIPv6Address((*p)->rmt_inner, tun->rmt_inner) ||
-                         !mDNSSameIPv6Address(old->loc_inner, tun->loc_inner)   ||
-                         !mDNSSameIPv4Address(old->loc_outer, tun->loc_outer)   ||
-                         !mDNSSameIPv4Address(old->rmt_outer, tun->rmt_outer)   ||
-                         !mDNSSameIPPort(old->rmt_outer_port, tun->rmt_outer_port))
-                {
-                    // Delete the old tunnel if the current tunnel to the same host does not have the same ULA or
-                    // the other parameters of the tunnel are different
-                    LogInfo("TunnelClientDeleteMatching: Deleting existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                    AutoTunnelSetKeys(old, mDNSfalse);
-                }
-                else
-                {
-                    // Reusing the existing tunnel means that we reuse the IPsec SAs and the policies. We delete the old
-                    // as "tun" and "old" are identical
-                    LogInfo("TunnelClientDeleteMatching: Reusing the existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c,
-                            &old->rmt_inner);
-                    needSetKeys = mDNSfalse;
-                }
-            }
-
-            *p = old->next;
-            LogInfo("TunnelClientDeleteMatching: Disposing ClientTunnel %p", old);
-            freeL("ClientTunnel", old);
-        }
-    }
-    return needSetKeys;
-}
-
-// v6Tunnel indicates whether to delete a tunnel whose outer header is IPv6. If false, outer IPv4
-// tunnel will be deleted
-mDNSlocal void TunnelClientDeleteAny(ClientTunnel *tun, mDNSBool v6Tunnel)
-{
-    ClientTunnel **p;
-
-    p = &tun->next;
-    while (*p)
-    {
-        // If there is more than one client tunnel to the same host, delete all of them.
-        // We do this by just checking against the EUI64 rather than the full address
-        if (!mDNSSameClientTunnel(&(*p)->rmt_inner, &tun->rmt_inner)) p = &(*p)->next;
-        else
-        {
-            ClientTunnel *old = *p;
-            if (v6Tunnel)
-            {
-                if (!mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
-                LogInfo("TunnelClientDeleteAny: Found existing IPv6 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-            }
-            else
-            {
-                if (mDNSIPPortIsZero(old->rmt_outer_port)) { p = &old->next; continue;}
-                LogInfo("TunnelClientDeleteAny: Found existing IPv4 AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-            }
-            if (old->q.ThisQInterval >= 0)
-            {
-                LogInfo("TunnelClientDeleteAny: Stopping query on AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                mDNS_StopQuery(&mDNSStorage, &old->q);
-            }
-            else
-            {
-                LogInfo("TunnelClientDeleteAny: Deleting existing AutoTunnel for %##s %.16a", old->dstname.c, &old->rmt_inner);
-                AutoTunnelSetKeys(old, mDNSfalse);
-            }
-            *p = old->next;
-            LogInfo("TunnelClientDeleteAny: Disposing ClientTunnel %p", old);
-            freeL("ClientTunnel", old);
-        }
-    }
-}
-
-mDNSlocal void TunnelClientFinish(DNSQuestion *question, const ResourceRecord *const answer)
-{
-    mDNS *const m = &mDNSStorage;
-    mDNSBool needSetKeys = mDNStrue;
-    ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
-    mDNSBool v6Tunnel = mDNSfalse;
-    DomainAuthInfo *info;
-
-    // If the port is zero, then we have a relay address of the peer
-    if (mDNSIPPortIsZero(tun->rmt_outer_port))
-        v6Tunnel = mDNStrue;
-
-    if (v6Tunnel)
-    {
-        LogInfo("TunnelClientFinish: Relay address %.16a", &answer->rdata->u.ipv6);
-        tun->rmt_outer6 = answer->rdata->u.ipv6;
-        tun->loc_outer6 = m->AutoTunnelRelayAddr;
-    }
-    else
-    {
-        LogInfo("TunnelClientFinish: SRV target address %.4a", &answer->rdata->u.ipv4);
-        tun->rmt_outer = answer->rdata->u.ipv4;
-        mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
-        tmpDst.ip.v4 = tun->rmt_outer;
-        mDNSAddr tmpSrc = zeroAddr;
-        mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
-        if (tmpSrc.type == mDNSAddrType_IPv4) tun->loc_outer = tmpSrc.ip.v4;
-        else tun->loc_outer = m->AdvertisedV4.ip.v4;
-    }
-
-    question->ThisQInterval = -1;       // So we know this tunnel setup has completed
-
-    info = GetAuthInfoForName(m, &tun->dstname);
-    if (!info)
-    {
-        LogMsg("TunnelClientFinish: Could not get AuthInfo for %##s", tun->dstname.c);
-        ReissueBlockedQuestions(&tun->dstname, mDNSfalse);
-        return;
-    }
-    
-    tun->loc_inner = info->AutoTunnelInnerAddress;
-
-    // If we found a v6Relay address for our peer, delete all the v4Tunnels for our peer and
-    // look for existing tunnels to see whether they have the same information for our peer.
-    // If not, delete them and need to create a new tunnel. If they are same, just use the
-    // same tunnel. Do the similar thing if we found a v4Tunnel end point for our peer.
-    TunnelClientDeleteAny(tun, !v6Tunnel);
-    needSetKeys = TunnelClientDeleteMatching(tun, v6Tunnel);
-
-    if (needSetKeys) LogInfo("TunnelClientFinish: New %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
-    else LogInfo("TunnelClientFinish: Reusing exiting %s AutoTunnel for %##s %.16a", (v6Tunnel ? "IPv6" : "IPv4"), tun->dstname.c, &tun->rmt_inner);
-
-    mStatus result = needSetKeys ? AutoTunnelSetKeys(tun, mDNStrue) : mStatus_NoError;
-    LogInfo("TunnelClientFinish: Tunnel setup result %d", result);
-    // Kick off any questions that were held pending this tunnel setup
-    ReissueBlockedQuestions(&tun->dstname, (result == mStatus_NoError) ? mDNStrue : mDNSfalse);
-}
-
-mDNSexport void AutoTunnelCallback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
-    ClientTunnel *tun = (ClientTunnel *)question->QuestionContext;
-    DomainAuthInfo *info;
-
-    LogInfo("AutoTunnelCallback tun %p AddRecord %d rdlength %d qtype %d", tun, AddRecord, answer->rdlength, question->qtype);
-
-    if (!AddRecord) return;
-    mDNS_StopQuery(m, question);
-
-    // If we are looking up the AAAA record for _autotunnel6, don't consider it as failure.
-    // The code below will look for _autotunnel._udp SRV record followed by A record
-    if (tun->tc_state != TC_STATE_AAAA_PEER_RELAY && !answer->rdlength)
+    if (eflags & IFEF_AWDL)
     {
-        LogInfo("AutoTunnelCallback NXDOMAIN %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-        UnlinkAndReissueBlockedQuestions(tun, mDNSfalse);
-        return;
+        // Set SupportsUnicastMDNSResponse false for the AWDL interface since unicast reserves
+        // limited AWDL resources so we don't set the kDNSQClass_UnicastResponse bit in
+        // Bonjour requests over the AWDL interface.
+        i->ifinfo.SupportsUnicastMDNSResponse = mDNSfalse;
+        AWDLInterfaceID = i->ifinfo.InterfaceID;
+        LogInfo("AddInterfaceToList: AWDLInterfaceID = %d", (int) AWDLInterfaceID);
     }
-
-    switch (tun->tc_state)
+    else
     {
-    case TC_STATE_AAAA_PEER:
-        if (question->qtype != kDNSType_AAAA)
-        {
-            LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER", question->qtype);
-        }
-        info = GetAuthInfoForName(m, &tun->dstname);
-        if (!info)
-        {
-            LogMsg("AutoTunnelCallback: Could not get AuthInfo for %##s", tun->dstname.c);
-            UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
-            return;
-        }
-        if (mDNSSameIPv6Address(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
-        {
-            LogInfo("AutoTunnelCallback: suppressing tunnel to self %.16a", &answer->rdata->u.ipv6);
-            UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
-            return;
-        }
-        if (info && mDNSSameIPv6NetworkPart(answer->rdata->u.ipv6, info->AutoTunnelInnerAddress))
-        {
-            LogInfo("AutoTunnelCallback: suppressing tunnel to peer %.16a", &answer->rdata->u.ipv6);
-            UnlinkAndReissueBlockedQuestions(tun, mDNStrue);
-            return;
-        }
-        tun->rmt_inner = answer->rdata->u.ipv6;
-        LogInfo("AutoTunnelCallback:TC_STATE_AAAA_PEER: dst host %.16a", &tun->rmt_inner);
-        if (!mDNSIPv6AddressIsZero(m->AutoTunnelRelayAddr))
-        {
-            LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA");
-            tun->tc_state = TC_STATE_AAAA_PEER_RELAY;
-            question->qtype = kDNSType_AAAA;
-            AssignDomainName(&question->qname, (const domainname*) "\x0C" "_autotunnel6");
-        }
-        else
-        {
-            LogInfo("AutoTunnelCallback: Looking up _autotunnel._udp SRV");
-            tun->tc_state = TC_STATE_SRV_PEER;
-            question->qtype = kDNSType_SRV;
-            AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
-        }
-        AppendDomainName(&question->qname, &tun->dstname);
-        mDNS_StartQuery(m, &tun->q);
-        return;
-    case TC_STATE_AAAA_PEER_RELAY:
-        if (question->qtype != kDNSType_AAAA)
-        {
-            LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_AAAA_PEER_RELAY", question->qtype);
-        }
-        // If it failed, look for the SRV record.
-        if (!answer->rdlength)
-        {
-            LogInfo("AutoTunnelCallback: Looking up _autotunnel6 AAAA failed, trying SRV");
-            tun->tc_state = TC_STATE_SRV_PEER;
-            AssignDomainName(&question->qname, (const domainname*) "\x0B" "_autotunnel" "\x04" "_udp");
-            AppendDomainName(&question->qname, &tun->dstname);
-            question->qtype = kDNSType_SRV;
-            mDNS_StartQuery(m, &tun->q);
-            return;
-        }
-        TunnelClientFinish(question, answer);
-        return;
-    case TC_STATE_SRV_PEER:
-        if (question->qtype != kDNSType_SRV)
-        {
-            LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_SRV_PEER", question->qtype);
-        }
-        LogInfo("AutoTunnelCallback: SRV target name %##s", answer->rdata->u.srv.target.c);
-        tun->tc_state = TC_STATE_ADDR_PEER;
-        AssignDomainName(&tun->q.qname, &answer->rdata->u.srv.target);
-        tun->rmt_outer_port = answer->rdata->u.srv.port;
-        question->qtype = kDNSType_A;
-        mDNS_StartQuery(m, &tun->q);
-        return;
-    case TC_STATE_ADDR_PEER:
-        if (question->qtype != kDNSType_A)
-        {
-            LogMsg("AutoTunnelCallback: Bad question type %d in TC_STATE_ADDR_PEER", question->qtype);
-        }
-        TunnelClientFinish(question, answer);
-        return;
-    default:
-        LogMsg("AutoTunnelCallback: Unknown question %p", question);
+        i->ifinfo.SupportsUnicastMDNSResponse = mDNStrue;
     }
-}
+    i->AppearanceTime  = utc;       // Brand new interface; AppearanceTime is now
+    i->LastSeen        = utc;
+    i->ifa_flags       = ifa->ifa_flags;
+    i->scope_id        = scope_id;
+    i->BSSID           = bssid;
+    i->sa_family       = ifa->ifa_addr->sa_family;
+    i->BPF_fd          = -1;
+    i->BPF_mcfd        = -1;
+    i->BPF_len         = 0;
+    i->Registered      = mDNSNULL;
 
-// Must be called with the lock held
-mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
-{
-    mDNS *const m = &mDNSStorage;
-    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->loc_outer6     = zerov6Addr;
-    p->rmt_inner      = zerov6Addr;
-    p->rmt_outer      = zerov4Addr;
-    p->rmt_outer6     = zerov6Addr;
-    p->rmt_outer_port = zeroIPPort;
-    p->tc_state = TC_STATE_AAAA_PEER;
-    p->next = m->TunnelClients;
-    m->TunnelClients = p;       // We intentionally build list in reverse order
-
-    p->q.InterfaceID      = mDNSInterface_Any;
-    p->q.flags            = 0;
-    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.SuppressUnusable = mDNSfalse;
-    p->q.SearchListIndex  = 0;
-    p->q.AppendSearchDomains = 0;
-    p->q.RetryWithSearchDomains = mDNSfalse;
-    p->q.TimeoutQuestion  = 0;
-    p->q.WakeOnResolve    = 0;
-    p->q.UseBackgroundTrafficClass = mDNSfalse;
-    p->q.ValidationRequired = 0;
-    p->q.ValidatingResponse = 0;
-    p->q.ProxyQuestion      = 0;
-    p->q.qnameOrig        = mDNSNULL;
-    p->q.AnonInfo         = mDNSNULL;
-    p->q.pid              = mDNSPlatformGetPID();
-    p->q.euid             = 0;
-    p->q.QuestionCallback = AutoTunnelCallback;
-    p->q.QuestionContext  = p;
-
-    LogInfo("AddNewClientTunnel start tun %p %##s (%s)%s", p, &q->qname.c, DNSTypeName(q->qtype), q->LongLived ? " LongLived" : "");
-    mDNS_StartQuery_internal(m, &p->q);
-}
+    // MulticastInterface() depends on the "m" and "ifa_flags" values being initialized above.
+    i->ifinfo.McastTxRx   = MulticastInterface(i);
+    // Do this AFTER i->BSSID has been set up
+    i->ifinfo.NetWake  = (eflags & IFEF_EXPENSIVE)? mDNSfalse :  NetWakeInterface(i);
+    GetMAC(&i->ifinfo.MAC, scope_id);
+    if (i->ifinfo.NetWake && !i->ifinfo.MAC.l[0])
+        LogMsg("AddInterfaceToList: Bad MAC address %.6a for %d %s %#a", &i->ifinfo.MAC, scope_id, i->ifinfo.ifname, &ip);
 
-#endif // APPLE_OSX_mDNSResponder
+    *p = i;
+    return(i);
+}
 
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -4769,8 +3933,7 @@ mDNSexport void AddNewClientTunnel(DNSQuestion *const q)
 mDNSlocal mStatus ReorderInterfaceList()
 {
     // Disable Reorder lists till <rdar://problem/30071012> is fixed to prevent spurious name conflicts
-    return (mStatus_NoError);
-
+#ifdef PR_30071012_FIXED
     mDNS *const m = &mDNSStorage;
     nwi_state_t state = nwi_state_copy();
 
@@ -4826,19 +3989,16 @@ mDNSlocal mStatus ReorderInterfaceList()
         m->HostInterfaces = newList;
 
     nwi_state_release(state);
+#endif // PR_30071012_FIXED
     return (mStatus_NoError);
 }
 
 mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
 {
     mDNS *const m = &mDNSStorage;
-    mDNSBool foundav4           = mDNSfalse;
-    mDNSBool foundav6           = mDNSfalse;
-    struct ifaddrs *ifa         = myGetIfAddrs(0);
-    struct ifaddrs *v4Loopback  = NULL;
-    struct ifaddrs *v6Loopback  = NULL;
+    struct ifaddrs *ifa = myGetIfAddrs(0);
     char defaultname[64];
-    int InfoSocket              = socket(AF_INET6, SOCK_DGRAM, 0);
+    int InfoSocket = socket(AF_INET6, SOCK_DGRAM, 0);
     if (InfoSocket < 3 && errno != EAFNOSUPPORT) 
         LogMsg("UpdateInterfaceList: InfoSocket error %d errno %d (%s)", InfoSocket, errno, strerror(errno));
 
@@ -4888,7 +4048,7 @@ mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
                 mDNSPlatformMemCopy(m->PrimaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6);
         }
 
-        if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && !isCoprocessorInterface(InfoSocket, ifa->ifa_name))
+        if (ifa->ifa_flags & IFF_UP && ifa->ifa_addr && !isExcludedInterface(InfoSocket, ifa->ifa_name))
             if (ifa->ifa_addr->sa_family == AF_INET || ifa->ifa_addr->sa_family == AF_INET6)
             {
                 if (!ifa->ifa_netmask)
@@ -4933,34 +4093,13 @@ mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
 
                     if (!(ifru_flags6 & (IN6_IFF_TENTATIVE | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY)))
                     {
-                        if (ifa->ifa_flags & IFF_LOOPBACK)
-                        {
-                            if (ifa->ifa_addr->sa_family == AF_INET) 
-                                v4Loopback = ifa;
-                            else if (sin6->sin6_addr.s6_addr[0] != 0xFD) 
-                                v6Loopback = ifa;
-                        }
-                        else
-                        {
-                            NetworkInterfaceInfoOSX *i = AddInterfaceToList(ifa, utc);
-                            if (i && MulticastInterface(i) && i->ifinfo.Advertise)
-                            {
-                                if (ifa->ifa_addr->sa_family == AF_INET) 
-                                    foundav4 = mDNStrue;
-                                else 
-                                    foundav6 = mDNStrue;
-                            }
-                        }
+                        AddInterfaceToList(ifa, utc);
                     }
                 }
             }
         ifa = ifa->ifa_next;
     }
 
-    // For efficiency, we don't register a loopback interface when other interfaces of that family are available and advertising
-    if (!foundav4 && v4Loopback) AddInterfaceToList(v4Loopback, utc);
-    if (!foundav6 && v6Loopback) AddInterfaceToList(v6Loopback, utc);
-
     if (InfoSocket >= 0) 
         close(InfoSocket);
 
@@ -4987,8 +4126,6 @@ mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
         MakeDomainLabelFromLiteralString(&hostlabel, defaultname);
     }
 
-    mDNSBool namechange = mDNSfalse;
-
     // 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))
@@ -4998,7 +4135,6 @@ mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
         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;
-        namechange = mDNStrue;
     }
 
     if (SameDomainLabelCS(m->p->userhostlabel.c, hostlabel.c))
@@ -5009,16 +4145,6 @@ mDNSlocal mStatus UpdateInterfaceList(mDNSs32 utc)
             LogMsg("User updated Local Hostname from “%#s” to “%#s”", m->p->userhostlabel.c, hostlabel.c);
         m->p->userhostlabel = m->hostlabel = hostlabel;
         mDNS_SetFQDN(m);
-        namechange = mDNStrue;
-    }
-
-    if (namechange)     // If either name has changed, we need to tickle our AutoTunnel state machine to update its registered records
-    {
-#if APPLE_OSX_mDNSResponder
-        DomainAuthInfo *info;
-        for (info = m->AuthInfoList; info; info = info->next)
-            if (info->AutoTunnel) AutoTunnelHostNameChanged(m, info);
-#endif // APPLE_OSX_mDNSResponder
     }
 
     return(mStatus_NoError);
@@ -5054,7 +4180,6 @@ mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
         {
             NetworkInterfaceInfo *const n = &i->ifinfo;
             NetworkInterfaceInfoOSX *primary = SearchForInterfaceByName(i->ifinfo.ifname, AF_UNSPEC);
-            if (!primary) LogMsg("SetupActiveInterfaces ERROR! SearchForInterfaceByName didn't find %s", i->ifinfo.ifname);
 
             if (i->Registered && i->Registered != primary)  // Sanity check
             {
@@ -5087,10 +4212,12 @@ mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
                     activationSpeed = FastActivation;
                     LogInfo("SetupActiveInterfaces: %s DirectLink interface registering", i->ifinfo.ifname);
                 }
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
                 else if (i->Flashing && i->Occulting)
                 {
                     activationSpeed = SlowActivation;
                 }
+#endif
                 else
                 {
                     activationSpeed = NormalActivation;
@@ -5099,7 +4226,9 @@ mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
                 mDNS_RegisterInterface(m, n, activationSpeed);
 
                 if (!mDNSAddressIsLinkLocal(&n->ip)) count++;
-                LogInfo("SetupActiveInterfaces: Registered  %7s(%u) BSSID %.6a Struct addr %p, primary %p, %#a/%d%s%s%s",
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                        "SetupActiveInterfaces: Registered " PUB_S " (%u) BSSID " PRI_MAC_ADDR " Struct addr %p, primary %p,"
+                        " " PRI_IP_ADDR "/%d" PUB_S PUB_S PUB_S,
                         i->ifinfo.ifname, i->scope_id, &i->BSSID, i, primary, &n->ip, CountMaskBits(&n->mask),
                         i->Flashing        ? " (Flashing)"  : "",
                         i->Occulting       ? " (Occulting)" : "",
@@ -5108,7 +4237,7 @@ mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
                 if (!n->McastTxRx)
                 {
                     debugf("SetupActiveInterfaces:   No Tx/Rx on   %5s(%lu) %.6a InterfaceID %p %#a", i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, &n->ip);
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
                     // We join the Bonjour multicast group on Apple embedded platforms ONLY when a client request is active,
                     // so we leave the multicast group here to clear any residual group membership.
                     if (i->sa_family == AF_INET)
@@ -5140,7 +4269,7 @@ mDNSlocal int SetupActiveInterfaces(mDNSs32 utc)
                                 LogMsg("setsockopt - IPV6_LEAVE_GROUP error %d errno %d (%s) group %.16a on %u", err, errno, strerror(errno), &i6mr.ipv6mr_multiaddr, i6mr.ipv6mr_interface);
                         }
                     }
-#endif // TARGET_OS_EMBEDDED
+#endif // TARGET_OS_IPHONE
                 }
                 else
                 {
@@ -5251,10 +4380,12 @@ mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
                     activationSpeed = FastActivation;
                     LogInfo("ClearInactiveInterfaces: %s DirectLink interface deregistering", i->ifinfo.ifname);
                 }
+#if MDNSRESPONDER_SUPPORTS(APPLE, SLOW_ACTIVATION)
                 else if (i->Flashing && i->Occulting)
                 {
                     activationSpeed = SlowActivation;
                 }
+#endif
                 else
                 {
                     activationSpeed = NormalActivation;
@@ -5282,7 +4413,7 @@ mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
         if (!i->Exists)
         {
             if (i->LastSeen == utc) i->LastSeen = utc - 1;
-            const mDNSBool delete = (i->isAWDL || (NumCacheRecordsForInterfaceID(m, i->ifinfo.InterfaceID) == 0)) && (utc - i->LastSeen >= 60);
+            const mDNSBool delete = ((utc - i->LastSeen) >= 60) ? mDNStrue : mDNSfalse;
             LogInfo("ClearInactiveInterfaces: %-13s %5s(%lu) %.6a InterfaceID %p(%p) %#a/%d Age %d%s", delete ? "Deleting" : "Holding",
                     i->ifinfo.ifname, i->scope_id, &i->BSSID, i->ifinfo.InterfaceID, i,
                     &i->ifinfo.ip, CountMaskBits(&i->ifinfo.mask), utc - i->LastSeen,
@@ -5304,7 +4435,7 @@ mDNSlocal int ClearInactiveInterfaces(mDNSs32 utc)
 
 mDNSlocal void AppendDNameListElem(DNameListElem ***List, mDNSu32 uid, domainname *name)
 {
-    DNameListElem *dnle = (DNameListElem*) mallocL("DNameListElem/AppendDNameListElem", sizeof(DNameListElem));
+    DNameListElem *dnle = (DNameListElem*) callocL("DNameListElem/AppendDNameListElem", sizeof(*dnle));
     if (!dnle) LogMsg("ERROR: AppendDNameListElem: memory exhausted");
     else
     {
@@ -5378,21 +4509,6 @@ mDNSlocal void FinalizeSearchDomainHash(MD5_CTX *sdc)
     else { LogInfo("FinalizeSearchDomains: The hash is same"); }
 }
 
-mDNSexport const char *DNSScopeToString(mDNSu32 scope)
-{
-    switch (scope)
-    {
-        case kScopeNone:
-            return "Unscoped";
-        case kScopeInterfaceID:
-            return "InterfaceScoped";
-        case kScopeServiceID:
-            return "ServiceScoped";
-        default:
-            return "Unknown";
-    }
-}
-
 mDNSlocal void ConfigSearchDomains(dns_resolver_t *resolver, mDNSInterfaceID interfaceId, mDNSu32 scope,  MD5_CTX *sdc, uint64_t generation)
 {
     const char *scopeString = DNSScopeToString(scope);
@@ -5474,80 +4590,46 @@ mDNSlocal void ConfigNonUnicastResolver(dns_resolver_t *r)
     }
 }
 
-#if !defined(NWI_IFSTATE_FLAGS_HAS_CLAT46)
-#define NWI_IFSTATE_FLAGS_HAS_CLAT46    0x0040
-#endif
-
-mDNSlocal mDNSBool NWIInterfaceHasCLAT46(nwi_state_t state, uint32_t ifIndex)
-{
-    char ifNameBuf[IFNAMSIZ + 1];
-    const char *ifNamePtr = if_indextoname(ifIndex, ifNameBuf);
-    if (!ifNamePtr) return(mDNSfalse);
-
-    const nwi_ifstate_t ifState = nwi_state_get_ifstate(state, ifNamePtr);
-    if (!ifState) return(mDNSfalse);
-
-    const nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifState);
-    return((flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) ? mDNStrue : mDNSfalse);
-}
-
-mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mDNSu32 scope, mDNSu32 resGroupID)
+mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interfaceID, mDNSu32 scope, mDNSu32 resGroupID)
 {
-    int n;
-    domainname d;
-    int serviceID = 0;
-    mDNSBool cellIntf = mDNSfalse;
-    mDNSBool reqA, reqAAAA;
-    NetworkInterfaceInfoOSX *info;
-    mDNSBool isExpensive;
-    mDNSBool isCLAT46;
-
-    if (!r->domain || !*r->domain) 
+    domainname domain;
+    if (!r->domain || (*r->domain == '\0'))
     {
-        d.c[0] = 0;
+        domain.c[0] = 0;
     }
-    else if (!MakeDomainNameFromDNSNameString(&d, r->domain))
+    else if (!MakeDomainNameFromDNSNameString(&domain, r->domain))
     { 
         LogMsg("ConfigDNSServers: bad domain %s", r->domain); 
         return;
     }
     // Parse the resolver specific attributes that affects all the DNS servers.
-    if (scope == kScopeServiceID)
-    {
-        serviceID = r->service_identifier;
-    }
-
+    const int32_t serviceID = (scope == kScopeServiceID) ? r->service_identifier : 0;
+
+    const mdns_interface_monitor_t monitor = GetInterfaceMonitorForIndex((uint32_t)((uintptr_t)interfaceID));
+    const mDNSBool isExpensive   = (monitor && mdns_interface_monitor_is_expensive(monitor))   ? mDNStrue : mDNSfalse;
+    const mDNSBool isConstrained = (monitor && mdns_interface_monitor_is_constrained(monitor)) ? mDNStrue : mDNSfalse;
+    const mDNSBool isCLAT46      = (monitor && mdns_interface_monitor_is_clat46(monitor))      ? mDNStrue : mDNSfalse;
+    const mDNSBool usableA       = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS)           ? mDNStrue : mDNSfalse;
+    const mDNSBool usableAAAA    = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS)        ? mDNStrue : mDNSfalse;
 #if TARGET_OS_IPHONE
-    cellIntf = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) ? mDNStrue : mDNSfalse;
+    const mDNSBool isCell        = (r->reach_flags & kSCNetworkReachabilityFlagsIsWWAN)        ? mDNStrue : mDNSfalse;
+#else
+    const mDNSBool isCell        = mDNSfalse;
 #endif
-    reqA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS ? mDNStrue : mDNSfalse);
-    reqAAAA = (r->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS ? mDNStrue : mDNSfalse);
-    info = IfindexToInterfaceInfoOSX(interface);
-    isExpensive = (info && info->isExpensive) ? mDNStrue : mDNSfalse;
-    if (mDNSStorage.p->NWIState && interface)
-    {
-        const uint32_t ifIndex = (uint32_t)((uintptr_t)interface);
-        isCLAT46 = NWIInterfaceHasCLAT46(mDNSStorage.p->NWIState, ifIndex);
-    }
-    else
-    {
-        isCLAT46 = mDNSfalse;
-    }
 
-    for (n = 0; n < r->n_nameserver; n++)
+    const mDNSIPPort port = (r->port != 0) ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort;
+    for (int32_t i = 0; i < r->n_nameserver; i++)
     {
-        mDNSAddr saddr;
-        DNSServer *s;
+        const int family = r->nameserver[i]->sa_family;
+        if ((family != AF_INET) && (family != AF_INET6)) continue;
 
-        if (r->nameserver[n]->sa_family != AF_INET && r->nameserver[n]->sa_family != AF_INET6)
-            continue;
-        
-        if (SetupAddr(&saddr, r->nameserver[n]))
+        mDNSAddr saddr;
+        if (SetupAddr(&saddr, r->nameserver[i]))
         {
             LogMsg("ConfigDNSServers: Bad address");
             continue;
         }
-        
+
         // The timeout value is for all the DNS servers in a given resolver, hence we pass
         // the timeout value only for the first DNSServer. If we don't have a value in the
         // resolver, then use the core's default value
@@ -5555,12 +4637,13 @@ mDNSlocal void ConfigDNSServers(dns_resolver_t *r, mDNSInterfaceID interface, mD
         // Note: this assumes that when the core picks a list of DNSServers for a question,
         // it takes the sum of all the timeout values for all DNS servers. By doing this, it
         // tries all the DNS servers in a specified timeout
-        s = mDNS_AddDNSServer(&mDNSStorage, &d, interface, serviceID, &saddr, r->port ? mDNSOpaque16fromIntVal(r->port) : UnicastDNSPort, scope,
-                              (n == 0 ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0), cellIntf, isExpensive, isCLAT46,
-                              resGroupID, reqA, reqAAAA, mDNStrue);
+        DNSServer *s = mDNS_AddDNSServer(&mDNSStorage, &domain, interfaceID, serviceID, &saddr, port, scope,
+            (i == 0) ? (r->timeout ? r->timeout : DEFAULT_UDNS_TIMEOUT) : 0, isCell, isExpensive, isConstrained, isCLAT46,
+            resGroupID, usableA, usableAAAA, mDNStrue);
         if (s)
         {
-            LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s", DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), d.c);
+            LogInfo("ConfigDNSServers(%s): DNS server %#a:%d for domain %##s",
+                DNSScopeToString(scope), &s->addr, mDNSVal16(s->port), domain.c);
         }
     }
 }
@@ -5637,10 +4720,10 @@ mDNSlocal void ConfigResolvers(dns_config_t *config, mDNSu32 scope, mDNSBool set
     }
 }
 
-#if APPLE_OSX_mDNSResponder
-mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+mDNSlocal mDNSBool QuestionValidForDNSTrigger(const DNSQuestion *q)
 {
-    if (QuerySuppressed(q))
+    if (q->Suppressed)
     {
         debugf("QuestionValidForDNSTrigger: Suppressed: %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
         return mDNSfalse;
@@ -5659,13 +4742,11 @@ mDNSlocal mDNSBool QuestionValidForDNSTrigger(DNSQuestion *q)
     }
     return mDNStrue;
 }
-#endif
 
 // This function is called if we are not delivering unicast answers to "A" or "AAAA" questions.
 // We set our state appropriately so that if we start receiving answers, trigger the
 // upper layer to retry DNS questions.
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
+mDNSexport void mDNSPlatformUpdateDNSStatus(const DNSQuestion *q)
 {
     mDNS *const m = &mDNSStorage;
     if (!QuestionValidForDNSTrigger(q))
@@ -5688,7 +4769,7 @@ mDNSexport void mDNSPlatformUpdateDNSStatus(DNSQuestion *q)
             DNSTypeName(q->qtype));
     }
 }
-#endif
+#endif  // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
 
 mDNSlocal void AckConfigd(dns_config_t *config)
 {
@@ -5699,10 +4780,10 @@ mDNSlocal void AckConfigd(dns_config_t *config)
     _dns_configuration_ack(config, "com.apple.mDNSResponder");
 }
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
 // If v4q is non-NULL, it means we have received some answers for "A" type questions
 // If v6q is non-NULL, it means we have received some answers for "AAAA" type questions
-#if APPLE_OSX_mDNSResponder
-mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
+mDNSexport void mDNSPlatformTriggerDNSRetry(const DNSQuestion *v4q, const DNSQuestion *v6q)
 {
     mDNS *const m = &mDNSStorage;
     mDNSBool trigger = mDNSfalse;
@@ -5777,7 +4858,9 @@ mDNSexport void mDNSPlatformTriggerDNSRetry(DNSQuestion *v4q, DNSQuestion *v6q)
         }
     }
 }
+#endif  // MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
 mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
 {
     // Record the so-called "primary" domain, which we use as a hint to tell if the user is on a network set up
@@ -5801,7 +4884,7 @@ mDNSlocal void SetupActiveDirectoryDomain(dns_config_t *config)
     }
     else
     {
-        AssignDomainName(&ActiveDirectoryPrimaryDomain, (const domainname *)"");
+        AssignConstStringDomainName(&ActiveDirectoryPrimaryDomain, "");
         ActiveDirectoryPrimaryDomainLabelCount = 0;
         ActiveDirectoryPrimaryDomainServer = zeroAddr;
     }
@@ -5889,42 +4972,11 @@ mDNSlocal void SetupDDNSDomains(domainname *const fqdn, DNameListElem **RegDomai
         }
         CFRelease(ddnsdict);
     }
-#if MDNSRESPONDER_BTMM_SUPPORT
-    if (RegDomains)
-    {
-        CFDictionaryRef btmm = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BackToMyMac);
-        if (btmm)
-        {
-            CFIndex size = CFDictionaryGetCount(btmm);
-            const void *key[size];
-            const void *val[size];
-            CFDictionaryGetKeysAndValues(btmm, key, val);
-            for (i = 0; i < size; i++)
-            {
-                LogInfo("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])
-                    {
-                        LogInfo("BackToMyMac %d %d %##s", i, uid, d.c);
-                        AppendDNameListElem(&RegDomains, uid, &d);
-                    }
-                }
-            }
-            CFRelease(btmm);
-        }
-    }
-#endif
 }
 
 // Returns mDNSfalse, if it does not set the configuration i.e., if the DNS configuration did not change
 mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn,
-    DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
+                                             DNameListElem **RegDomains, DNameListElem **BrowseDomains, mDNSBool ackConfig)
 {
     mDNS *const m = &mDNSStorage;
     MD5_CTX sdc;    // search domain context
@@ -6017,21 +5069,50 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setse
             // on every update; and only updating when the generation number changes.
 
             // If this is a DNS server update and the configuration hasn't changed, then skip update
-            if (setservers &&  m->p->LastConfigGeneration == config->generation)
+            if (setservers && !m->p->if_interface_changed && m->p->LastConfigGeneration == config->generation)
             {
                 LogInfo("mDNSPlatformSetDNSConfig(setservers): generation number %llu same, not processing", config->generation);
                 dns_configuration_free(config);
                 SetupDDNSDomains(fqdn, RegDomains, BrowseDomains);
                 return mDNSfalse;
             }
-#if APPLE_OSX_mDNSResponder
+            if (setservers) {
+                // Must check if setservers is true, because mDNSPlatformSetDNSConfig can be called for multiple times
+                // with setservers equals to false. If setservers is false, we will end up with clearing if_interface_changed
+                // without really updating the server.
+                m->p->if_interface_changed = mDNSfalse;
+            }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
             SetupActiveDirectoryDomain(config);
 #endif
-
             ConfigResolvers(config, kScopeNone, setsearch, setservers, &sdc);
             ConfigResolvers(config, kScopeInterfaceID, setsearch, setservers, &sdc);
             ConfigResolvers(config, kScopeServiceID, setsearch, setservers, &sdc);
 
+            const CFIndex n = m->p->InterfaceMonitors ? CFArrayGetCount(m->p->InterfaceMonitors) : 0;
+            for (CFIndex i = n - 1; i >= 0; i--)
+            {
+                mdns_interface_monitor_t monitor;
+                monitor = (mdns_interface_monitor_t) CFArrayGetValueAtIndex(m->p->InterfaceMonitors, i);
+                const uint32_t ifIndex = mdns_interface_monitor_get_interface_index(monitor);
+                DNSServer *server;
+                for (server = m->DNSServers; server; server = server->next)
+                {
+                    if ((((uintptr_t)server->interface) == ifIndex) && !(server->flags & DNSServerFlag_Delete))
+                    {
+                        break;
+                    }
+                }
+                if (!server)
+                {
+                    mdns_retain(monitor);
+                    CFArrayRemoveValueAtIndex(m->p->InterfaceMonitors, i);
+                    mdns_interface_monitor_invalidate(monitor);
+                    mdns_release(monitor);
+                }
+            }
+
             // Acking provides a hint to other processes that the current DNS configuration has completed
             // its update.  When configd receives the ack, it publishes a notification.
             // Applications monitoring the notification then know when to re-issue their DNS queries
@@ -6176,7 +5257,7 @@ mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const
     else
     {
         const CFNumberRef StatusVals[1] = { CFNumberCreate(NULL, kCFNumberSInt32Type, &status) };
-        if (!StatusVals[0]) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
+        if (StatusVals[0] == NULL) LogMsg("SetDDNSNameStatus: CFNumberCreate(%d) failed", status);
         else
         {
             const CFDictionaryRef HostVals[1] = { CFDictionaryCreate(NULL, (void*)StatusKeys, (void*)StatusVals, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) };
@@ -6201,160 +5282,6 @@ mDNSexport void mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const
     }
 }
 
-#if MDNSRESPONDER_BTMM_SUPPORT
-#if !NO_AWACS
-
-// checks whether a domain is present in Setup:/Network/BackToMyMac. Just because there is a key in the
-// keychain for a domain, it does not become a valid BTMM domain. If things get inconsistent, this will
-// help catch it
-mDNSlocal mDNSBool IsBTMMDomain(domainname *d)
-{
-    SCDynamicStoreRef store = SCDynamicStoreCreate(NULL, CFSTR("mDNSResponder:IsBTMMDomain"), NULL, NULL);
-    if (!store)
-    {
-        LogMsg("IsBTMMDomain: SCDynamicStoreCreate failed: %s", SCErrorString(SCError()));
-        return mDNSfalse;
-    }
-    CFDictionaryRef btmm = SCDynamicStoreCopyValue(store, NetworkChangedKey_BackToMyMac);
-    if (btmm)
-    {
-        CFIndex size = CFDictionaryGetCount(btmm);
-        char buf[MAX_ESCAPED_DOMAIN_NAME];  // Max legal C-string name, including terminating NUL
-        const void *key[size];
-        const void *val[size];
-        domainname dom;
-        int i;
-        CFDictionaryGetKeysAndValues(btmm, key, val);
-        for (i = 0; i < size; i++)
-        {
-            LogInfo("BackToMyMac %d", i);
-            if (!CFStringGetCString(key[i], buf, sizeof(buf), kCFStringEncodingUTF8))
-                LogMsg("IsBTMMDomain: ERROR!! Can't read BackToMyMac %d key %s", i, buf);
-            else
-            {
-                mDNSu32 uid = atoi(buf);
-                if (!CFStringGetCString(val[i], buf, sizeof(buf), kCFStringEncodingUTF8))
-                    LogMsg("IsBTMMDomain: Can't read BackToMyMac %d val %s", i, buf);
-                else if (MakeDomainNameFromDNSNameString(&dom, buf) && dom.c[0])
-                {
-                    if (SameDomainName(&dom, d))
-                    {
-                        LogInfo("IsBTMMDomain: Domain %##s is a btmm domain, uid %u", d->c, uid);
-                        CFRelease(btmm);
-                        CFRelease(store);
-                        return mDNStrue;
-                    }
-                }
-            }
-        }
-        CFRelease(btmm);
-    }
-    CFRelease(store);
-    LogInfo("IsBTMMDomain: Domain %##s not a btmm domain", d->c);
-    return mDNSfalse;
-}
-
-// Appends data to the buffer
-mDNSlocal int AddOneItem(char *buf, int bufsz, char *data, int *currlen)
-{
-    int len;
-
-    len = strlcpy(buf + *currlen, data, bufsz - *currlen);
-    if (len >= (bufsz - *currlen))
-    {
-        // if we have exceeded the space in buf, it has already been NULL terminated
-        // and we have nothing more to do. Set currlen to the last byte so that the caller
-        // knows to do the right thing
-        LogMsg("AddOneItem: Exceeded the max buffer size currlen %d, len %d", *currlen, len);
-        *currlen = bufsz - 1;
-        return -1;
-    }
-    else { (*currlen) += len; }
-
-    buf[*currlen] = ',';
-    if (*currlen >= bufsz)
-    {
-        LogMsg("AddOneItem: ERROR!! How can currlen be %d", *currlen);
-        *currlen = bufsz - 1;
-        buf[*currlen] = 0;
-        return -1;
-    }
-    // if we have filled up the buffer exactly, then there is no more work to do
-    if (*currlen == bufsz - 1) { buf[*currlen] = 0; return -1; }
-    (*currlen)++;
-    return *currlen;
-}
-
-// If we have at least one BTMM domain, then trigger the connection to the relay. If we have no
-// BTMM domains, then bring down the connection to the relay.
-mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
-{
-    DomainAuthInfo *BTMMDomain = mDNSNULL;
-    DomainAuthInfo *FoundInList;
-    static mDNSBool AWACSDConnected = mDNSfalse;
-    char AllUsers[1024];    // maximum size of mach message
-    char AllPass[1024];     // maximum size of mach message
-    char username[MAX_DOMAIN_LABEL + 1];
-    int currulen = 0;
-    int currplen = 0;
-
-    // if a domain is being deleted, we want to send a disconnect. If we send a disconnect now,
-    // we may not be able to send the dns queries over the relay connection which may be needed
-    // for sending the deregistrations. Hence, we need to delay sending the disconnect. But we
-    // need to make sure that we send the disconnect before attempting the next connect as the
-    // awacs connections are redirected based on usernames.
-    //
-    // For now we send a disconnect immediately. When we start sending dns queries over the relay
-    // connection, we will need to fix this.
-
-    for (FoundInList = m->AuthInfoList; FoundInList; FoundInList = FoundInList->next)
-        if (!FoundInList->deltime && FoundInList->AutoTunnel && IsBTMMDomain(&FoundInList->domain))
-        {
-            // We need the passwd from the first domain.
-            BTMMDomain = FoundInList;
-            ConvertDomainLabelToCString_unescaped((domainlabel *)BTMMDomain->domain.c, username);
-            LogInfo("UpdateBTMMRelayConnection: user %s for domain %##s", username, BTMMDomain->domain.c);
-            if (AddOneItem(AllUsers, sizeof(AllUsers), username, &currulen) == -1) break;
-            if (AddOneItem(AllPass, sizeof(AllPass), BTMMDomain->b64keydata, &currplen) == -1) break;
-        }
-
-    if (BTMMDomain)
-    {
-        // In the normal case (where we neither exceed the buffer size nor write bytes that
-        // fit exactly into the buffer), currulen/currplen should be a different size than
-        // (AllUsers - 1) / (AllPass - 1). In that case, we need to override the "," with a NULL byte.
-
-        if (currulen != (int)(sizeof(AllUsers) - 1)) AllUsers[currulen - 1] = 0;
-        if (currplen != (int)(sizeof(AllPass) - 1)) AllPass[currplen - 1] = 0;
-
-        LogInfo("UpdateBTMMRelayConnection: AWS_Connect for user %s", AllUsers);
-        AWACS_Connect(AllUsers, AllPass, "hello.connectivity.me.com");
-        AWACSDConnected = mDNStrue;
-    }
-    else
-    {
-        // Disconnect only if we connected previously
-        if (AWACSDConnected)
-        {
-            LogInfo("UpdateBTMMRelayConnection: AWS_Disconnect");
-            AWACS_Disconnect();
-            AWACSDConnected = mDNSfalse;
-        }
-        else LogInfo("UpdateBTMMRelayConnection: Not calling AWS_Disconnect");
-    }
-}
-#else
-mDNSlocal void UpdateBTMMRelayConnection(mDNS *const m)
-{
-    (void) m; // Unused
-    LogInfo("UpdateBTMMRelayConnection: AWACS connection not started, no AWACS library");
-}
-#endif // ! NO_AWACS
-
-mDNSlocal void ProcessConndConfigChanges(void);
-
-#endif // MDNSRESPONDER_BTMM_SUPPORT
-
 // MUST be called holding the lock
 mDNSlocal void SetDomainSecrets_internal(mDNS *m)
 {
@@ -6362,7 +5289,6 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
         (void) m;
     LogMsg("Note: SetDomainSecrets: no keychain support");
 #else
-    mDNSBool haveAutoTunnels = mDNSfalse;
 
     LogInfo("SetDomainSecrets");
 
@@ -6375,18 +5301,6 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
     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)
-        {
-            LogInfo("SetDomainSecrets: tunnel to %##s marked for deletion", client->dstname.c);
-            client->MarkedForDeletion = mDNStrue;
-        }
-    }
-#endif // APPLE_OSX_mDNSResponder
-
     // String Array used to write list of private domains to Dynamic Store
     CFMutableArrayRef sa = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
     if (!sa) { LogMsg("SetDomainSecrets: CFArrayCreateMutable failed"); return; }
@@ -6403,7 +5317,6 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
         // Iterate through the secrets
         for (i = 0; i < ArrayCount; ++i)
         {
-            mDNSBool AutoTunnel;
             int j, offset;
             CFArrayRef entry = CFArrayGetValueAtIndex(secrets, i);
             if (CFArrayGetTypeID() != CFGetTypeID(entry) || itemsPerEntry != CFArrayGetCount(entry))
@@ -6414,26 +5327,19 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
 
             // The names have already been vetted by the helper, but checking them again here helps humans and automated tools verify correctness
 
-            // Max legal domainname as C-string, including space for btmmprefix and terminating NUL
+            // Max legal domainname as C-string, including space for dnsprefix and terminating NUL
             // Get DNS domain this key is for (kmDNSKcWhere)
-            char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(btmmprefix)];
+            char stringbuf[MAX_ESCAPED_DOMAIN_NAME + sizeof(dnsprefix)];
             data = CFArrayGetValueAtIndex(entry, kmDNSKcWhere);
             if (CFDataGetLength(data) >= (int)sizeof(stringbuf))
             { LogMsg("SetDomainSecrets: Bad kSecServiceItemAttr length %d", CFDataGetLength(data)); continue; }
             CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (UInt8 *)stringbuf);
             stringbuf[CFDataGetLength(data)] = '\0';
 
-            AutoTunnel = mDNSfalse;
             offset = 0;
             if (!strncmp(stringbuf, dnsprefix, strlen(dnsprefix)))
                 offset = strlen(dnsprefix);
-#if MDNSRESPONDER_BTMM_SUPPORT
-            else if (!strncmp(stringbuf, btmmprefix, strlen(btmmprefix)))
-            {
-                AutoTunnel = mDNStrue;
-                offset = strlen(btmmprefix);
-            }
-#endif
+
             domainname domain;
             if (!MakeDomainNameFromDNSNameString(&domain, stringbuf + offset)) { LogMsg("SetDomainSecrets: bad key domain %s", stringbuf); continue; }
 
@@ -6504,21 +5410,6 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
             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))
-                    {
-                        LogInfo("SetDomainSecrets: tunnel to %##s no longer marked for deletion", client->dstname.c);
-                        client->MarkedForDeletion = 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!
             //LogInfo("SetDomainSecrets: domain %##s keyname %##s key %s hostname %##s port %d", &domain.c, &keyname.c, stringbuf, hostname.c, (port.b[0] << 8 | port.b[1]));
@@ -6526,17 +5417,13 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
 
             // 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));
+                ptr = (DomainAuthInfo*) callocL("DomainAuthInfo", sizeof(*ptr));
                 if (!ptr) { LogMsg("SetDomainSecrets: No memory"); continue; }
             }
 
-            //LogInfo("SetDomainSecrets: %d of %d %##s", i, ArrayCount, &domain);
-
-            // It is an AutoTunnel if the keychains tells us so (with btmm prefix) or if it is a TunnelModeDomain
-            if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port, AutoTunnel) == mStatus_BadParamErr)
+            if (mDNS_SetSecretForDomain(m, ptr, &domain, &keyname, stringbuf, &hostname, &port) == mStatus_BadParamErr)
             {
                 if (!FoundInList) mDNSPlatformMemFree(ptr);     // If we made a new DomainAuthInfo here, and it turned out bad, dispose it immediately
                 continue;
@@ -6560,67 +5447,6 @@ mDNSlocal void SetDomainSecrets_internal(mDNS *m)
     }
     CFRelease(sa);
 
-#if APPLE_OSX_mDNSResponder
-    {
-        // clean up ClientTunnels
-        ClientTunnel **pp = &m->TunnelClients;
-        while (*pp)
-        {
-            if ((*pp)->MarkedForDeletion)
-            {
-                ClientTunnel *cur = *pp;
-                LogInfo("SetDomainSecrets: removing client %p %##s from list", cur, cur->dstname.c);
-                if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
-                AutoTunnelSetKeys(cur, mDNSfalse);
-                *pp = cur->next;
-                freeL("ClientTunnel", cur);
-            }
-            else
-                pp = &(*pp)->next;
-        }
-
-        mDNSBool needAutoTunnelNAT = mDNSfalse;
-        DomainAuthInfo *info;
-        for (info = m->AuthInfoList; info; info = info->next)
-        {
-            if (info->AutoTunnel)
-            {
-                UpdateAutoTunnelDeviceInfoRecord(m, info);
-                UpdateAutoTunnelHostRecord(m, info);
-                UpdateAutoTunnelServiceRecords(m, info);
-                UpdateAutoTunnel6Record(m, info);
-                if (info->deltime)
-                {
-                    if (info->AutoTunnelServiceStarted) info->AutoTunnelServiceStarted = mDNSfalse;
-                }
-                else if (info->AutoTunnelServiceStarted)
-                    needAutoTunnelNAT = true;
-
-                   UpdateAutoTunnelDomainStatus(info);
-            }
-        }
-
-        // If the AutoTunnel NAT-T is no longer needed (& is currently running), stop it
-        if (!needAutoTunnelNAT && m->AutoTunnelNAT.clientContext)
-        {
-            // stop the NAT operation, reset port, cleanup state
-            mDNS_StopNATOperation_internal(m, &m->AutoTunnelNAT);
-            m->AutoTunnelNAT.ExternalAddress = zerov4Addr;
-            m->AutoTunnelNAT.NewAddress      = zerov4Addr;
-            m->AutoTunnelNAT.ExternalPort    = zeroIPPort;
-            m->AutoTunnelNAT.RequestedPort   = zeroIPPort;
-            m->AutoTunnelNAT.Lifetime        = 0;
-            m->AutoTunnelNAT.Result          = mStatus_NoError;
-            m->AutoTunnelNAT.clientContext   = mDNSNULL;
-        }
-
-        UpdateAnonymousRacoonConfig(m);     // Determine whether we need racoon to accept incoming connections
-#if MDNSRESPONDER_BTMM_SUPPORT
-        ProcessConndConfigChanges();       // Update AutoTunnelInnerAddress values and default ipsec policies as necessary
-#endif
-    }
-#endif // APPLE_OSX_mDNSResponder
-
     CheckSuppressUnusableQuestions(m);
 
 #endif /* NO_SECURITYFRAMEWORK */
@@ -6653,7 +5479,7 @@ mDNSlocal void SetLocalDomains(void)
 
 mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
 {
-       
+    
     CFDictionaryRef dict = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_PowerSettings);
     if (!dict)
     {
@@ -6662,11 +5488,11 @@ mDNSlocal void GetCurrentPMSetting(const CFStringRef name, mDNSs32 *val)
     else
     {
         CFNumberRef number = CFDictionaryGetValue(dict, name);
-        if (!number || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
+        if ((number == NULL) || CFGetTypeID(number) != CFNumberGetTypeID() || !CFNumberGetValue(number, kCFNumberSInt32Type, val))
             *val = 0;
         CFRelease(dict);
     }
-       
+    
 }
 
 #if APPLE_OSX_mDNSResponder
@@ -6678,7 +5504,7 @@ mDNSlocal void SPSStatusPutNumber(CFMutableDictionaryRef dict, const mDNSu8* con
 {
     mDNSu8 tmp = (ptr[0] - '0') * 10 + ptr[1] - '0';
     CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt8Type, &tmp);
-    if (!num)
+    if (num == NULL)
         LogMsg("SPSStatusPutNumber: Could not create CFNumber");
     else
     {
@@ -6706,7 +5532,7 @@ mDNSlocal CFMutableDictionaryRef SPSCreateDict(const mDNSu8* const ptr)
 
     mDNSu32 tmp = SPSMetric(ptr);
     CFNumberRef num = CFNumberCreate(NULL, kCFNumberSInt32Type, &tmp);
-    if (!num)
+    if (num == NULL)
         LogMsg("SPSCreateDict: Could not create CFNumber");
     else
     {
@@ -6816,7 +5642,7 @@ mDNSlocal mDNSs32 GetSystemSleepTimerSetting(void)
         if (dict)
         {
             CFNumberRef number = CFDictionaryGetValue(dict, CFSTR("System Sleep Timer"));
-            if (number) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
+            if (number != NULL) CFNumberGetValue(number, kCFNumberSInt32Type, &val);
             CFRelease(dict);
         }
         CFRelease(store);
@@ -6917,22 +5743,14 @@ mDNSlocal mDNSu32 GetPortArray(int trans, mDNSIPPort *portarray)
 
                 // Add it into the port list only if it not already present in the list
                 if (i >= count)
-                    portarray[count++] = rr->resrec.rdata->u.srv.port;
-            }
-        }
-    }
-
-    // If Back to My Mac is on, also wake for packets to the IPSEC UDP port (4500)
-    if (trans == mDNSTransport_UDP && m->AutoTunnelNAT.clientContext)
-    {
-        LogSPS("GetPortArray Back to My Mac at %u", count);
-        if (portarray) portarray[count] = IPSECPort;
-        count++;
+                    portarray[count++] = rr->resrec.rdata->u.srv.port;
+            }
+        }
     }
     return(count);
 }
 
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
 mDNSlocal mDNSBool SupportsTCPKeepAlive()
 {
     IOReturn  ret      = kIOReturnSuccess;
@@ -6963,8 +5781,7 @@ mDNSlocal mDNSBool OnBattery(void)
     LogSPS("%s: The system is on %s", __func__, (result)? "Battery" : "AC Power");
     return result;
 }
-
-#endif // !TARGET_OS_EMBEDDED
+#endif
 
 #define TfrRecordToNIC(RR) \
     ((!(RR)->resrec.InterfaceID && ((RR)->ForceMCast || IsLocalDomain((RR)->resrec.name))))
@@ -6982,7 +5799,7 @@ mDNSlocal mDNSu32 CountProxyRecords(uint32_t *const numbytes, mDNSBool TCPKAOnly
     {
         if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
         {
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
             isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
             // Skip over all other records if we are registering TCP KeepAlive records only
             // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive.
@@ -7021,11 +5838,12 @@ mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes,
     {
         if (!(rr->AuthFlags & AuthFlagsWakeOnly) && rr->resrec.RecordType > kDNSRecordTypeDeregistering)
         {
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
             const mDNSBool isKeepAliveRecord = mDNS_KeepaliveRecord(&rr->resrec);
 
             // Skip over all other records if we are registering TCP KeepAlive records only
             // Skip over TCP KeepAlive records if the policy prohibits it or if the interface does not support TCP Keepalive
+            // supportsTCPKA is set to true if both policy and interface allow TCP Keepalive
             if ((TCPKAOnly && !isKeepAliveRecord) || (isKeepAliveRecord && !supportsTCPKA))
                 continue;
 
@@ -7049,8 +5867,7 @@ mDNSlocal void GetProxyRecords(DNSMessage *const msg, uint32_t *const numbytes,
             (void) intf;          // unused
             (void) TCPKAOnly;     // unused
             (void) supportsTCPKA; // unused
-#endif // APPLE_OSX_mDNSResponder
-
+#endif
             if (TfrRecordToNIC(rr))
             {
                 records[count].sixtyfourbits = zeroOpaque64;
@@ -7087,7 +5904,7 @@ mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool
     mDNSBool     supportsTCPKA = mDNSfalse;
     io_service_t service       = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, intf->ifname));
 
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
     // Check if the interface supports TCP Keepalives and the system policy says it is ok to offload TCP Keepalive records
     supportsTCPKA = (InterfaceSupportsKeepAlive(intf) && SupportsTCPKeepAlive()) ? mDNStrue : mDNSfalse;
     if (!offloadKeepAlivesOnly)
@@ -7139,10 +5956,10 @@ mDNSexport mStatus ActivateLocalProxy(NetworkInterfaceInfo *const intf, mDNSBool
                 cmd.numRRRecords  = CountProxyRecords(&cmd.rrBufferSize, TCPKAOnly, supportsTCPKA);
                 cmd.compression   = sizeof(DNSMessageHeader);
 
-                DNSMessage *msg   = (DNSMessage *)mallocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
-                cmd.rrRecords.ptr = cmd.numRRRecords ? mallocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr))     : NULL;
-                cmd.udpPorts.ptr  = cmd.numUDPPorts  ? mallocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts  * sizeof(mDNSIPPort)) : NULL;
-                cmd.tcpPorts.ptr  = cmd.numTCPPorts  ? mallocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts  * sizeof(mDNSIPPort)) : NULL;
+                DNSMessage *msg   = (DNSMessage *) callocL("mDNSOffloadCmd msg", sizeof(DNSMessageHeader) + cmd.rrBufferSize);
+                cmd.rrRecords.ptr = cmd.numRRRecords ? callocL("mDNSOffloadCmd rrRecords", cmd.numRRRecords * sizeof(FatPtr))     : NULL;
+                cmd.udpPorts.ptr  = cmd.numUDPPorts  ? callocL("mDNSOffloadCmd udpPorts" , cmd.numUDPPorts  * sizeof(mDNSIPPort)) : NULL;
+                cmd.tcpPorts.ptr  = cmd.numTCPPorts  ? callocL("mDNSOffloadCmd tcpPorts" , cmd.numTCPPorts  * sizeof(mDNSIPPort)) : NULL;
 
                 LogSPS("ActivateLocalProxy: msg %p %u RR %p %u, UDP %p %u, TCP %p %u",
                        msg, cmd.rrBufferSize,
@@ -7185,7 +6002,7 @@ mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
     mDNSu8  ret = (mDNSu8)mDNS_NoWake;
 
 #if TARGET_OS_IOS
-    LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client disabled by command-line option");
+    LogSPS("SystemWakeForNetworkAccess: Sleep Proxy Client always disabled on TARGET_OS_IOS");
     return ret;
 #endif
 
@@ -7199,7 +6016,7 @@ mDNSlocal mDNSu8 SystemWakeForNetworkAccess(void)
 
     ret = (mDNSu8)(val != 0) ? mDNS_WakeOnAC : mDNS_NoWake;
 
-#if APPLE_OSX_mDNSResponder && !TARGET_OS_EMBEDDED
+#if APPLE_OSX_mDNSResponder && TARGET_OS_OSX
     // If we have TCP Keepalive support, system is capable of registering for TCP Keepalives.
     // Further policy decisions on whether to offload the records is handled during sleep processing.
     if ((ret == mDNS_NoWake) && SupportsTCPKeepAlive())
@@ -7221,305 +6038,6 @@ mDNSlocal mDNSBool SystemSleepOnlyIfWakeOnLAN(void)
     return val != 0 ? mDNStrue : mDNSfalse;
 }
 
-
-#if APPLE_OSX_mDNSResponder
-// When sleeping, we always ensure that the _autotunnel6 record (if connected to RR relay)
-// gets deregistered, so that older peers are forced to connect over direct UDP instead of
-// the RR relay.
-//
-// When sleeping w/o a successful AutoTunnel NAT Mapping, we ensure that all our BTMM
-// service records are deregistered, so they do not appear in peers' Finder sidebars.
-// We do this by checking for the (non-autotunnel) SRV records, as the PTR and TXT records
-// depend on their associated SRV record and therefore will be deregistered together in a
-// single update with the SRV record.
-//
-// Also, the per-zone _kerberos TXT record is always there, including while sleeping, so
-// its presence shouldn't delay sleep.
-//
-// Note that the order of record deregistration is: first _autotunnel6 (if connected to RR
-// relay) and host records get deregistered, then SRV (UpdateAllSrvRecords), PTR and TXT.
-//
-// Also note that returning false here will not delay sleep past the maximum of 10 seconds.
-mDNSexport mDNSBool RecordReadyForSleep(AuthRecord *rr)
-{
-    mDNS *const m = &mDNSStorage;
-    if (!AuthRecord_uDNS(rr)) return mDNStrue;
-    
-    if ((rr->resrec.rrtype == kDNSType_AAAA) && SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0c_autotunnel6"))
-    {
-        LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
-        return mDNSfalse;
-    }
-    
-    if ((mDNSIPPortIsZero(m->AutoTunnelNAT.ExternalPort) || m->AutoTunnelNAT.Result))
-    {
-        if (rr->resrec.rrtype == kDNSType_SRV && rr->state != regState_NoTarget && rr->zone
-            && !SameDomainLabel(rr->namestorage.c, (const mDNSu8 *)"\x0b_autotunnel"))
-        {
-            DomainAuthInfo *info = GetAuthInfoForName_internal(m, rr->zone);
-            if (info && info->AutoTunnel)
-            {
-                LogInfo("RecordReadyForSleep: %s not ready for sleep", ARDisplayString(m, rr));
-                return mDNSfalse;
-            }
-        }
-    }
-    
-    return mDNStrue;
-}
-
-// Caller must hold the lock
-mDNSexport void RemoveAutoTunnel6Record(mDNS *const m)
-{
-    DomainAuthInfo *info;
-    // Set the address to zero before calling UpdateAutoTunnel6Record, so that it will
-    // deregister the record, and the MemFree callback won't re-register.
-    m->AutoTunnelRelayAddr = zerov6Addr;
-    for (info = m->AuthInfoList; info; info = info->next)
-        if (info->AutoTunnel)
-            UpdateAutoTunnel6Record(m, info);
-}
-#endif /* APPLE_OSX_mDNSResponder */
-
-#if MDNSRESPONDER_BTMM_SUPPORT
-mDNSlocal mDNSBool IPv6AddressIsOnInterface(mDNSv6Addr ipv6Addr, char *ifname)
-{
-    struct ifaddrs  *ifa;
-    struct ifaddrs  *ifaddrs;
-    mDNSAddr addr;
-
-    if (if_nametoindex(ifname) == 0) {LogInfo("IPv6AddressIsOnInterface: Invalid name %s", ifname); return mDNSfalse;}
-
-    if (getifaddrs(&ifaddrs) < 0) {LogInfo("IPv6AddressIsOnInterface: getifaddrs failed"); return mDNSfalse;}
-
-    for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next)
-    {
-        if (strncmp(ifa->ifa_name, ifname, IFNAMSIZ) != 0)
-            continue;
-        if ((ifa->ifa_flags & IFF_UP) == 0 || !ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET6)
-            continue;
-        if (SetupAddr(&addr, ifa->ifa_addr) != mStatus_NoError)
-        {
-            LogInfo("IPv6AddressIsOnInterface: SetupAddr error, continuing to the next address");
-            continue;
-        }
-        if (mDNSSameIPv6Address(ipv6Addr, *(mDNSv6Addr*)&addr.ip.v6))
-        {
-            LogInfo("IPv6AddressIsOnInterface: found %.16a", &ipv6Addr);
-            break;
-        }
-    }
-    freeifaddrs(ifaddrs);
-    return ifa != NULL;
-}
-
-mDNSlocal mDNSv6Addr IPv6AddressFromString(char* buf)
-{
-    mDNSv6Addr retVal;
-    struct addrinfo hints;
-    struct addrinfo *res0;
-
-    memset(&hints, 0, sizeof(hints));
-    hints.ai_family = AF_INET6;
-    hints.ai_flags = AI_NUMERICHOST;
-
-    int err = getaddrinfo(buf, NULL, &hints, &res0);
-    if (err)
-        return zerov6Addr;
-
-    retVal = *(mDNSv6Addr*)&((struct sockaddr_in6*)res0->ai_addr)->sin6_addr;
-
-    freeaddrinfo(res0);
-
-    return retVal;
-}
-
-mDNSlocal CFDictionaryRef CopyConnectivityBackToMyMacDict()
-{
-    CFDictionaryRef connd = NULL;
-    CFDictionaryRef BTMMDict = NULL;
-
-    connd = SCDynamicStoreCopyValue(NULL, NetworkChangedKey_BTMMConnectivity);
-    if (!connd)
-    {
-        LogInfo("CopyConnectivityBackToMyMacDict: SCDynamicStoreCopyValue failed: %s", SCErrorString(SCError()));
-        goto end;
-    }
-
-    BTMMDict = CFDictionaryGetValue(connd, CFSTR("BackToMyMac"));
-    if (!BTMMDict)
-    {
-        LogInfo("CopyConnectivityBackToMyMacDict: CFDictionaryGetValue: No value for BackToMyMac");
-        goto end;
-    }
-
-    // Non-dictionary is treated as non-existent dictionary
-    if (CFGetTypeID(BTMMDict) != CFDictionaryGetTypeID())
-    {
-        BTMMDict = NULL;
-        LogMsg("CopyConnectivityBackToMyMacDict: BackToMyMac not a dictionary");
-        goto end;
-    }
-
-    CFRetain(BTMMDict);
-
-end:
-    if (connd) CFRelease(connd);
-
-    return BTMMDict;
-}
-
-#define MAX_IPV6_TEXTUAL 40
-
-mDNSlocal mDNSv6Addr ParseBackToMyMacAddr(CFDictionaryRef BTMMDict, CFStringRef ifKey, CFStringRef addrKey)
-{
-    mDNSv6Addr retVal = zerov6Addr;
-    CFTypeRef string = NULL;
-    char ifname[IFNAMSIZ];
-    char address[MAX_IPV6_TEXTUAL];
-
-    if (!BTMMDict)
-        return zerov6Addr;
-
-    if (!CFDictionaryGetValueIfPresent(BTMMDict, ifKey, &string))
-    {
-        LogInfo("ParseBackToMyMacAddr: interface key does not exist");
-        return zerov6Addr;
-    }
-
-    if (!CFStringGetCString(string, ifname, IFNAMSIZ, kCFStringEncodingUTF8))
-    {
-        LogMsg("ParseBackToMyMacAddr: Could not convert interface to CString");
-        return zerov6Addr;
-    }
-
-    if (!CFDictionaryGetValueIfPresent(BTMMDict, addrKey, &string))
-    {
-        LogMsg("ParseBackToMyMacAddr: address key does not exist, but interface key does");
-        return zerov6Addr;
-    }
-
-    if (!CFStringGetCString(string, address, sizeof(address), kCFStringEncodingUTF8))
-    {
-        LogMsg("ParseBackToMyMacAddr: Could not convert address to CString");
-        return zerov6Addr;
-    }
-
-    retVal = IPv6AddressFromString(address);
-    LogInfo("ParseBackToMyMacAddr: %s (%s) %.16a", ifname, address, &retVal);
-
-    if (mDNSIPv6AddressIsZero(retVal))
-        return zerov6Addr;
-
-    if (!IPv6AddressIsOnInterface(retVal, ifname))
-    {
-        LogMsg("ParseBackToMyMacAddr: %.16a is not on %s", &retVal, ifname);
-        return zerov6Addr;
-    }
-
-    return retVal;
-}
-
-mDNSlocal CFDictionaryRef GetBackToMyMacZones(CFDictionaryRef BTMMDict)
-{
-    CFTypeRef zones = NULL;
-
-    if (!BTMMDict)
-        return NULL;
-
-    if (!CFDictionaryGetValueIfPresent(BTMMDict, CFSTR("Zones"), &zones))
-    {
-        LogInfo("CopyBTMMZones: Zones key does not exist");
-        return NULL;
-    }
-
-    return zones;
-}
-
-mDNSlocal mDNSv6Addr ParseBackToMyMacZone(CFDictionaryRef zones, DomainAuthInfo* info)
-{
-    mDNSv6Addr addr = zerov6Addr;
-    char buffer[MAX_ESCAPED_DOMAIN_NAME];
-    CFStringRef domain = NULL;
-    CFTypeRef theZone = NULL;
-
-    if (!zones)
-        return addr;
-
-    ConvertDomainNameToCString(&info->domain, buffer);
-    domain = CFStringCreateWithCString(NULL, buffer, kCFStringEncodingUTF8);
-    if (!domain)
-        return addr;
-
-    if (CFDictionaryGetValueIfPresent(zones, domain, &theZone))
-        addr = ParseBackToMyMacAddr(theZone, CFSTR("Interface"), CFSTR("Address"));
-
-    CFRelease(domain);
-
-    return addr;
-}
-
-mDNSlocal void SetupBackToMyMacInnerAddresses(CFDictionaryRef BTMMDict)
-{
-    mDNS *const m = &mDNSStorage;
-    DomainAuthInfo* info;
-    CFDictionaryRef zones = GetBackToMyMacZones(BTMMDict);
-    mDNSv6Addr newAddr;
-
-    for (info = m->AuthInfoList; info; info = info->next)
-    {
-        if (!info->AutoTunnel)
-            continue;
-
-        newAddr = ParseBackToMyMacZone(zones, info);
-
-        if (mDNSSameIPv6Address(newAddr, info->AutoTunnelInnerAddress))
-            continue;
-
-        info->AutoTunnelInnerAddress = newAddr;
-        DeregisterAutoTunnelHostRecord(m, info);
-        UpdateAutoTunnelHostRecord(m, info);
-        UpdateAutoTunnelDomainStatus(info);
-    }
-}
-
-// MUST be called holding the lock
-mDNSlocal void ProcessConndConfigChanges(void)
-{
-    mDNS *const m = &mDNSStorage;
-    CFDictionaryRef dict = CopyConnectivityBackToMyMacDict();
-    if (!dict)
-        LogInfo("ProcessConndConfigChanges: No BTMM dictionary");
-    mDNSv6Addr relayAddr = ParseBackToMyMacAddr(dict, CFSTR("RelayInterface"), CFSTR("RelayAddress"));
-
-    LogInfo("ProcessConndConfigChanges: relay %.16a", &relayAddr);
-
-    SetupBackToMyMacInnerAddresses(dict);
-
-    if (dict) CFRelease(dict);
-
-    if (!mDNSSameIPv6Address(relayAddr, m->AutoTunnelRelayAddr))
-    {
-        m->AutoTunnelRelayAddr = relayAddr;
-
-        DomainAuthInfo* info;
-        for (info = m->AuthInfoList; info; info = info->next)
-            if (info->AutoTunnel)
-            {
-                DeregisterAutoTunnel6Record(m, info);
-                UpdateAutoTunnel6Record(m, info);
-                UpdateAutoTunnelDomainStatus(info);
-            }
-
-        // Determine whether we need racoon to accept incoming connections
-        UpdateAnonymousRacoonConfig(m);
-    }
-
-    // If awacsd crashes or exits for some reason, restart it
-    UpdateBTMMRelayConnection(m);
-}
-#endif // MDNSRESPONDER_BTMM_SUPPORT
-
 mDNSlocal mDNSBool IsAppleNetwork(mDNS *const m)
 {
     DNSServer *s;
@@ -7544,10 +6062,13 @@ mDNSlocal void SetNetworkChanged(mDNSs32 delay)
     if (!m->NetworkChanged || m->NetworkChanged - NonZeroTime(m->timenow + delay) > 0)
     {
         m->NetworkChanged = NonZeroTime(m->timenow + delay);
-        LogInfo("SetNetworkChanged: Scheduling in %d ticks", delay);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "SetNetworkChanged: Scheduling in %d ticks", delay);
     }
     else
-        LogInfo("SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
+       {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "SetNetworkChanged: *NOT* increasing delay from %d to %d", m->NetworkChanged - m->timenow, delay);
+    }
 }
 
 // Called with KQueueLock & mDNS lock
@@ -7565,9 +6086,10 @@ mDNSlocal void SetKeyChainTimer(mDNSs32 delay)
 mDNSexport void mDNSMacOSXNetworkChanged(void)
 {
     mDNS *const m = &mDNSStorage;
-    LogInfo("***   Network Configuration Change   ***  %d ticks late%s",
-            m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
-            m->NetworkChanged ? "" : " (no scheduled configuration change)");
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+        "*** Network Configuration Change ***  %d ticks late" PUB_S,
+        m->NetworkChanged ? mDNS_TimeNow(m) - m->NetworkChanged : 0,
+        m->NetworkChanged ? "" : " (no scheduled configuration change)");
     m->NetworkChanged = 0;       // If we received a network change event and deferred processing, we're now dealing with it
 
     // If we have *any* TENTATIVE IPv6 addresses, wait until they've finished configuring
@@ -7592,7 +6114,9 @@ mDNSexport void mDNSMacOSXNetworkChanged(void)
                 {
                     if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
                     {
-                        LogInfo("***   Network Configuration Change   ***  IPv6 address %.16a TENTATIVE, will retry", &ifr6.ifr_addr.sin6_addr);
+                        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                            "*** Network Configuration Change ***  IPv6 address " PRI_IPv6_ADDR " TENTATIVE, will retry",
+                            &ifr6.ifr_addr.sin6_addr);
                         tentative = mDNStrue;
                         // no need to check other interfaces if we already found out that one interface is TENTATIVE
                         break;
@@ -7609,7 +6133,8 @@ mDNSexport void mDNSMacOSXNetworkChanged(void)
             mDNS_Unlock(m);
             return;
         }
-        LogInfo("***   Network Configuration Change   ***  No IPv6 address TENTATIVE, will continue");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "*** Network Configuration Change ***  No IPv6 address TENTATIVE, will continue");
     }
 
     mDNSs32 utc = mDNSPlatformUTC();
@@ -7622,59 +6147,6 @@ mDNSexport void mDNSMacOSXNetworkChanged(void)
     ReorderInterfaceList();
 
 #if APPLE_OSX_mDNSResponder
-#if !TARGET_OS_EMBEDDED
-#if MDNSRESPONDER_BTMM_SUPPORT
-    mDNS_Lock(m);
-    ProcessConndConfigChanges();
-    mDNS_Unlock(m);
-#endif
-
-    // 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)
-        {
-            DomainAuthInfo* info = GetAuthInfoForName(m, &p->dstname);
-            if (!info)
-            {
-                LogMsg("mDNSMacOSXNetworkChanged: Could not get AuthInfo for %##s, removing tunnel keys", p->dstname.c);
-                AutoTunnelSetKeys(p, mDNSfalse);
-            }
-            else
-            {
-                mDNSv6Addr inner = info->AutoTunnelInnerAddress;
-
-                if (!mDNSIPPortIsZero(p->rmt_outer_port))
-                {
-                    mDNSAddr tmpSrc = zeroAddr;
-                    mDNSAddr tmpDst = { mDNSAddrType_IPv4, {{{0}}} };
-                    tmpDst.ip.v4 = p->rmt_outer;
-                    mDNSPlatformSourceAddrForDest(&tmpSrc, &tmpDst);
-                    if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
-                        !mDNSSameIPv4Address(p->loc_outer, tmpSrc.ip.v4))
-                    {
-                        AutoTunnelSetKeys(p, mDNSfalse);
-                        p->loc_inner = inner;
-                        p->loc_outer = tmpSrc.ip.v4;
-                        AutoTunnelSetKeys(p, mDNStrue);
-                    }
-                }
-                else
-                {
-                    if (!mDNSSameIPv6Address(p->loc_inner, inner) ||
-                        !mDNSSameIPv6Address(p->loc_outer6, m->AutoTunnelRelayAddr))
-                    {
-                        AutoTunnelSetKeys(p, mDNSfalse);
-                        p->loc_inner = inner;
-                        p->loc_outer6 = m->AutoTunnelRelayAddr;
-                        AutoTunnelSetKeys(p, mDNStrue);
-                    }
-                }
-            }
-        }
-#endif //!TARGET_OS_EMBEDDED
-
     SetSPS(m);
 
     NetworkInterfaceInfoOSX *i;
@@ -7765,8 +6237,8 @@ mDNSlocal int ChangedKeysHaveIPv4LL(CFArrayRef inkeys)
     }
 
     ic = CFDictionaryGetCount(dict);
-    vals = mDNSPlatformMemAllocate(sizeof (void *) * ic);
-    keys = mDNSPlatformMemAllocate(sizeof (void *) * ic);
+    vals = (const void **) mDNSPlatformMemAllocate(sizeof(void *) * ic);
+    keys = (const void **) mDNSPlatformMemAllocate(sizeof(void *) * ic);
     CFDictionaryGetKeysAndValues(dict, keys, vals);
 
     // For each key we were given...
@@ -7849,7 +6321,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
     mDNS_Lock(m);
 
     //mDNSs32 delay = mDNSPlatformOneSecond * 2;                // Start off assuming a two-second delay
-    const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40;   // 25 ms delay
+    const mDNSs32 delay = (mDNSPlatformOneSecond + 39) / 40;    // 25 ms delay
 
     const int c = CFArrayGetCount(changedKeys);                   // Count changes
     CFRange range = { 0, c };
@@ -7857,11 +6329,6 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
     const int c_comp = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_Computername) != 0);
     const int c_udns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DNS         ) != 0);
     const int c_ddns = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_DynamicDNS  ) != 0);
-#if MDNSRESPONDER_BTMM_SUPPORT
-    const int c_btmm = (CFArrayContainsValue(changedKeys, range, NetworkChangedKey_BackToMyMac ) != 0);
-#else
-    const int c_btmm = 0;
-#endif
     const int c_v4ll = ChangedKeysHaveIPv4LL(changedKeys);
     int c_fast = 0;
     
@@ -7909,7 +6376,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
         }
     }
 
-    //if (c && c - c_host - c_comp - c_udns - c_ddns - c_btmm - c_v4ll - c_fast == 0)
+    //if (c && c - c_host - c_comp - c_udns - c_ddns - c_v4ll - c_fast == 0)
     //    delay = mDNSPlatformOneSecond/10;  // If these were the only changes, shorten delay
 
     if (mDNS_LoggingEnabled)
@@ -7919,19 +6386,19 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
         {
             char buf[256];
             if (!CFStringGetCString(CFArrayGetValueAtIndex(changedKeys, i), buf, sizeof(buf), kCFStringEncodingUTF8)) buf[0] = 0;
-            LogInfo("***   Network Configuration Change   *** SC key: %s", buf);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "*** Network Configuration Change *** SC key: " PUB_S, buf);
         }
-        LogInfo("***   Network Configuration Change   *** %d change%s %s%s%s%s%s%s%sdelay %d%s",
-                c, c>1 ? "s" : "",
-                c_host ? "(Local Hostname) " : "",
-                c_comp ? "(Computer Name) "  : "",
-                c_udns ? "(DNS) "            : "",
-                c_ddns ? "(DynamicDNS) "     : "",
-                c_btmm ? "(BTMM) "           : "",
-                c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
-                c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) "  : "",
-                delay,
-                (c_ddns || c_btmm) ? " + SetKeyChainTimer" : "");
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+            "*** Network Configuration Change *** %d change" PUB_S " " PUB_S PUB_S PUB_S PUB_S PUB_S PUB_S "delay %d" PUB_S,
+            c, c>1 ? "s" : "",
+            c_host ? "(Local Hostname) " : "",
+            c_comp ? "(Computer Name) "  : "",
+            c_udns ? "(DNS) "            : "",
+            c_ddns ? "(DynamicDNS) "     : "",
+            c_v4ll ? "(kSCValNetIPv4ConfigMethodLinkLocal) " : "",
+            c_fast ? "(P2P/IFEF_DIRECTLINK/IFEF_AWDL/IsCarPlaySSID) "  : "",
+            delay,
+            c_ddns ? " + SetKeyChainTimer" : "");
     }
 
     SetNetworkChanged(delay);
@@ -7941,7 +6408,7 @@ mDNSlocal void NetworkChanged(SCDynamicStoreRef store, CFArrayRef changedKeys, v
     // setup the DomainAuthInfo before handing the network change.
     // If we don't, then we will first try to register services in the clear, then later setup the
     // DomainAuthInfo, which is incorrect.
-    if (c_ddns || c_btmm)
+    if (c_ddns)
         SetKeyChainTimer(delay);
 
     // Don't try to call mDNSMacOSXNetworkChanged() here -- we're running on the wrong thread
@@ -7991,9 +6458,6 @@ mDNSlocal void DynamicStoreReconnected(SCDynamicStoreRef store, void *info)
         mDNSDynamicStoreSetConfig(kmDNSPrivateConfig, mDNSNULL, privateDnsArray);
 
 #if APPLE_OSX_mDNSResponder
-    // State:/Network/BackToMyMac
-    UpdateAutoTunnelDomainStatuses(m);
-
     // State:/Network/Interface/en0/SleepProxyServers
     if (spsStatusDict) 
         CFDictionaryApplyFunction(spsStatusDict, RefreshSPSStatus, NULL);
@@ -8021,10 +6485,6 @@ mDNSlocal mStatus WatchForNetworkChanges(mDNS *const m)
     CFArrayAppendValue(keys, NetworkChangedKey_DNS);
     CFArrayAppendValue(keys, NetworkChangedKey_DynamicDNS);
     CFArrayAppendValue(keys, NetworkChangedKey_PowerSettings);
-#if MDNSRESPONDER_BTMM_SUPPORT
-    CFArrayAppendValue(keys, NetworkChangedKey_BackToMyMac);
-    CFArrayAppendValue(keys, NetworkChangedKey_BTMMConnectivity);
-#endif
     CFArrayAppendValue(patterns, pattern1);
     CFArrayAppendValue(patterns, pattern2);
     CFArrayAppendValue(patterns, CFSTR("State:/Network/Interface/[^/]+/AirPort"));
@@ -8056,8 +6516,7 @@ exit:
     return(err);
 }
 
-#if !TARGET_OS_EMBEDDED     // don't setup packet filter rules on embedded
-
+#if TARGET_OS_OSX
 mDNSlocal void mDNSSetPacketFilterRules(char * ifname, const ResourceRecord *const excludeRecord)
 {
     mDNS *const m = &mDNSStorage;
@@ -8137,16 +6596,13 @@ mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord
         intf = GetFirstActiveInterface(intf->next);
     }
 }
-
-#else // !TARGET_OS_EMBEDDED
-
+#else // !TARGET_OS_OSX
 // Currently no packet filter setup required on embedded platforms.
 mDNSexport void mDNSUpdatePacketFilter(const ResourceRecord *const excludeRecord)
 {
     (void) excludeRecord; // unused
 }
-
-#endif // !TARGET_OS_EMBEDDED
+#endif
 
 // AWDL should no longer generate KEV_DL_MASTER_ELECTED events, so just log a message if we receive one.
 mDNSlocal void newMasterElected(struct net_event_data * ptr)
@@ -8319,8 +6775,7 @@ mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __
         if (msg.k.event_code == KEV_DL_WAKEFLAGS_CHANGED || msg.k.event_code == KEV_DL_LINK_ON)
             SetNetworkChanged(mDNSPlatformOneSecond * 2);
 
-#if !TARGET_OS_EMBEDDED     // don't setup packet filter rules on embedded
-
+#if TARGET_OS_OSX
         // For p2p interfaces, need to open the advertised service port in the firewall.
         if (msg.k.event_code == KEV_DL_IF_ATTACHED)
         {
@@ -8355,8 +6810,7 @@ mDNSlocal void SysEventCallBack(int s1, short __unused filter, void *context, __
                 mDNSPacketFilterControl(PF_CLEAR_RULES, ifname, 0, portArray, protocolArray);
             }
         }
-#endif // !TARGET_OS_EMBEDDED
-
+#endif
     }
 
     mDNS_Unlock(m);
@@ -8409,12 +6863,6 @@ mDNSlocal OSStatus KeychainChanged(SecKeychainEvent keychainEvent, SecKeychainCa
                 {
                     relevant = ((a->attr[0].length == 4 && (!strncasecmp(a->attr[0].data, "ddns", 4) || !strncasecmp(a->attr[0].data, "sndd", 4))) ||
                                 (a->attr[1].length >= mDNSPlatformStrLen(dnsprefix) && (!strncasecmp(a->attr[1].data, dnsprefix, mDNSPlatformStrLen(dnsprefix)))));
-#if MDNSRESPONDER_BTMM_SUPPORT
-                    if (!relevant && (a->attr[1].length >= mDNSPlatformStrLen(btmmprefix)) && !strncasecmp(a->attr[1].data, btmmprefix, mDNSPlatformStrLen(btmmprefix)))
-                    {
-                        relevant = mDNStrue;
-                    }
-#endif
                     SecKeychainItemFreeAttributesAndData(a, NULL);
                 }
             }
@@ -8480,10 +6928,10 @@ mDNSlocal void PowerOn(mDNS *const m)
         }
     }
 
-       // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
-       // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
-       // We will clear this assertion as soon as we think the mainenance activities are done.
-       mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
+    // Hold on to a sleep assertion to allow mDNSResponder to perform its maintenance activities.
+    // This allows for the network link to come up, DHCP to get an address, mDNS to issue queries etc.
+    // We will clear this assertion as soon as we think the mainenance activities are done.
+    mDNSPlatformPreventSleep(DARK_WAKE_TIME, "mDNSResponder:maintenance");
 
 }
 
@@ -8550,7 +6998,7 @@ mDNSlocal void PowerChanged(void *refcon, io_service_t service, natural_t messag
 
 // iPhone OS doesn't currently have SnowLeopard's IO Power Management
 // but it does define kIOPMAcknowledgmentOptionSystemCapabilityRequirements
-#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && !TARGET_OS_EMBEDDED
+#if defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) && TARGET_OS_OSX
 mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection, IOPMConnectionMessageToken token, IOPMSystemPowerStateCapabilities eventDescriptor)
 {
     mDNS *const m = (mDNS *const)refcon;
@@ -8582,12 +7030,12 @@ mDNSlocal void SnowLeopardPowerChanged(void *refcon, IOPMConnection connection,
         // CPU Waking. Note: Can get this message repeatedly, as other subsystems power up or down.
         if (m->SleepState != SleepState_Awake)
         {
-                       PowerOn(m);
-                       // If the network notifications have already come before we got the wakeup, we ignored them and
-                       // in case we get no more, we need to trigger one.
-                       mDNS_Lock(m);
-                       SetNetworkChanged(mDNSPlatformOneSecond * 2);
-                       mDNS_Unlock(m);
+            PowerOn(m);
+            // If the network notifications have already come before we got the wakeup, we ignored them and
+            // in case we get no more, we need to trigger one.
+            mDNS_Lock(m);
+            SetNetworkChanged(mDNSPlatformOneSecond * 2);
+            mDNS_Unlock(m);
         }
         IOPMConnectionAcknowledgeEvent(connection, token);
     }
@@ -8701,9 +7149,9 @@ mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const
                 {
                     mDNSv4Addr ip;
                     ip.NotAnInteger = ((struct sockaddr_in*)sa)->sin_addr.s_addr;
-                    if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip))
+                    if (mDNSSameIPv4Address(rr->resrec.rdata->u.ipv4, ip) && InterfaceID == rr->resrec.InterfaceID)
                     {
-                        LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address for name %##s", domain->c);
+                        LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv4 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID));
                         return mDNSfalse;
                     }
                 }
@@ -8714,9 +7162,9 @@ mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const
                     ip6.l[1] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[1];
                     ip6.l[2] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[2];
                     ip6.l[3] = ((struct sockaddr_in6*)sa)->sin6_addr.__u6_addr.__u6_addr32[3];
-                    if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6))
+                    if (mDNSSameIPv6Address(rr->resrec.rdata->u.ipv6, ip6) && InterfaceID == rr->resrec.InterfaceID)
                     {
-                        LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address for name %##s", domain->c);
+                        LogInfo("mDNSMacOSXCreateEtcHostsEntry: Same IPv6 address and InterfaceID for name %##s ID %d", domain->c, IIDPrintable(InterfaceID));
                         return mDNSfalse;
                     }
                 }
@@ -8732,9 +7180,8 @@ mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const
             rr = rr->next;
         }
     }
-    rr= mallocL("etchosts", sizeof(*rr));
+    rr = (AuthRecord *) callocL("etchosts", sizeof(*rr));
     if (rr == NULL) return mDNSfalse;
-    mDNSPlatformMemZero(rr, sizeof(*rr));
     mDNS_SetupResourceRecord(rr, NULL, InterfaceID, rrtype, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
     AssignDomainName(&rr->namestorage, domain);
 
@@ -8759,7 +7206,7 @@ mDNSlocal mDNSBool mDNSMacOSXCreateEtcHostsEntry(const domainname *domain, const
     }
     rr->resrec.namehash = DomainNameHashValue(rr->resrec.name);
     SetNewRData(&rr->resrec, mDNSNULL, 0);  // Sets rr->rdatahash for us
-    LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s", ARDisplayString(&mDNSStorage, rr));
+    LogInfo("mDNSMacOSXCreateEtcHostsEntry: Adding resource record %s ID %d", ARDisplayString(&mDNSStorage, rr), IIDPrintable(rr->resrec.InterfaceID));
     InsertAuthRecord(&mDNSStorage, auth, rr);
     return mDNStrue;
 }
@@ -9169,7 +7616,7 @@ mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
                         // this is a common case. To fix this, we also need to modify
                         // mDNS_Register_internal in how it handles duplicates. If it becomes a
                         // common case, we will fix it then.
-                        if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec))
+                        if (IdenticalResourceRecord(&rr1->resrec, &rr->resrec) && rr1->resrec.InterfaceID == rr->resrec.InterfaceID)
                         {
                             LogInfo("EtcHostsAddNewEntries: Skipping, not adding %s", ARDisplayString(m, rr1));
                             found = mDNStrue;
@@ -9189,7 +7636,7 @@ mDNSlocal mDNSBool EtcHostsAddNewEntries(AuthHash *newhosts, mDNSBool justCheck)
                     // if there is no primary, point to self
                     rr->RRSet = (primary ? primary : rr);
                     rr->next = NULL;
-                    LogInfo("EtcHostsAddNewEntries: Adding %s", ARDisplayString(m, rr));
+                    LogInfo("EtcHostsAddNewEntries: Adding %s ID %d", ARDisplayString(m, rr), IIDPrintable(rr->resrec.InterfaceID));
                     if (mDNS_Register_internal(m, rr) != mStatus_NoError)
                         LogMsg("EtcHostsAddNewEntries: mDNS_Register failed for %s", ARDisplayString(m, rr));
                 }
@@ -9440,9 +7887,8 @@ mDNSlocal void CreatePTRRecord(const domainname *domain)
     AuthRecord *rr;
     const domainname *pname = (domainname *)"\x9" "localhost";
 
-    rr= mallocL("localhosts", sizeof(*rr));
+    rr = (AuthRecord *) callocL("localhosts", sizeof(*rr));
     if (rr == NULL) return;
-    mDNSPlatformMemZero(rr, sizeof(*rr));
 
     mDNS_SetupResourceRecord(rr, mDNSNULL, mDNSInterface_LocalOnly, kDNSType_PTR, kHostNameTTL, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, mDNSNULL, mDNSNULL);
     AssignDomainName(&rr->namestorage, domain);
@@ -9488,12 +7934,7 @@ mDNSlocal void setSameDomainLabelPointer(void);
 // 6) client calls to enumerate domains now go over LocalOnly interface
 //    (!!!KRS may add outgoing interface in addition)
 
-#if TARGET_OS_IPHONE
-mDNSlocal mDNSBool IsAppleInternalBuild(void)
-{
-    return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue : mDNSfalse);
-}
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
 mDNSlocal mStatus RegisterLocalOnlyAddressRecord(const domainname *const name, mDNSu16 type, const void *rdata, mDNSu16 rdlength)
 {
     switch(type)
@@ -9510,9 +7951,8 @@ mDNSlocal mStatus RegisterLocalOnlyAddressRecord(const domainname *const name, m
         return (mStatus_BadParamErr);
     }
 
-    AuthRecord *rr = mallocL("etchosts", sizeof(*rr));
+    AuthRecord *rr = (AuthRecord *) callocL("etchosts", sizeof(*rr));
     if (!rr) return (mStatus_NoMemoryErr);
-    mDNSPlatformMemZero(rr, sizeof(*rr));
 
     mDNS_SetupResourceRecord(rr, NULL, mDNSInterface_LocalOnly, type, 1, kDNSRecordTypeKnownUnique, AuthRecordLocalOnly, FreeEtcHosts, NULL);
     AssignDomainName(&rr->namestorage, name);
@@ -9536,37 +7976,7 @@ mDNSlocal void RegisterLocalOnlyAAAARecord(const domainname *const name, const m
 {
     RegisterLocalOnlyAddressRecord(name, kDNSType_AAAA, addr->b, (mDNSu16)sizeof(mDNSv6Addr));
 }
-#endif
-
-mDNSlocal void NWIEventHandler(void)
-{
-    mDNS * const m = &mDNSStorage;
-    nwi_state_t newState = nwi_state_copy();
-
-    KQueueLock();
-    const nwi_state_t oldState = m->p->NWIState;
-    m->p->NWIState = newState;
-    if (m->p->NWIState)
-    {
-        uint32_t lastIfIndex = 0;
-        mDNSBool lastCLAT46  = mDNSfalse;
-        for (DNSServer *server = m->DNSServers; server; server = server->next)
-        {
-            const uint32_t ifIndex = (uint32_t)((uintptr_t)server->interface);
-            if (ifIndex == 0) continue;
-            if (ifIndex == lastIfIndex)
-            {
-                server->isCLAT46 = lastCLAT46;
-                continue;
-            }
-            server->isCLAT46 = NWIInterfaceHasCLAT46(m->p->NWIState, ifIndex);
-            lastIfIndex      = ifIndex;
-            lastCLAT46       = server->isCLAT46;
-        }
-    }
-    KQueueUnlock("NWIEventHandler");
-    if (oldState) nwi_state_release(oldState);
-}
+#endif  // MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
 
 mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 {
@@ -9614,6 +8024,9 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 
     m->hostlabel.c[0]        = 0;
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    GetRandomUUIDLocalHostname(&m->RandomizedHostname);
+#endif
     int get_model[2] = { CTL_HW, HW_MODEL };
     size_t len_model = sizeof(HINFO_HWstring_buffer);
 
@@ -9621,7 +8034,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
     // internal code names are strings containing no commas, e.g. "N88AP".
     // We used to ignore internal code names, but Apple now uses these internal code names
     // even in released shipping products, so we no longer ignore strings containing no commas.
-//     if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
+//  if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0 && strchr(HINFO_HWstring_buffer, ','))
     if (sysctl(get_model, 2, HINFO_HWstring_buffer, &len_model, NULL, 0) == 0)
         HINFO_HWstring = HINFO_HWstring_buffer;
 
@@ -9673,9 +8086,10 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
         else m->UnicastPort6.NotAnInteger = s6.sin6_port;
     }
 
-    m->p->InterfaceList      = mDNSNULL;
-    m->p->userhostlabel.c[0] = 0;
-    m->p->usernicelabel.c[0] = 0;
+    m->p->InterfaceList         = mDNSNULL;
+    m->p->InterfaceMonitors     = NULL;
+    m->p->userhostlabel.c[0]    = 0;
+    m->p->usernicelabel.c[0]    = 0;
     m->p->prevoldnicelabel.c[0] = 0;
     m->p->prevnewnicelabel.c[0] = 0;
     m->p->prevoldhostlabel.c[0] = 0;
@@ -9690,8 +8104,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
     m->p->v6answers          = 1;
     m->p->DNSTrigger         = 0;
     m->p->LastConfigGeneration = 0;
-
-    m->AutoTunnelRelayAddr = zerov6Addr;
+    m->p->if_interface_changed = mDNSfalse;
 
     NetworkChangedKey_IPv4         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4);
     NetworkChangedKey_IPv6         = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6);
@@ -9708,18 +8121,6 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
     err = WatchForSysEvents(m);
     if (err) { LogMsg("mDNSPlatformInit_setup: WatchForSysEvents failed %d", err); return(err); }
 
-    m->p->NWIState = nwi_state_copy();
-    uint32_t status = notify_register_dispatch(nwi_state_get_notify_key(), &m->p->NWINotifyToken, dispatch_get_main_queue(),
-        ^(__unused int token) { NWIEventHandler(); });
-    if (status == NOTIFY_STATUS_OK)
-    {
-        m->p->NWINotifyRegistered = mDNStrue;
-    }
-    else
-    {
-        LogMsg("mDNSPlatformInit_setup: notify_register_dispatch failed %u", status);
-    }
-
     mDNSs32 utc = mDNSPlatformUTC();
     m->SystemWakeOnLANEnabled = SystemWakeForNetworkAccess();
     myGetIfAddrs(1);
@@ -9742,7 +8143,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
     if (err) { LogMsg("mDNSPlatformInit_setup: SecKeychainAddCallback failed %d", err); return(err); }
 #endif
 
-#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_EMBEDDED
+#if !defined(kIOPMAcknowledgmentOptionSystemCapabilityRequirements) || TARGET_OS_IPHONE
     LogMsg("Note: Compiled without SnowLeopard Fine-Grained Power Management support");
 #else
     IOPMConnection c;
@@ -9809,7 +8210,7 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
 #endif
     if (SSLqueue == mDNSNULL) LogMsg("dispatch_queue_create: SSL queue NULL");
 
-#if TARGET_OS_IPHONE
+#if MDNSRESPONDER_SUPPORTS(APPLE, IGNORE_HOSTS_FILE)
     // On device OSes (iOS, tvOS, watchOS, etc.), ignore /etc/hosts unless the OS is an internal build. When the /etc/hosts
     // file is ignored, LocalOnly auth records will be registered for localhost and broadcasthost addresses contained in the
     // standard /etc/hosts file:
@@ -9845,6 +8246,10 @@ mDNSlocal mStatus mDNSPlatformInit_setup(mDNS *const m)
         mDNSMacOSXUpdateEtcHosts(m);
     }
     SetupLocalHostRecords();
+    
+#if MDNSRESPONDER_SUPPORTS(COMMON, DNS_PUSH)
+    dso_transport_init();
+#endif
 
     return(mStatus_NoError);
 }
@@ -9916,11 +8321,6 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
     }
 
     if (m->p->SysEventNotifier >= 0) { close(m->p->SysEventNotifier); m->p->SysEventNotifier = -1; }
-    if (m->p->NWINotifyRegistered)
-    {
-        notify_cancel(m->p->NWINotifyToken);
-        m->p->NWINotifyRegistered = mDNSfalse;
-    }
     terminateD2DPlugins();
 
     mDNSs32 utc = mDNSPlatformUTC();
@@ -9928,24 +8328,17 @@ mDNSexport void mDNSPlatformClose(mDNS *const m)
     ClearInactiveInterfaces(utc);
     CloseSocketSet(&m->p->permanentsockets);
 
-#if APPLE_OSX_mDNSResponder
-    // clean up tunnels
-    while (m->TunnelClients)
-    {
-        ClientTunnel *cur = m->TunnelClients;
-        LogInfo("mDNSPlatformClose: removing client tunnel %p %##s from list", cur, cur->dstname.c);
-        if (cur->q.ThisQInterval >= 0) mDNS_StopQuery(m, &cur->q);
-        AutoTunnelSetKeys(cur, mDNSfalse);
-        m->TunnelClients = cur->next;
-        freeL("ClientTunnel", cur);
-    }
-
-    if (AnonymousRacoonConfig)
+    if (m->p->InterfaceMonitors)
     {
-        AnonymousRacoonConfig = mDNSNULL;
-        LogInfo("mDNSPlatformClose: Deconfiguring autotunnel need not be done in mDNSResponder");
+        CFArrayRef monitors = m->p->InterfaceMonitors;
+        m->p->InterfaceMonitors = NULL;
+        const CFIndex n = CFArrayGetCount(monitors);
+        for (CFIndex i = 0; i < n; i++)
+        {
+            mdns_interface_monitor_invalidate((mdns_interface_monitor_t) CFArrayGetValueAtIndex(monitors, i));
+        }
+        CFRelease(monitors);
     }
-#endif // APPLE_OSX_mDNSResponder
 }
 
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -9992,7 +8385,7 @@ mDNSexport mDNSs32 mDNSPlatformRawTime(void)
     if (mDNSPlatformClockDivisor == 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
+    //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)
     {
@@ -10020,7 +8413,6 @@ 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(      void *dst, const void *src)              { strcpy((char *)dst, (const char *)src); }
 mDNSexport mDNSu32  mDNSPlatformStrLCopy(     void *dst, const void *src, mDNSu32 dstlen) { return (strlcpy((char *)dst, (const char *)src, dstlen)); }
 mDNSexport mDNSu32  mDNSPlatformStrLen (                 const void *src)              { return(strlen((const char*)src)); }
 mDNSexport void     mDNSPlatformMemCopy(      void *dst, const void *src, mDNSu32 len) { memcpy(dst, src, len); }
@@ -10031,11 +8423,11 @@ mDNSexport void     mDNSPlatformQsort  (      void *base, int nel, int width, in
 {
     return (qsort(base, nel, width, compar));
 }
-#if !(APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING)
-mDNSexport void *   mDNSPlatformMemAllocate(mDNSu32 len) { return(mallocL("mDNSPlatformMemAllocate", len)); }
-mDNSexport void *   mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL("mDNSPlatformMemAllocateClear", len)); }
+#if !MDNS_MALLOC_DEBUGGING
+mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len)      { return(mallocL("mDNSPlatformMemAllocate", len)); }
+mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL("mDNSPlatformMemAllocateClear", len)); }
+mDNSexport void  mDNSPlatformMemFree    (void *mem)                 { freeL("mDNSPlatformMemFree", mem); }
 #endif
-mDNSexport void     mDNSPlatformMemFree    (void *mem)   { freeL("mDNSPlatformMemFree", mem); }
 
 mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reason)
 {
@@ -10065,25 +8457,25 @@ mDNSexport void mDNSPlatformSetAllowSleep(mDNSBool allowSleep, const char *reaso
 
 mDNSexport void mDNSPlatformPreventSleep(mDNSu32 timeout, const char *reason)
 {
-       mDNS *const m = &mDNSStorage;
+    mDNS *const m = &mDNSStorage;
     if (m->p->IOPMAssertion)
-       {
-               LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
+    {
+        LogSPS("Sleep Assertion is already being held. Will not attempt to get it again for %d seconds for %s", timeout, reason);
         return;
-       }
+    }
 #ifdef kIOPMAssertionTypeNoIdleSleep
 
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
     if (!IsAppleTV())
         return; // No need for maintenance wakes on non-AppleTV embedded devices.
 #endif
 
-       double timeoutVal = (double)timeout;
+    double timeoutVal = (double)timeout;
     CFStringRef str = CFStringCreateWithCString(NULL, reason, kCFStringEncodingUTF8);
-       CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
-       CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
-                                                                                                                                                  &kCFTypeDictionaryKeyCallBacks,
-                                                                                                                                                  &kCFTypeDictionaryValueCallBacks);
+    CFNumberRef Timeout_num = CFNumberCreate(NULL, kCFNumberDoubleType, &timeoutVal);
+    CFMutableDictionaryRef assertionProperties = CFDictionaryCreateMutable(NULL, 0,
+                                                                           &kCFTypeDictionaryKeyCallBacks,
+                                                                           &kCFTypeDictionaryValueCallBacks);
     if (IsAppleTV())
         CFDictionarySetValue(assertionProperties, kIOPMAssertionTypeKey, kIOPMAssertPreventUserIdleSystemSleep);
     else
@@ -10128,8 +8520,7 @@ mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
 
     if (   (InterfaceID == mDNSInterface_Any) 
         || (InterfaceID == mDNSInterfaceMark)
-        || (InterfaceID == mDNSInterface_LocalOnly)
-        || (InterfaceID == mDNSInterface_Unicast))
+        || (InterfaceID == mDNSInterface_LocalOnly))
         return mDNSfalse;
 
     // Compare to cached AWDL interface ID.
@@ -10147,6 +8538,13 @@ mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
     return (mDNSBool) info->D2DInterface;
 }
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSexport mDNSBool mDNSPlatformInterfaceIsAWDL(const mDNSInterfaceID interfaceID)
+{
+    return ((AWDLInterfaceID && (interfaceID == AWDLInterfaceID)) ? mDNStrue : mDNSfalse);
+}
+#endif
+
 // Filter records send over P2P (D2D) type interfaces
 // Note that the terms P2P and D2D are used synonymously in the current code and comments.
 mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
@@ -10276,23 +8674,23 @@ mDNSexport void mDNSPlatformDispatchAsync(mDNS *const m, void *context, AsyncDis
 
 mDNSlocal mDNSu8 getModelIconColors(char *color)
 {
-       mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
+    mDNSPlatformMemZero(color, MODEL_RGB_VALUE_LEN + 1);
 
-#if !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
-       mDNSu8   red      = 0;
-       mDNSu8   green    = 0;
-       mDNSu8   blue     = 0;
+#if TARGET_OS_OSX && defined(kIOPlatformDeviceEnclosureColorKey)
+    mDNSu8   red      = 0;
+    mDNSu8   green    = 0;
+    mDNSu8   blue     = 0;
 
-       IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
-                                                                                                               &red, &green, &blue);
-       if (kIOReturnSuccess == rGetDeviceColor)
-       {
-               // IOKit was able to get enclosure color for the current device.
-               return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
-       }
-#endif // !TARGET_OS_EMBEDDED && defined(kIOPlatformDeviceEnclosureColorKey)
+    IOReturn rGetDeviceColor = IOPlatformGetDeviceColor(kIOPlatformDeviceEnclosureColorKey,
+                                                        &red, &green, &blue);
+    if (kIOReturnSuccess == rGetDeviceColor)
+    {
+        // IOKit was able to get enclosure color for the current device.
+        return snprintf(color, MODEL_RGB_VALUE_LEN + 1, "%d,%d,%d", red, green, blue);
+    }
+#endif
 
-       return 0;
+    return 0;
 }
 
 
@@ -10323,19 +8721,19 @@ mDNSexport mDNSu32 initializeDeviceInfoTXT(mDNS *m, mDNSu8 *ptr)
         mDNSPlatformMemCopy(ptr, ver_num, VER_NUM_LEN);
         ptr += VER_NUM_LEN;
 
-               char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
-               len = getModelIconColors(rgb);
-               if (len)
-               {
-                       *ptr = MODEL_COLOR_LEN + len; // length byte
-                       ptr++;
+        char rgb[MODEL_RGB_VALUE_LEN + 1]; // RGB value + null written by snprintf
+        len = getModelIconColors(rgb);
+        if (len)
+        {
+            *ptr = MODEL_COLOR_LEN + len; // length byte
+            ptr++;
 
-                       mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
-                       ptr += MODEL_COLOR_LEN;
+            mDNSPlatformMemCopy(ptr, MODEL_COLOR, MODEL_COLOR_LEN);
+            ptr += MODEL_COLOR_LEN;
 
-                       mDNSPlatformMemCopy(ptr, rgb, len);
-                       ptr += len;
-               }
+            mDNSPlatformMemCopy(ptr, rgb, len);
+            ptr += len;
+        }
     }
 
     return (ptr - bufferStart);
@@ -10351,8 +8749,7 @@ mDNSlocal mDNSBool (*SameDomainLabelPointer)(const mDNSu8 *a, const mDNSu8 *b) =
 #include <System/machine/cpu_capabilities.h>
 #define _cpu_capabilities   ((uint32_t*) _COMM_PAGE_CPU_CAPABILITIES)[0]
 
-#if TARGET_OS_EMBEDDED
-
+#if TARGET_OS_IPHONE
 #include <arm_neon.h>
 
 // Cache line aligned table that returns 32 for the upper case letters.
@@ -10538,9 +8935,9 @@ mDNSlocal void setSameDomainLabelPointer(void)
     else
         LogMsg("setSameDomainLabelPointer: using scalar code");
 }
+#endif // TARGET_OS_IPHONE
 
-#else   // TARGET_OS_EMBEDDED
-
+#if TARGET_OS_OSX
 #include <smmintrin.h>
 
 // Cache line aligned table that returns 32 for the upper case letters.
@@ -10661,8 +9058,7 @@ mDNSlocal void setSameDomainLabelPointer(void)
     else
         LogMsg("setSameDomainLabelPointer: using scalar code");
 }
-
-#endif  // TARGET_OS_EMBEDDED
+#endif // TARGET_OS_OSX
 
 // Original SameDomainLabel() implementation.
 mDNSlocal mDNSBool scalarSameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
@@ -10692,8 +9088,26 @@ mDNSexport mDNSBool SameDomainLabel(const mDNSu8 *a, const mDNSu8 *b)
 
 #endif // APPLE_OSX_mDNSResponder
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+mDNSexport void GetRandomUUIDLabel(domainlabel *label)
+{
+    uuid_t uuid;
+    uuid_string_t uuidStr;
+    uuid_generate_random(uuid);
+    uuid_unparse_lower(uuid, uuidStr);
+    MakeDomainLabelFromLiteralString(label, uuidStr);
+}
+
+mDNSexport void GetRandomUUIDLocalHostname(domainname *hostname)
+{
+    domainlabel uuidLabel;
+    GetRandomUUIDLabel(&uuidLabel);
+    hostname->c[0] = 0;
+    AppendDomainLabel(hostname, &uuidLabel);
+    AppendLiteralLabelString(hostname, "local");
+}
+#endif
 
 #ifdef UNIT_TEST
 #include "../unittests/mdns_macosx_ut.c"
 #endif
-
index 233681831bcd995bc77d23409191e1ac3b700989..b0a3b12016808ca2bc304ccecf6c2e52f1275a50 100644 (file)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2018 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.
@@ -28,8 +28,8 @@ extern "C" {
 #include <IOKit/pwr_mgt/IOPMLibPrivate.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
-#include <network_information.h>    // for nwi_state
 #include "mDNSEmbeddedAPI.h"        // for domain name structure
+#include "mdns_private.h"           // for mdns_interface_monitor_t struct
 
 #include <net/if.h>
 #include <os/log.h>
@@ -40,10 +40,9 @@ extern "C" {
 #include <dispatch/private.h>
 #endif
 
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
 #define NO_SECURITYFRAMEWORK 1
 #define NO_CFUSERNOTIFICATION 1
-#include <MobileGestalt.h> // for IsAppleTV()
 #endif
 
 #ifndef NO_SECURITYFRAMEWORK
@@ -108,16 +107,16 @@ typedef enum
 
 struct TCPSocket_struct
 {
-    TCPSocketFlags flags;       // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
+    mDNSIPPort port;                // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with mDNSIPPort
+    TCPSocketFlags flags;           // MUST BE SECOND FIELD -- mDNSCore expects every TCPSocket_struct have TCPSocketFlags flags after mDNSIPPort
     TCPConnectionCallback callback;
     int fd;
-    KQueueEntry *kqEntry;
-    KQSocketSet ss;
+    KQueueEntry kqEntry;
 #ifndef NO_SECURITYFRAMEWORK
     SSLContextRef tlsContext;
     pthread_t handshake_thread;
 #endif /* NO_SECURITYFRAMEWORK */
-    domainname hostname;
+    domainname *hostname;
     void *context;
     mDNSBool setup;
     mDNSBool connected;
@@ -126,6 +125,17 @@ struct TCPSocket_struct
     mStatus err;
 };
 
+struct TCPListener_struct
+{
+    TCPAcceptedCallback callback;
+    int fd;
+    KQueueEntry kqEntry;
+    void *context;
+    mDNSAddr_Type addressType;
+    TCPSocketFlags socketFlags;
+    mDNS *m; // So we can call KQueueLock from the SSLHandshake thread
+};
+
 // Value assiged to 'Exists' to indicate the multicast state of the interface has changed.
 #define MulticastStateChanged   2
 
@@ -153,7 +163,6 @@ struct NetworkInterfaceInfoOSX_struct
     int BPF_fd;                                 // -1 uninitialized; -2 requested BPF; -3 failed
     int BPF_mcfd;                               // Socket for our IPv6 ND group membership
     u_int BPF_len;
-    mDNSBool isExpensive;                       // True if this interface has the IFEF_EXPENSIVE flag set.
     mDNSBool isAWDL;                            // True if this interface has the IFEF_AWDL flag set.
 #ifdef MDNSRESPONDER_USES_LIB_DISPATCH_AS_PRIMARY_EVENT_LOOP_MECHANISM
     dispatch_source_t BPF_source;
@@ -167,6 +176,7 @@ struct NetworkInterfaceInfoOSX_struct
 struct mDNS_PlatformSupport_struct
 {
     NetworkInterfaceInfoOSX *InterfaceList;
+    CFMutableArrayRef InterfaceMonitors;
     KQSocketSet permanentsockets;
     int num_mcasts;                             // Number of multicasts received during this CPU scheduling period (used for CPU limiting)
     domainlabel userhostlabel;                  // The hostlabel as it was set in System Preferences the last time we looked
@@ -185,9 +195,6 @@ struct mDNS_PlatformSupport_struct
     SCDynamicStoreRef Store;
     CFRunLoopSourceRef StoreRLS;
     CFRunLoopSourceRef PMRLS;
-    nwi_state_t NWIState;
-    int NWINotifyToken;
-    mDNSBool NWINotifyRegistered;
     int SysEventNotifier;
     KQueueEntry SysEventKQueue;
     IONotificationPortRef PowerPortRef;
@@ -212,8 +219,12 @@ struct mDNS_PlatformSupport_struct
     mDNSu8 v6answers;                  // for A/AAAA from external DNS servers
     mDNSs32 DNSTrigger;                // Time the DNSTrigger was given
     uint64_t LastConfigGeneration;     // DNS configuration generation number
+    mDNSBool if_interface_changed;     // There are some changes that we do not know from LastConfigGeneration, such as
+                                       // if the interface is expensive/constrained or not. Therefore, we need an additional
+                                       // field to determine if the interface has changed.
     UDPSocket UDPProxy;
-    TCPSocket TCPProxy;
+    TCPSocket TCPProxyV4;
+    TCPSocket TCPProxyV6;
     ProxyCallback *UDPProxyCallback;
     ProxyCallback *TCPProxyCallback;
 };
@@ -247,11 +258,11 @@ extern int KQueueSet(int fd, u_short flags, short filter, const KQueueEntry *con
 extern void KQueueLock(void);
 extern void KQueueUnlock(const char* task);
 extern void mDNSPlatformCloseFD(KQueueEntry *kq, int fd);
+extern ssize_t myrecvfrom(const int s, void *const buffer, const size_t max,
+                             struct sockaddr *const from, size_t *const fromlen, mDNSAddr *dstaddr, char *ifname, mDNSu8 *ttl);
 
 extern mDNSBool DictionaryIsEnabled(CFDictionaryRef dict);
 
-extern const char *DNSScopeToString(mDNSu32 scope);
-
 // 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
@@ -283,6 +294,13 @@ extern mDNSInterfaceID AWDLInterfaceID;
 void initializeD2DPlugins(mDNS *const m);
 void terminateD2DPlugins(void);
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+extern void mDNSPlatformUpdateDNSStatus(const DNSQuestion *q);
+extern void mDNSPlatformTriggerDNSRetry(const DNSQuestion *v4q, const DNSQuestion *v6q);
+#endif
+
+extern mdns_interface_monitor_t GetInterfaceMonitorForIndex(uint32_t ifIndex);
+
 #ifdef  __cplusplus
 }
 #endif
index a163640186fbacc43d783ddfeeb67a8048a48224..049f4fc4091594f82c26b46755d180a97b396181 100644 (file)
@@ -2,39 +2,45 @@
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
-    <key>com.apple.wifi.manager-access</key>
-    <true/>
-    <key>com.apple.SystemConfiguration.trailing-edge-agent</key>
-    <true/>
-    <key>com.apple.private.network.socket-delegate</key>
-    <true/>
-    <key>com.apple.private.SCNetworkConnection-proxy-user</key>
-    <true/>
-    <key>com.apple.mDNSResponder_Helper</key>
-    <true/>
-    <key>com.apple.private.network.reserved-port</key>
-    <true/>
-    <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
-    <true/>
-    <key>com.apple.private.snhelper</key>
-    <true/>
-    <key>com.apple.private.necp.match</key>
-    <true/>
-    <key>com.apple.security.network.server</key>
-    <true/>
-    <key>com.apple.security.network.client</key>
-    <true/>
-    <key>com.apple.private.network.awdl.restricted</key>
-    <true/>
-    <key>com.apple.BTServer.allowRestrictedServices</key>
-    <true/>
-    <key>com.apple.BTServer.appleMfgDataAdvertising</key>
-    <true/>
-    <key>com.apple.BTServer.appleMfgDataScanner</key>
-    <true/>
-    <key>com.apple.BTServer.le.att</key>
-    <true/>
-    <key>com.apple.private.network.delegation-whitelist</key>
-    <true/>
+       <key>com.apple.BTServer.allowRestrictedServices</key>
+       <true/>
+       <key>com.apple.BTServer.appleMfgDataAdvertising</key>
+       <true/>
+       <key>com.apple.BTServer.appleMfgDataScanner</key>
+       <true/>
+       <key>com.apple.BTServer.le.att</key>
+       <true/>
+       <key>com.apple.mDNSResponder_Helper</key>
+       <true/>
+       <key>com.apple.networkd_privileged</key>
+       <true/>
+       <key>com.apple.private.necp.match</key>
+       <true/>
+       <key>com.apple.private.network.awdl.restricted</key>
+       <true/>
+       <key>com.apple.private.network.delegation-whitelist</key>
+       <true/>
+       <key>com.apple.private.network.reserved-port</key>
+       <true/>
+       <key>com.apple.private.network.socket-delegate</key>
+       <true/>
+       <key>com.apple.private.SCNetworkConnection-proxy-user</key>
+       <true/>
+       <key>com.apple.private.snhelper</key>
+       <true/>
+       <key>com.apple.private.validated-resolver</key>
+       <true/>
+       <key>com.apple.security.network.client</key>
+       <true/>
+       <key>com.apple.security.network.server</key>
+       <true/>
+       <key>com.apple.SystemConfiguration.SCDynamicStore-write-access</key>
+       <true/>
+       <key>com.apple.SystemConfiguration.trailing-edge-agent</key>
+       <true/>
+       <key>com.apple.wifi.manager-access</key>
+       <true/>
+       <key>com.apple.wifip2pd</key>
+       <true/>
 </dict>
 </plist>
diff --git a/mDNSMacOSX/mDNSResponder.plist b/mDNSMacOSX/mDNSResponder.plist
deleted file mode 100644 (file)
index 6150bc3..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<array>
-<dict>
-       <key>OpenSourceProject</key>
-       <string>libipsec</string>
-       <key>OpenSourceVersion</key>
-       <string>Original version number unavailable, possibly RELENG_4_9_0_RELEASE</string>
-       <key>OpenSourceWebsiteURL</key>
-       <string>http://www.freebsd.org</string>
-       <key>OpenSourceSCM</key>
-       <string>svn export http://svn.freebsd.org/base/release/4.9.0/lib/libipsec</string>
-       <key>OpenSourceImportDate</key>
-       <string>2007-07-31</string>
-       <key>OpenSourceModifications</key>
-       <array>
-               <string>Removed all files except ipsec_strerror.h libpfkey.h pfkey.c</string>
-               <string>Added Apple Computer copyright and Apache license</string>
-               <string>Removed unused include netkey/key_var.h</string>
-               <string>Fixed compiler warnings such as "unused function parameter" and "signed/unsigned comparison"</string>
-               <string>Added code to conditionally compile only on OSX</string>
-               <string>Whitespace changes</string>
-       </array>
-       <key>OpenSourceLicense</key>
-       <string>bsd</string>
-       <key>OpenSourceLicenseFile</key>
-       <string>mDNSResponder.txt</string>
-</dict>
-</array>
-</plist>
index 2918631402b3cb4cf335b7d92c3e44d46f7ea2c3..493e3a23a757c0b60a36110b3ea3f98bbdd34281 100644 (file)
@@ -1,6 +1,5 @@
-; -*- Mode: Scheme; tab-width: 4 -*-
 ;
-; Copyright (c) 2012-2018 Apple Inc. All rights reserved.
+; Copyright (c) 2012-2019 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:
@@ -64,6 +63,7 @@
        (global-name "com.apple.SystemConfiguration.NetworkInformation")
        (global-name "com.apple.system.notification_center")
        (global-name "com.apple.system.logger")
+       (global-name "com.apple.trustd")
        (global-name "com.apple.usymptomsd")
        (global-name "com.apple.webcontentfilter.dns")
        (global-name "com.apple.server.bluetooth")
        (global-name "com.apple.networkd")
        (global-name "com.apple.securityd")
        (global-name "com.apple.wifi.manager")
+       (global-name "com.apple.wifip2pd")
        ; "com.apple.blued" is the name used in pre Lobo builds,
        ; leave it in place while still running roots on pre Lobo targets
        (global-name "com.apple.blued")
        (global-name "com.apple.bluetoothd")
        (global-name "com.apple.mobilegestalt.xpc")
        (global-name "com.apple.ReportCrash.SimulateCrash")
-       (global-name "com.apple.snhelper"))
+       (global-name "com.apple.snhelper")
+       (global-name "com.apple.networkd_privileged"))
 
 (allow mach-register
        (global-name "com.apple.d2d.ipc"))
     (allow sysctl-read sysctl-write
         (sysctl-name "vm.footprint_suspend"))) ; dyld performance reporting
 
+; Used to dump internal state
+; Allows directory lookup, and creating, reading and writing files under /private/var/log/mDNSResponder
+; We know that this sandbox rule seems to give the broader access to mDNSResponder, but given the fact that the directory
+; "/private/var/log/mDNSResponder" is owned by user "_mdnsresponder" who is in "wheel" group, no one else would have the
+; access to this directory, so there is not much security concern.
+(allow file-read* file-write* (subpath "/private/var/log/mDNSResponder"))
diff --git a/mDNSMacOSX/mDNSResponder.txt b/mDNSMacOSX/mDNSResponder.txt
deleted file mode 100644 (file)
index f798e56..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-1)
- * 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.
-
-2)
- * 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.
index 5df1073dd6662e09e5778b9ee06c48418f979857..b89ec2c82f0d42dde7ec51d140a5729d8ab0000e 100644 (file)
@@ -7,44 +7,25 @@
        objects = {
 
 /* Begin PBXAggregateTarget section */
-               00AD62BB032D7A0C0CCA2C71 /* Build More */ = {
+               03067D640C83A3700022BE1F /* Build Core */ = {
                        isa = PBXAggregateTarget;
-                       buildConfigurationList = D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */;
-                       buildPhases = (
-                       );
-                       dependencies = (
-                               03067D860C849CC30022BE1F /* PBXTargetDependency */,
-                               D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */,
-                               D284BF300ADD81630027CCDF /* PBXTargetDependency */,
-                               0C52E92F1E96AD74006EFE7B /* PBXTargetDependency */,
-                               0C4F36B41E206711005A536B /* PBXTargetDependency */,
-                       );
-                       name = "Build More";
-                       productName = "Build All";
-               };
-               03067D640C83A3700022BE1F /* Build Some */ = {
-                       isa = PBXAggregateTarget;
-                       buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */;
+                       buildConfigurationList = 03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Core" */;
                        buildPhases = (
                        );
                        dependencies = (
                                03067D680C83A3830022BE1F /* PBXTargetDependency */,
                                03067D6E0C83A39C0022BE1F /* PBXTargetDependency */,
-                               03067D6C0C83A3920022BE1F /* PBXTargetDependency */,
-                               BD7833F01ABA5E3500EC51ED /* PBXTargetDependency */,
-                               0C1596C71D7751AD00E09998 /* PBXTargetDependency */,
-                               84C5B3411665544B00C324A8 /* PBXTargetDependency */,
-                               217A4C49138EE14C000A5BA8 /* PBXTargetDependency */,
-                               BD9BA7721EAFA3D500658CCF /* PBXTargetDependency */,
-                       );
-                       name = "Build Some";
+                               B7237FE62194D99200B113B1 /* PBXTargetDependency */,
+                               D4528FFE21F91263004D61BF /* PBXTargetDependency */,
+                       );
+                       name = "Build Core";
                        productName = "Build Some";
                };
                2141DCF8123FFB5D0086D23E /* SystemLibraries */ = {
                        isa = PBXAggregateTarget;
                        buildConfigurationList = 2141DD08123FFB830086D23E /* Build configuration list for PBXAggregateTarget "SystemLibraries" */;
                        buildPhases = (
-                               B7E2951A1E259AA000C42F6D /* ShellScript */,
+                               B7E2951A1E259AA000C42F6D /* Copy Sandbox Profile */,
                        );
                        dependencies = (
                                2141DD0E123FFC960086D23E /* PBXTargetDependency */,
                        name = SystemLibrariesStatic;
                        productName = SystemLibrariesStatic;
                };
-               B7C4B7251E71BD5000136C7A /* Build Some iOS */ = {
+               B70F38A5217AA6CE00612D3A /* Build Extras */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = B70F38B0217AA6CE00612D3A /* Build configuration list for PBXAggregateTarget "Build Extras" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               B70F38A6217AA6CE00612D3A /* PBXTargetDependency */,
+                               B70F38AE217AA6CE00612D3A /* PBXTargetDependency */,
+                               B70F38A8217AA6CE00612D3A /* PBXTargetDependency */,
+                               B7237FDA2194D0EF00B113B1 /* PBXTargetDependency */,
+                       );
+                       name = "Build Extras";
+                       productName = "Build Extras";
+               };
+               B718416921F8D0A600CA42AD /* Build Services */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = B718417221F8D0A600CA42AD /* Build configuration list for PBXAggregateTarget "Build Services" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               B718416E21F8D0A600CA42AD /* PBXTargetDependency */,
+                       );
+                       name = "Build Services";
+                       productName = "Build Some";
+               };
+               B7DB5895215EB4DD0054CD46 /* Build Extras-iOS */ = {
+                       isa = PBXAggregateTarget;
+                       buildConfigurationList = B7DB5898215EB4DD0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-iOS" */;
+                       buildPhases = (
+                       );
+                       dependencies = (
+                               B7237FDE2194D16E00B113B1 /* PBXTargetDependency */,
+                               B7DB589A215EB4F70054CD46 /* PBXTargetDependency */,
+                       );
+                       name = "Build Extras-iOS";
+                       productName = "Build UI";
+               };
+               B7DB589D215EB61C0054CD46 /* Build Extras-macOS */ = {
                        isa = PBXAggregateTarget;
-                       buildConfigurationList = B7C4B7281E71BD5000136C7A /* Build configuration list for PBXAggregateTarget "Build Some iOS" */;
+                       buildConfigurationList = B7DB58A2215EB61C0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-macOS" */;
                        buildPhases = (
                        );
                        dependencies = (
-                               B7C4B72E1E71BE3500136C7A /* PBXTargetDependency */,
-                               B7C4B72C1E71BD6000136C7A /* PBXTargetDependency */,
+                               B7237FDC2194D16900B113B1 /* PBXTargetDependency */,
+                               B7DB58C2215F04490054CD46 /* PBXTargetDependency */,
+                               B7DB58A0215EB61C0054CD46 /* PBXTargetDependency */,
+                               B7DB58A6215ED26D0054CD46 /* PBXTargetDependency */,
                        );
-                       name = "Build Some iOS";
-                       productName = "Build More iOS";
+                       name = "Build Extras-macOS";
+                       productName = "Build UI";
                };
                FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */ = {
                        isa = PBXAggregateTarget;
                        buildPhases = (
                        );
                        dependencies = (
-                               FFB7657D0AEED97F00583A2C /* PBXTargetDependency */,
                                2141DCFD123FFB7D0086D23E /* PBXTargetDependency */,
                        );
                        name = "Build All";
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
-               0C10EC281DDB956E00D7A0E3 /* LocalOnlyTimeoutTests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */; };
                0C1596B51D7740B500E09998 /* mDNSPosix.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B31D7740B500E09998 /* mDNSPosix.c */; };
                0C1596B61D7740B500E09998 /* NetMonitor.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B41D7740B500E09998 /* NetMonitor.c */; };
                0C1596B81D7740C100E09998 /* mDNSUNP.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C1596B71D7740C100E09998 /* mDNSUNP.c */; };
-               0C1596B91D7740CD00E09998 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
                0C1596BA1D7740D200E09998 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
                0C1596BB1D7740D700E09998 /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
                0C1596BC1D7740DC00E09998 /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
                0C1596BE1D7740E900E09998 /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
                0C1596BF1D7740EF00E09998 /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
                0C1596C01D77410A00E09998 /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
-               0C5674B41DA2BF8600AF3367 /* mDNSCoreReceiveTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */; };
                0C635A891E9418D90026C796 /* bjIPAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7D1E9418D90026C796 /* bjIPAddr.cpp */; };
                0C635A8A1E9418D90026C796 /* bjMACAddr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7E1E9418D90026C796 /* bjMACAddr.cpp */; };
                0C635A8B1E9418D90026C796 /* bjsocket.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A7F1E9418D90026C796 /* bjsocket.cpp */; };
                0C635A931E9418D90026C796 /* LLRBTree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A871E9418D90026C796 /* LLRBTree.cpp */; };
                0C635A941E9418D90026C796 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C635A881E9418D90026C796 /* main.cpp */; };
                0C6FB90F1D77767300DF6F51 /* mDNSNetMonitor.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0C6FB90E1D775FE900DF6F51 /* mDNSNetMonitor.8 */; };
-               0C7C00501DD553640078BA89 /* unittest_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C00491DD553490078BA89 /* unittest_common.c */; };
-               0C7C00511DD5536E0078BA89 /* CNameRecordTests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C004F1DD553490078BA89 /* CNameRecordTests.c */; };
-               0CB1C7FC1D9C5C1100A5939F /* D2D.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C7633D1D777B8C0077AFCA /* D2D.c */; };
                21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
                21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
                2124FA2C1471E98C0021D7BB /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
                21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
                21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
                21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
-               21B830A21D8A63A300AE2001 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 219D5541149ED645004464AE /* libxml2.dylib */; };
-               21B830A31D8A63AE00AE2001 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 65713D46025A293200000109 /* SystemConfiguration.framework */; };
-               21B830A41D8A63BB00AE2001 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
-               21B830A51D8A63CB00AE2001 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
-               21B830A61D8A63E400AE2001 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */; };
                21B830A71D8A641F00AE2001 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
                21B830A81D8A642200AE2001 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
                21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
-               21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
-               21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
                21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
                21F51DC11B3541940070B05C /* com.apple.mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */; };
                21F51DC31B3541F50070B05C /* com.apple.mDNSResponderHelper.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */; };
                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 */; };
                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 */; };
                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 */; };
                2EDC5E750C39EA640092701B /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
-               371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */; };
-               371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */; };
-               373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */ = {isa = PBXBuildFile; fileRef = 3732020F1BAB4349007DE806 /* DNSMessageTest.c */; };
-               37538DFC1D7A424500226BE4 /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
-               37538DFD1D7A425700226BE4 /* helper.h in Headers */ = {isa = PBXBuildFile; fileRef = 2E96A5250C39BE480087C4D2 /* helper.h */; };
-               37538DFE1D7A427B00226BE4 /* helper-server.h in Headers */ = {isa = PBXBuildFile; fileRef = 2EDC5E720C39EA640092701B /* helper-server.h */; };
-               37538DFF1D7A428500226BE4 /* helpermsg-types.h in Headers */ = {isa = PBXBuildFile; fileRef = 2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */; };
-               37538E001D7A429900226BE4 /* CryptoAlg.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F4B145B2AE100939099 /* CryptoAlg.h */; };
-               37538E011D7A429900226BE4 /* CryptoSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21A57F52145B2B1400939099 /* CryptoSupport.h */; };
-               37538E021D7A42B000226BE4 /* nsec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2B1471E98C0021D7BB /* nsec.h */; };
-               37538E031D7A42B000226BE4 /* nsec3.h in Headers */ = {isa = PBXBuildFile; fileRef = 2127A47615C3C7B900A857FC /* nsec3.h */; };
-               37538E041D7A42BE00226BE4 /* BLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA21C90A7B5004F25CC /* BLE.h */; };
-               37538E051D7A42D000226BE4 /* DNSServiceDiscoveryDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */; };
-               37538E061D7A42DA00226BE4 /* dnsproxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 218E8E50156D8C0300720DA0 /* dnsproxy.h */; };
-               37538E071D7A42E200226BE4 /* coreBLE.h in Headers */ = {isa = PBXBuildFile; fileRef = 22448EA51C90A82D004F25CC /* coreBLE.h */; };
-               37538E081D7A42F000226BE4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
-               37538E091D7A42FC00226BE4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
-               37538E0A1D7A430600226BE4 /* anonymous.h in Headers */ = {isa = PBXBuildFile; fileRef = 21DD8FBE161E9A250033C8F8 /* anonymous.h */; };
-               37538E0B1D7A432200226BE4 /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA3F0871C48DB6D0054FB4B /* Metrics.h */; };
-               37538E0C1D7A435200226BE4 /* dnssec.h in Headers */ = {isa = PBXBuildFile; fileRef = 2124FA2F1471E9B50021D7BB /* dnssec.h */; };
-               37538E0D1D7A437300226BE4 /* DNSSECSupport.h in Headers */ = {isa = PBXBuildFile; fileRef = 21070E5E16486B9000A69507 /* DNSSECSupport.h */; };
-               37538E141D7A43B600226BE4 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 37538E131D7A43B600226BE4 /* libicucore.dylib */; };
-               37538E1B1D7A442300226BE4 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
-               37538E1C1D7A449000226BE4 /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BDA3F0881C48DB6D0054FB4B /* Metrics.m */; };
-               37538E1D1D7A449D00226BE4 /* coreBLE.m in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA61C90A82D004F25CC /* coreBLE.m */; };
-               37538E1E1D7A4F9D00226BE4 /* anonymous.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DD8FBD161E9A250033C8F8 /* anonymous.c */; };
-               37538E1F1D7A504F00226BE4 /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
-               3771F67D1BA387DD0072355E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9351BA386E70092AC61 /* main.c */; };
-               37812CD41D7A307200F34505 /* BLE.c in Sources */ = {isa = PBXBuildFile; fileRef = 22448EA11C90A7B5004F25CC /* BLE.c */; };
-               37812CD71D7A307200F34505 /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
-               37812CD81D7A307200F34505 /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
-               37812CD91D7A307200F34505 /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
-               37812CDA1D7A307200F34505 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
-               37812CDB1D7A307200F34505 /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
-               37812CDE1D7A307200F34505 /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
-               37812CDF1D7A307200F34505 /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
-               37812CE01D7A307200F34505 /* dnssd_clientlib.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38620AEEDB090065B80A /* dnssd_clientlib.c */; };
-               37812CE11D7A307300F34505 /* dnssd_clientstub.c in Sources */ = {isa = PBXBuildFile; fileRef = FFFA38640AEEDB130065B80A /* dnssd_clientstub.c */; };
-               37812CE21D7A307300F34505 /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
-               37812CE31D7A307300F34505 /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
-               37812CE41D7A307300F34505 /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
-               37812CE51D7A307300F34505 /* GenLinkedList.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE2C057E8F660085CAD0 /* GenLinkedList.c */; };
-               37812CE91D7A307300F34505 /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
-               37812CEA1D7A307300F34505 /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
-               37812CEB1D7A307300F34505 /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
-               37812CEC1D7A307300F34505 /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
-               37812CED1D7A307300F34505 /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
-               37812CEE1D7A307300F34505 /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
-               37812CEF1D7A307300F34505 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; };
-               37812CF11D7A307300F34505 /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
-               37812CF21D7A307300F34505 /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
-               37812CF31D7A307300F34505 /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
-               37812CF41D7A307300F34505 /* uDNSPathEvalulation.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */; };
-               37812CF51D7A307300F34505 /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
-               37812CF61D7A307300F34505 /* dnsctl_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */; };
-               37812CF71D7A307300F34505 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
-               37DDE9331BA383D30092AC61 /* unittest.c in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE9271BA3825C0092AC61 /* unittest.c */; };
-               37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
-               4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */; };
-               4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */; };
                4AAE0C9A0C68EA81003882A5 /* mDNSResponderHelper.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */; };
                4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */ = {isa = PBXBuildFile; fileRef = 4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */; };
                4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */; };
-               72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */ = {isa = PBXBuildFile; fileRef = 72FB545A166D5F960090B2D9 /* dnsctl.c */; };
                789036921F7AC1FA0077A962 /* libnetwork.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 789036911F7AC1F90077A962 /* libnetwork.tbd */; };
-               789036931F7AC2050077A962 /* libnetwork.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 789036911F7AC1F90077A962 /* libnetwork.tbd */; };
-               8415A6571897109000BDBA26 /* libdns_services.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 8415A6561897109000BDBA26 /* libdns_services.dylib */; };
-               8417375C1B967D37000CD5C2 /* dnsctl_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 8417375A1B967CBE000CD5C2 /* dnsctl_server.c */; };
-               848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 848DA5C6165477E000D2E8B4 /* xpc_services.c */; };
-               848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5C9165477EB00D2E8B4 /* xpc_services.h */; };
-               848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* dns_xpc.h */; };
+               848DA5D616547F7200D2E8B4 /* xpc_clients.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* xpc_clients.h */; };
                84C5B33C166553F100C324A8 /* dns_services.c in Sources */ = {isa = PBXBuildFile; fileRef = 84C5B339166553AF00C324A8 /* dns_services.c */; };
                84F4C090188F050200D1E1DE /* dns_services.h in Headers */ = {isa = PBXBuildFile; fileRef = 84F4C08F188F04CF00D1E1DE /* dns_services.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               894A55D722C438AF008CDEA1 /* bats_test_proxy.sh in Resources */ = {isa = PBXBuildFile; fileRef = 894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */; };
+               897729B22202A5370018FAEB /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
+               897729B32202A5370018FAEB /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+               897729B42202A5370018FAEB /* dso-transport.h in Headers */ = {isa = PBXBuildFile; fileRef = 897729B02202A5370018FAEB /* dso-transport.h */; };
+               897729B52202A5370018FAEB /* dso.h in Headers */ = {isa = PBXBuildFile; fileRef = 897729B12202A5370018FAEB /* dso.h */; };
+               897729B72202A5480018FAEB /* dnssd_clientshim.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729B62202A5480018FAEB /* dnssd_clientshim.c */; };
+               898E98342203619800812DC6 /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+               898E98352203619800812DC6 /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
+               898E98362203621200812DC6 /* dnssd_clientshim.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729B62202A5480018FAEB /* dnssd_clientshim.c */; };
+               898E98372203621200812DC6 /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+               898E98382203621200812DC6 /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
+               898E98392203633800812DC6 /* dnssd_clientshim.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729B62202A5480018FAEB /* dnssd_clientshim.c */; };
+               898E983A2203633800812DC6 /* dso-transport.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AF2202A5370018FAEB /* dso-transport.c */; };
+               898E983B2203633800812DC6 /* dso.c in Sources */ = {isa = PBXBuildFile; fileRef = 897729AE2202A5370018FAEB /* dso.c */; };
                B7016F521D5D0D2900107E7C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F511D5D0D2900107E7C /* Localizable.strings */; };
                B701E7041D9DD811008F3022 /* BonjourSCStore.m in Sources */ = {isa = PBXBuildFile; fileRef = B701E7031D9DD811008F3022 /* BonjourSCStore.m */; };
                B7024D171E82FA9500312DEF /* com.apple.preference.bonjour.tool.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
                B71C8B091E79F2CD00E99939 /* BonjourSCStore.m in Sources */ = {isa = PBXBuildFile; fileRef = B701E7031D9DD811008F3022 /* BonjourSCStore.m */; };
+               B72D38B41ECB96ED00B10E39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B72D38B31ECB96ED00B10E39 /* Localizable.strings */; };
                B7325FE81DA4737400663834 /* CNBrowseDomainsController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7325FE71DA4737400663834 /* CNBrowseDomainsController.m */; };
                B7325FF71DA47F9100663834 /* CNDomainBrowserViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = B7A214081D1B29D6005F7DD9 /* CNDomainBrowserViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
                B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */; };
                B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
                B7325FFD1DA4809400663834 /* DomainBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = B74EC1271D494C5800A1D155 /* DomainBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; };
                B7325FFF1DA480A500663834 /* DomainBrowser.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */; };
+               B7473E671EC3954400D31B9D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E661EC3954400D31B9D /* AppDelegate.m */; };
+               B7473E691EC3954400D31B9D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E681EC3954400D31B9D /* main.m */; };
+               B7473E6C1EC3954400D31B9D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E6B1EC3954400D31B9D /* ViewController.m */; };
+               B7473E6E1EC3954400D31B9D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B7473E6D1EC3954400D31B9D /* Assets.xcassets */; };
+               B7473E711EC3954400D31B9D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B7473E6F1EC3954400D31B9D /* Main.storyboard */; };
+               B7473E831EC395C300D31B9D /* SafariExtensionHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E821EC395C300D31B9D /* SafariExtensionHandler.m */; };
+               B7473E861EC395C300D31B9D /* SafariExtensionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B7473E851EC395C300D31B9D /* SafariExtensionViewController.m */; };
+               B7473E891EC395C300D31B9D /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = B7473E871EC395C300D31B9D /* SafariExtensionViewController.xib */; };
+               B7473E911EC395C300D31B9D /* Bonjour Safari Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+               B7473E961EC3C77800D31B9D /* CNDomainBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */; };
+               B7473E971EC3C77D00D31B9D /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
+               B7473E981EC3C78300D31B9D /* _CNDomainBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA5E1D107573005E24CF /* _CNDomainBrowser.m */; };
+               B7473E991EC3C86600D31B9D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
                B74A96261DD4EDE60084A8C5 /* Preferences.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B74A96251DD4EDE60084A8C5 /* Preferences.framework */; };
+               B74F16F4211BA55400BEBE84 /* DNSMessageTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */; };
                B74F2B461E82FEAE0084960E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
                B74F2B471E82FEFE0084960E /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
                B75700241E8347A6005CD56C /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B75700231E8347A6005CD56C /* InfoPlist.strings */; };
+               B76373761ECA25DE00B9404A /* CNServiceBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B76373751ECA25DE00B9404A /* CNServiceBrowserView.m */; };
                B764319F1DB0423800DB376D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
                B76431A01DB0423900DB376D /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
                B76783C11E82D8F500DA271E /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B76783BC1E82D8F500DA271E /* main.m */; };
                B7706AAF1DBA9C1800593FD5 /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
                B778EE4D1D51113800C814A2 /* HostnameController.m in Sources */ = {isa = PBXBuildFile; fileRef = B778EE4B1D51113800C814A2 /* HostnameController.m */; };
                B778EE501D51287100C814A2 /* BonjourSettingsController.m in Sources */ = {isa = PBXBuildFile; fileRef = B778EE4F1D51287100C814A2 /* BonjourSettingsController.m */; };
+               B78A9C30223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib in Resources */ = {isa = PBXBuildFile; fileRef = B78A9C2E223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib */; };
                B79568351D53F693005E3BED /* DomainBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = B74EC12B1D494C7200A1D155 /* DomainBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; };
                B79568361D53F69B005E3BED /* CNDomainBrowserView.h in Headers */ = {isa = PBXBuildFile; fileRef = B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */; settings = {ATTRIBUTES = (Public, ); }; };
                B799209F1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
                B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
                B79920A21DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */; };
                B79920A41DA6C49700C6E02B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B79920A31DA6C49700C6E02B /* Assets.xcassets */; };
+               B79FA14B211CE8CA00B7861E /* DNSCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F60587CEF6001880B3 /* DNSCommon.c */; };
+               B7A8618921274BFC00E81CC3 /* ResourceRecordTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */; };
+               B7A8618B21274FA200E81CC3 /* mDNSCoreReceiveTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */; };
+               B7A861952127806600E81CC3 /* unittest_common.c in Sources */ = {isa = PBXBuildFile; fileRef = 0C7C00491DD553490078BA89 /* unittest_common.c */; };
+               B7A861972127845800E81CC3 /* CNameRecordTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A861962127845700E81CC3 /* CNameRecordTest.m */; };
+               B7A86199212B074500E81CC3 /* LocalOnlyTimeoutTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */; };
+               B7A8619B212B34CF00E81CC3 /* unittest.h in Headers */ = {isa = PBXBuildFile; fileRef = B7A8619A212B34CF00E81CC3 /* unittest.h */; };
+               B7A861A1212B3FF400E81CC3 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF2609FA07B4433800CE10E5 /* Cocoa.framework */; };
+               B7A861A2212B408D00E81CC3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7F869685066EE02400D2A2DC /* Security.framework */; };
+               B7A861A3212B409200E81CC3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00CA213D02786FC30CCA2C71 /* IOKit.framework */; };
+               B7A861A7212B410D00E81CC3 /* libxml2.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A4212B40BC00E81CC3 /* libxml2.tbd */; };
+               B7A861A8212B411200E81CC3 /* libicucore.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A6212B40BC00E81CC3 /* libicucore.tbd */; };
+               B7A861A9212B411600E81CC3 /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A5212B40BC00E81CC3 /* Network.framework */; };
+               B7CEF6131F6354AA008B08D3 /* ToolbarItemIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = B7CEF6121F635404008B08D3 /* ToolbarItemIcon.png */; };
                B7D566C91E81DA0000E43008 /* com.apple.preference.bonjour.remoteservice.xpc in CopyFiles */ = {isa = PBXBuildFile; fileRef = B7D566BA1E81D8FD00E43008 /* com.apple.preference.bonjour.remoteservice.xpc */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
                B7D566CD1E81DDB600E43008 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
                B7D566CE1E81DDB600E43008 /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */; };
                B7D6CA7A1D107714005E24CF /* CNDomainBrowserView.m in Sources */ = {isa = PBXBuildFile; fileRef = B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */; };
                B7E06B0D1DBA9DFE00E4580C /* ClientCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FF5852100DD27BD300862BDF /* ClientCommon.c */; };
                B7E06B0E1DBA9E9700E4580C /* DomainBrowser.strings in Resources */ = {isa = PBXBuildFile; fileRef = B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */; };
+               B7EEF7C1212601460093828F /* mDNSMacOSX.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEB022EAF7200000109 /* mDNSMacOSX.c */; };
+               B7EEF7C2212602EC0093828F /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
+               B7EEF7C4212603B20093828F /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */; };
+               B7EEF7C5212603D50093828F /* CryptoAlg.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F4A145B2AE100939099 /* CryptoAlg.c */; };
+               B7EEF7CA2126046A0093828F /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
+               B7EEF7CB2126048F0093828F /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
+               B7EEF7CC212604A80093828F /* LegacyNATTraversal.c in Sources */ = {isa = PBXBuildFile; fileRef = 7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */; };
+               B7EEF7CD212604CB0093828F /* DNSDigest.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F461DB5062DBF2900672BF3 /* DNSDigest.c */; };
+               B7EEF7D0212605170093828F /* D2D.c in Sources */ = {isa = PBXBuildFile; fileRef = 22C7633D1D777B8C0077AFCA /* D2D.c */; };
+               B7EEF7D6212606F50093828F /* uDNSPathEvalulation.c in Sources */ = {isa = PBXBuildFile; fileRef = 216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */; };
+               B7EEF7D7212607520093828F /* mDNSDebug.c in Sources */ = {isa = PBXBuildFile; fileRef = DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */; };
+               B7EEF7D82126076F0093828F /* dnssec.c in Sources */ = {isa = PBXBuildFile; fileRef = 213BDC6C147319F400000896 /* dnssec.c */; };
+               B7EEF7D9212607C40093828F /* nsec.c in Sources */ = {isa = PBXBuildFile; fileRef = 2124FA321471E9DE0021D7BB /* nsec.c */; };
+               B7EEF7DA212608F50093828F /* nsec3.c in Sources */ = {isa = PBXBuildFile; fileRef = 2127A47515C3C7B900A857FC /* nsec3.c */; };
+               B7EEF7DB2126090D0093828F /* DNSSECSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21070E5D16486B9000A69507 /* DNSSECSupport.c */; };
+               B7EEF7E021260A1F0093828F /* helper-stubs.c in Sources */ = {isa = PBXBuildFile; fileRef = 2E96A52D0C39C1A50087C4D2 /* helper-stubs.c */; };
+               B7EEF7E221260A610093828F /* PlatformCommon.c in Sources */ = {isa = PBXBuildFile; fileRef = FFCB6D73075D539900B8AF62 /* PlatformCommon.c */; };
+               B7EEF7E421260DC90093828F /* dnssd_ipc.c in Sources */ = {isa = PBXBuildFile; fileRef = F5E11B5A04A28126019798ED /* dnssd_ipc.c */; };
+               B7EEF7E521260DE80093828F /* daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBEC022EAF7200000109 /* daemon.c */; };
+               B7EEF7E921260E4C0093828F /* CryptoSupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21A57F51145B2B1400939099 /* CryptoSupport.c */; };
+               B7EEF7EA212613260093828F /* uds_daemon.c in Sources */ = {isa = PBXBuildFile; fileRef = F525E72804AA167501F1CF4D /* uds_daemon.c */; };
+               B7EEF7EC212613D10093828F /* dnsproxy.c in Sources */ = {isa = PBXBuildFile; fileRef = 218E8E4F156D8C0300720DA0 /* dnsproxy.c */; };
+               B7EEF7ED212613D50093828F /* DNSProxySupport.c in Sources */ = {isa = PBXBuildFile; fileRef = 21DED43415702C0F0060B6B9 /* DNSProxySupport.c */; };
                BD03E88D1AD31278005E8A81 /* SymptomReporter.c in Sources */ = {isa = PBXBuildFile; fileRef = BD03E88C1AD31278005E8A81 /* SymptomReporter.c */; };
+               BD11267121DB1B25006115E6 /* dnssd_server.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11267021DB1AFE006115E6 /* dnssd_server.h */; };
+               BD11267221DB1B29006115E6 /* dnssd_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */; };
+               BD11267321DB1B34006115E6 /* dnssd_server.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11266F21DB1AFE006115E6 /* dnssd_server.c */; };
+               BD11267421DB1B4D006115E6 /* dnssd_xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */; };
+               BD11267821DB2A9B006115E6 /* dnssd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11267521DB2A9A006115E6 /* dnssd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               BD11267921DB2A9B006115E6 /* dnssd_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD11267621DB2A9A006115E6 /* dnssd_object.m */; };
+               BD11267A21DB2A9B006115E6 /* dnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11267721DB2A9A006115E6 /* dnssd.c */; };
+               BD11267C21DB2C7C006115E6 /* dnssd_object.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11267B21DB2C7C006115E6 /* dnssd_object.h */; };
+               BD11267E21DB3019006115E6 /* dnssd_xpc.h in Headers */ = {isa = PBXBuildFile; fileRef = BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */; };
+               BD11267F21DB303F006115E6 /* dnssd_xpc.c in Sources */ = {isa = PBXBuildFile; fileRef = BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */; };
+               BD1628CF2168B02700020528 /* ClientRequests.h in Headers */ = {isa = PBXBuildFile; fileRef = BD1628CD2168B02600020528 /* ClientRequests.h */; };
+               BD1628D02168B02700020528 /* ClientRequests.c in Sources */ = {isa = PBXBuildFile; fileRef = BD1628CE2168B02700020528 /* ClientRequests.c */; };
                BD28AE8F207B892D00F0B257 /* bonjour-mcast-diagnose in Copy diagnose scripts */ = {isa = PBXBuildFile; fileRef = BD28AE8E207B88F600F0B257 /* bonjour-mcast-diagnose */; };
+               BD2A15B9225ED30C00BEA50A /* mdns_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BD2A15B8225ED2E500BEA50A /* mdns_private.h */; };
+               BD2A15BA225ED31C00BEA50A /* mdns.c in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B7225ED2E500BEA50A /* mdns.c */; };
+               BD2A15BB225ED33C00BEA50A /* mdns_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B5225ED2E500BEA50A /* mdns_object.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+               BD2A15BC225ED38600BEA50A /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A861A5212B40BC00E81CC3 /* Network.framework */; };
                BD41B27D203EBE6100A53629 /* dns_sd.h in Headers */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; settings = {ATTRIBUTES = (Public, ); }; };
                BD41F9C4209B60AC0077F8B6 /* libpcap.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BD41F9C3209B60AC0077F8B6 /* libpcap.tbd */; };
+               BD42EE2021DB41970053A651 /* libobjc.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BD42EE1F21DB41970053A651 /* libobjc.tbd */; };
                BD691B2A1ED2F47100E6F317 /* DNS64.c in Sources */ = {isa = PBXBuildFile; fileRef = BD691B281ED2F43200E6F317 /* DNS64.c */; };
                BD691B2B1ED2F4AB00E6F317 /* DNS64.h in Headers */ = {isa = PBXBuildFile; fileRef = BD691B291ED2F43200E6F317 /* DNS64.h */; };
                BD75E940206ADEF400656ED3 /* com.apple.mDNSResponder.plist in Copy AppleInternal Logging Profile */ = {isa = PBXBuildFile; fileRef = BDB61846206ADDDF00AFF600 /* com.apple.mDNSResponder.plist */; };
                BD893CE5206C0D980055F9E7 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */; };
                BD893CE7206C0EAF0055F9E7 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD893CE6206C0EAF0055F9E7 /* CoreFoundation.framework */; };
-               BD9BA7551EAF91FB00658CCF /* dnssdutil.c in Sources */ = {isa = PBXBuildFile; fileRef = BD9BA7541EAF91E700658CCF /* dnssdutil.c */; };
+               BD93516E21E369B90078582E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
+               BD97754C221D643600F68FFC /* dnssdutil.c in Sources */ = {isa = PBXBuildFile; fileRef = BD97754B221D643500F68FFC /* dnssdutil.c */; };
+               BD97754F221D64BF00F68FFC /* DNSMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = BD97754D221D64BF00F68FFC /* DNSMessage.c */; };
+               BD977550221D64BF00F68FFC /* DNSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = BD97754E221D64BF00F68FFC /* DNSMessage.h */; };
+               BD98A798213A417C0002EC47 /* mDNSResponder.plist in Copy BATS test plist */ = {isa = PBXBuildFile; fileRef = BD98A796213A3EAE0002EC47 /* mDNSResponder.plist */; };
                BD9BA7581EAF929C00658CCF /* CoreUtils.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BD9BA7571EAF929C00658CCF /* CoreUtils.framework */; };
                BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA3F0891C48DB910054FB4B /* Foundation.framework */; };
                BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA3F0871C48DB6D0054FB4B /* Metrics.h */; };
                BDA3F08F1C48DCA50054FB4B /* Metrics.m in Sources */ = {isa = PBXBuildFile; fileRef = BDA3F0881C48DB6D0054FB4B /* Metrics.m */; };
+               BDA82B8A22BF8A7000A31CBE /* libdns_services.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = BDA82B8922BF8A7000A31CBE /* libdns_services.tbd */; };
                BDA9A7881B3A924C00523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               BDA9A7891B3A92A500523835 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BDAF4BC020B52D3D0062219E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BDAF4BBF20B52D3D0062219E /* CFNetwork.framework */; };
-               BDB04221203FEF4C00419961 /* dns_sd.h in Headers */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               BDB04222203FEF4D00419961 /* dns_sd.h in Headers */ = {isa = PBXBuildFile; fileRef = FFA572630AF190C20055A0F1 /* dns_sd.h */; settings = {ATTRIBUTES = (Public, ); }; };
-               BDB04223203FF18000419961 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
-               BDB04224203FF18000419961 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
                BDB61845206ADB9D00AFF600 /* com.apple.mDNSResponder.plist in Copy Base Logging Profile */ = {isa = PBXBuildFile; fileRef = BDB61843206ADB7700AFF600 /* com.apple.mDNSResponder.plist */; };
                BDBF9B941ED74B9C001498A8 /* DNS64State.h in Headers */ = {isa = PBXBuildFile; fileRef = BDBF9B931ED74B8C001498A8 /* DNS64State.h */; };
-               BDE5BCCA226D7181009C723C /* DNSCommon.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE5BCC9226D7181009C723C /* DNSCommon.h */; };
-               BDE5BCCC226D7198009C723C /* uDNS.h in Headers */ = {isa = PBXBuildFile; fileRef = BDE5BCCB226D7197009C723C /* uDNS.h */; };
-               BDF8BB902208E2A800419B62 /* mDNSResponder.plist in Copy BATS test plist */ = {isa = PBXBuildFile; fileRef = BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */; };
+               BDF2D02A2169961900D0DBF5 /* ClientRequests.c in Sources */ = {isa = PBXBuildFile; fileRef = BD1628CE2168B02700020528 /* ClientRequests.c */; };
+               BDF2D02C2169B77C00D0DBF5 /* SymptomReporter.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF2D02B2169B77B00D0DBF5 /* SymptomReporter.h */; };
+               BDF2D02E216A25E800D0DBF5 /* ApplePlatformFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = BDF2D02D216A25E800D0DBF5 /* ApplePlatformFeatures.h */; };
                D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */ = {isa = PBXBuildFile; fileRef = F5E11B5B04A28126019798ED /* dnssd_ipc.h */; };
                D284BE580ADD80740027CCDF /* mDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 6575FBE9022EAF5A00000109 /* mDNS.c */; };
                D284BE590ADD80740027CCDF /* uDNS.c in Sources */ = {isa = PBXBuildFile; fileRef = 7F18A9F70587CEF6001880B3 /* uDNS.c */; };
                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 */; };
                D284BEFE0ADD80B00027CCDF /* DNSServiceDiscoveryPref.m in Sources */ = {isa = PBXBuildFile; fileRef = FFFB0DAC07B43CBA00B88D48 /* DNSServiceDiscoveryPref.m */; };
                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 */; };
+               D401238B227284FE006C9BBE /* mdns.c in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B7225ED2E500BEA50A /* mdns.c */; };
+               D401238D22728506006C9BBE /* mdns_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BD2A15B8225ED2E500BEA50A /* mdns_private.h */; };
+               D401238F227286BE006C9BBE /* mdns_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B5225ED2E500BEA50A /* mdns_object.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+               D40123912272B6E3006C9BBE /* mdns_object.m in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B5225ED2E500BEA50A /* mdns_object.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
+               D40123922272B7A7006C9BBE /* mdns.c in Sources */ = {isa = PBXBuildFile; fileRef = BD2A15B7225ED2E500BEA50A /* mdns.c */; };
+               D421B3DF22178BE700D35C20 /* system_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = D421B3DD22178BE700D35C20 /* system_utilities.h */; };
+               D421B3E022178BE700D35C20 /* system_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D421B3DE22178BE700D35C20 /* system_utilities.c */; };
+               D448F7A8222DAB8E0069E1D2 /* bats_test_state_dump.sh in Copy script-based unit tests */ = {isa = PBXBuildFile; fileRef = D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */; };
+               D448F7A8222DAB8E0069E1D3 /* bats_test_proxy.sh in Copy script-based unit tests */ = {isa = PBXBuildFile; fileRef = 894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */; };
+               D448F7AC222DCB5C0069E1D2 /* libarchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D448F7AB222DCB5B0069E1D2 /* libarchive.tbd */; };
+               D448F7AF222DCC8F0069E1D2 /* system_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D421B3DE22178BE700D35C20 /* system_utilities.c */; };
+               D459F0D4222862BA0056AC5B /* HelperFunctionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */; };
+               D461F94A2203A6B400A88910 /* xpc_services.h in Headers */ = {isa = PBXBuildFile; fileRef = D461F9482203A6B400A88910 /* xpc_services.h */; };
+               D461F94B2203A6B400A88910 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F9492203A6B400A88910 /* xpc_services.c */; };
+               D461F94C2203A6B400A88910 /* xpc_services.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F9492203A6B400A88910 /* xpc_services.c */; };
+               D461F94F2203A8AA00A88910 /* xpc_service_dns_proxy.h in Headers */ = {isa = PBXBuildFile; fileRef = D461F94D2203A8AA00A88910 /* xpc_service_dns_proxy.h */; };
+               D461F9502203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */; };
+               D461F9512203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */ = {isa = PBXBuildFile; fileRef = D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */; };
+               D470807322123E44006BAB32 /* libarchive.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D470807222123E44006BAB32 /* libarchive.tbd */; };
+               D4A1591622E27D43002F6278 /* DNSMessage.c in Sources */ = {isa = PBXBuildFile; fileRef = BD97754D221D64BF00F68FFC /* DNSMessage.c */; };
+               D4A1591822E27F61002F6278 /* DNSMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = BD97754E221D64BF00F68FFC /* DNSMessage.h */; };
+               D4A9F60521FA797F0079D0C6 /* dns_sd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = BDA9A7871B3A923600523835 /* dns_sd_private.h */; };
+               D4BFF8DB22B1C52100A0BA86 /* posix_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */; };
+               D4BFF8DC22B1C52100A0BA86 /* posix_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = D4BFF8DA22B1C52100A0BA86 /* posix_utilities.h */; };
+               D4C2AED62203E4F900B35685 /* xpc_service_log_utility.c in Sources */ = {isa = PBXBuildFile; fileRef = D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */; };
+               D4C2AED72203E4F900B35685 /* xpc_service_log_utility.c in Sources */ = {isa = PBXBuildFile; fileRef = D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */; };
+               D4C2AED922050E8800B35685 /* xpc_client_dns_proxy.h in Headers */ = {isa = PBXBuildFile; fileRef = D4C2AED822050E8800B35685 /* xpc_client_dns_proxy.h */; };
+               D4C2AEDB22050F4E00B35685 /* xpc_client_log_utility.h in Headers */ = {isa = PBXBuildFile; fileRef = D4C2AEDA22050F4E00B35685 /* xpc_client_log_utility.h */; };
+               D4C2AEDD22052A3400B35685 /* xpc_clients.h in Headers */ = {isa = PBXBuildFile; fileRef = 848DA5D516547F7200D2E8B4 /* xpc_clients.h */; };
+               D4CFA7D121E7BA0E00F5AD0E /* liblog_mdnsresponder.m in Sources */ = {isa = PBXBuildFile; fileRef = D4CFA7D021E7BA0E00F5AD0E /* liblog_mdnsresponder.m */; };
+               D4CFA7D421E7BA9700F5AD0E /* mDNSFeatures.h in Headers */ = {isa = PBXBuildFile; fileRef = D4CFA7D221E7BA8F00F5AD0E /* mDNSFeatures.h */; };
+               D4E219202268E09F00F06AA5 /* bats_test_state_dump.sh in Resources */ = {isa = PBXBuildFile; fileRef = D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */; };
+               D4F2BB2822CD21CB00234A38 /* posix_utilities.c in Sources */ = {isa = PBXBuildFile; fileRef = D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */; };
                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 */; };
                        isa = PBXBuildRule;
                        compilerSpec = com.apple.compilers.proxy.script;
                        fileType = sourcecode.yacc;
+                       inputFiles = (
+                       );
                        isEditable = 1;
                        outputFiles = (
-                               "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).h",
                                "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
                        );
-                       script = "echo NOOP yacc ${INPUT_FILE_PATH}";
+                       script = "/usr/bin/bison -o \"${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c\" \"${INPUT_FILE_PATH}\"\n";
                };
                D284BFB80ADD8E510027CCDF /* PBXBuildRule */ = {
                        isa = PBXBuildRule;
                        compilerSpec = com.apple.compilers.proxy.script;
                        fileType = sourcecode.lex;
+                       inputFiles = (
+                       );
                        isEditable = 1;
                        outputFiles = (
                                "$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).c",
                        );
-                       script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}";
+                       script = "/usr/bin/flex -i -o${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.c ${INPUT_FILE_PATH}\n";
                };
 /* End PBXBuildRule section */
 
                        remoteGlobalIDString = D284BE500ADD80740027CCDF;
                        remoteInfo = mDNSResponder;
                };
-               03067D6B0C83A3920022BE1F /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = D284BEA50ADD80920027CCDF;
-                       remoteInfo = "dns-sd tool";
-               };
                03067D6D0C83A39C0022BE1F /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        remoteGlobalIDString = 2E0405EF0C31955500F13B59;
                        remoteInfo = mDNSResponderHelper;
                };
-               03067D850C849CC30022BE1F /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 03067D640C83A3700022BE1F;
-                       remoteInfo = "Build Some";
-               };
-               0C1596C61D7751AD00E09998 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 0C1596AB1D773FE300E09998;
-                       remoteInfo = mDNSNetMonitor;
-               };
-               0C2AAB311B6929F300113637 /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 84C5B3341665529800C324A8;
-                       remoteInfo = dns_services;
-               };
-               0C4F36B31E206711005A536B /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 37DDE92C1BA383610092AC61;
-                       remoteInfo = unittests;
-               };
-               0C52E92E1E96AD74006EFE7B /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 0C635A751E9418A60026C796;
-                       remoteInfo = BonjourTop;
-               };
                2130257012400E9300AC839F /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        remoteGlobalIDString = 2141DD29123FFD2C0086D23E;
                        remoteInfo = libdns_sd_profile_static;
                };
-               217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */ = {
+               4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 213FB21712028A7A002B3A08;
-                       remoteInfo = BonjourEvents;
+                       remoteGlobalIDString = 4AE471670EAFF81900A6C5AD;
+                       remoteInfo = dns_sd.jar;
                };
-               4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */ = {
+               B70F38A7217AA6CE00612D3A /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 4AE471670EAFF81900A6C5AD;
-                       remoteInfo = dns_sd.jar;
+                       remoteGlobalIDString = B74F16EA2114E49C00BEBE84;
+                       remoteInfo = Tests;
+               };
+               B70F38A9217AA6CE00612D3A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = BD9BA7481EAF90E400658CCF;
+                       remoteInfo = dnssdutil;
+               };
+               B70F38AF217AA6CE00612D3A /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D284BEA50ADD80920027CCDF;
+                       remoteInfo = "dns-sd tool";
                };
-               84C5B3401665544B00C324A8 /* PBXContainerItemProxy */ = {
+               B718416F21F8D0A600CA42AD /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
                        remoteGlobalIDString = 84C5B3341665529800C324A8;
                        remoteInfo = dns_services;
                };
-               B76783B81E82D83800DA271E /* PBXContainerItemProxy */ = {
+               B7237FD92194D0EF00B113B1 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = B76783AB1E82D65900DA271E;
-                       remoteInfo = ddnsWriteTool;
+                       remoteGlobalIDString = 0C1596AB1D773FE300E09998;
+                       remoteInfo = mDNSNetMonitor;
                };
-               B7C4B72B1E71BD6000136C7A /* PBXContainerItemProxy */ = {
+               B7237FDB2194D16900B113B1 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = B74EC1151D47FC7700A1D155;
-                       remoteInfo = BonjourSettings;
+                       remoteGlobalIDString = B70F38A5217AA6CE00612D3A;
+                       remoteInfo = "Build Extras";
+               };
+               B7237FDD2194D16E00B113B1 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = B70F38A5217AA6CE00612D3A;
+                       remoteInfo = "Build Extras";
+               };
+               B7237FE52194D99200B113B1 /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = 213FB21712028A7A002B3A08;
+                       remoteInfo = BonjourEvents;
+               };
+               B7473E8F1EC395C300D31B9D /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = B7473E791EC395C300D31B9D;
+                       remoteInfo = "Bonjour Extension";
                };
-               B7C4B72D1E71BE3500136C7A /* PBXContainerItemProxy */ = {
+               B76783B81E82D83800DA271E /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 03067D640C83A3700022BE1F;
-                       remoteInfo = "Build Some";
+                       remoteGlobalIDString = B76783AB1E82D65900DA271E;
+                       remoteInfo = ddnsWriteTool;
                };
                B7D566C71E81D9E700E43008 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        remoteGlobalIDString = B7D566B91E81D8FD00E43008;
                        remoteInfo = RemoteViewService;
                };
-               BD7833EF1ABA5E3500EC51ED /* PBXContainerItemProxy */ = {
+               B7DB5899215EB4F70054CD46 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = 72FB545E166D5FB00090B2D9;
-                       remoteInfo = dnsctl;
+                       remoteGlobalIDString = B74EC1151D47FC7700A1D155;
+                       remoteInfo = BonjourSettings;
                };
-               BD9BA7711EAFA3D500658CCF /* PBXContainerItemProxy */ = {
+               B7DB58A1215EB61C0054CD46 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = BD9BA7481EAF90E400658CCF;
-                       remoteInfo = dnssdutil;
+                       remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
+                       remoteInfo = PreferencePane;
                };
-               D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */ = {
+               B7DB58A5215ED26D0054CD46 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = D284BEBF0ADD80A20027CCDF;
-                       remoteInfo = dnsextd;
+                       remoteGlobalIDString = B7473E601EC3954400D31B9D;
+                       remoteInfo = "Bonjour Safari Menu";
                };
-               D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */ = {
+               B7DB58C1215F04490054CD46 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
                        proxyType = 1;
-                       remoteGlobalIDString = D284BEEA0ADD80B00027CCDF;
-                       remoteInfo = PreferencePane;
+                       remoteGlobalIDString = 0C635A751E9418A60026C796;
+                       remoteInfo = BonjourTop;
+               };
+               D4528FFD21F91263004D61BF /* PBXContainerItemProxy */ = {
+                       isa = PBXContainerItemProxy;
+                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+                       proxyType = 1;
+                       remoteGlobalIDString = D4CFA7CB21E7B95E00F5AD0E;
+                       remoteInfo = liblog_mdnsresponder;
                };
                FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */ = {
                        isa = PBXContainerItemProxy;
                        remoteGlobalIDString = FFA5723C0AF18F450055A0F1;
                        remoteInfo = "libdns_sd profile";
                };
-               FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */ = {
-                       isa = PBXContainerItemProxy;
-                       containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
-                       proxyType = 1;
-                       remoteGlobalIDString = 00AD62BB032D7A0C0CCA2C71;
-                       remoteInfo = "Build Main";
-               };
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXCopyFilesBuildPhase section */
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 8;
-                       dstPath = /usr/local/OpenSourceVersions;
-                       dstSubfolderSpec = 0;
-                       files = (
-                               4A7B9E8014FDA25000B84CC1 /* mDNSResponder.plist in CopyFiles */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
-               4A7B9E8114FDA25500B84CC1 /* CopyFiles */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 8;
-                       dstPath = /usr/local/OpenSourceLicenses;
-                       dstSubfolderSpec = 0;
-                       files = (
-                               4A7B9E8214FDA26C00B84CC1 /* mDNSResponder.txt in CopyFiles */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 1;
-               };
                4AAE0C5A0C68E6EC003882A5 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               72FB545D166D5FB00090B2D9 /* CopyFiles */ = {
-                       isa = PBXCopyFilesBuildPhase;
-                       buildActionMask = 12;
-                       dstPath = /usr/share/man/man1/;
-                       dstSubfolderSpec = 0;
-                       files = (
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                8418673D15AB8BFF00BB7F70 /* Copy Base Logging Profile */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        name = "Copy Base Logging Profile";
                        runOnlyForDeploymentPostprocessing = 1;
                };
+               B7473E951EC395C300D31B9D /* Embed App Extensions */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 2147483647;
+                       dstPath = "";
+                       dstSubfolderSpec = 13;
+                       files = (
+                               B7473E911EC395C300D31B9D /* Bonjour Safari Extension.appex in Embed App Extensions */,
+                       );
+                       name = "Embed App Extensions";
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                B7D566C61E81D9B600E43008 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 2147483647;
                        name = "Copy AppleInternal Logging Profile";
                        runOnlyForDeploymentPostprocessing = 1;
                };
-               BDF8BB8A2208E09D00419B62 /* Copy BATS test plist */ = {
+               BD98A797213A41240002EC47 /* Copy BATS test plist */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                        dstPath = /AppleInternal/CoreOS/BATS/unit_tests;
                        dstSubfolderSpec = 0;
                        files = (
-                               BDF8BB902208E2A800419B62 /* mDNSResponder.plist in Copy BATS test plist */,
+                               BD98A798213A417C0002EC47 /* mDNSResponder.plist in Copy BATS test plist */,
                        );
                        name = "Copy BATS test plist";
                        runOnlyForDeploymentPostprocessing = 1;
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                };
+               D448F7A5222DA8E20069E1D2 /* Copy script-based unit tests */ = {
+                       isa = PBXCopyFilesBuildPhase;
+                       buildActionMask = 8;
+                       dstPath = /AppleInternal/Tests/mDNSResponder;
+                       dstSubfolderSpec = 0;
+                       files = (
+                               D448F7A8222DAB8E0069E1D2 /* bats_test_state_dump.sh in Copy script-based unit tests */,
+                               D448F7A8222DAB8E0069E1D3 /* bats_test_proxy.sh in Copy script-based unit tests */,
+                       );
+                       name = "Copy script-based unit tests";
+                       runOnlyForDeploymentPostprocessing = 1;
+               };
                FFFF8F770C32F0FD00722979 /* CopyFiles */ = {
                        isa = PBXCopyFilesBuildPhase;
                        buildActionMask = 8;
                000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mDNSMacOSX.h; sourceTree = "<group>"; };
                00CA213D02786FC30CCA2C71 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
                09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
-               0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = LocalOnlyTimeoutTests.c; path = ../unittests/LocalOnlyTimeoutTests.c; sourceTree = "<group>"; };
-               0C10EC271DDB956000D7A0E3 /* LocalOnlyTimeoutTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LocalOnlyTimeoutTests.h; path = ../unittests/LocalOnlyTimeoutTests.h; sourceTree = "<group>"; };
                0C1596AC1D773FE300E09998 /* mDNSNetMonitor */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSNetMonitor; sourceTree = BUILT_PRODUCTS_DIR; };
                0C1596B31D7740B500E09998 /* mDNSPosix.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSPosix.c; path = ../../mDNSPosix/mDNSPosix.c; sourceTree = "<group>"; };
                0C1596B41D7740B500E09998 /* NetMonitor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = NetMonitor.c; path = ../../mDNSPosix/NetMonitor.c; sourceTree = "<group>"; };
                0C1596B71D7740C100E09998 /* mDNSUNP.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSUNP.c; path = ../../mDNSPosix/mDNSUNP.c; sourceTree = "<group>"; };
-               0C5674B11DA2BF6300AF3367 /* mDNSCoreReceiveTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSCoreReceiveTest.h; path = ../unittests/mDNSCoreReceiveTest.h; sourceTree = "<group>"; };
-               0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mDNSCoreReceiveTest.c; path = ../unittests/mDNSCoreReceiveTest.c; sourceTree = "<group>"; };
                0C635A761E9418A60026C796 /* bonjourtop */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = bonjourtop; sourceTree = BUILT_PRODUCTS_DIR; };
                0C635A7D1E9418D90026C796 /* bjIPAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjIPAddr.cpp; path = source/bjIPAddr.cpp; sourceTree = "<group>"; };
                0C635A7E1E9418D90026C796 /* bjMACAddr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = bjMACAddr.cpp; path = source/bjMACAddr.cpp; sourceTree = "<group>"; };
                0C6FB90E1D775FE900DF6F51 /* mDNSNetMonitor.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = mDNSNetMonitor.8; sourceTree = "<group>"; };
                0C7C00491DD553490078BA89 /* unittest_common.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unittest_common.c; path = ../unittests/unittest_common.c; sourceTree = "<group>"; };
                0C7C004A1DD553490078BA89 /* unittest_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest_common.h; path = ../unittests/unittest_common.h; sourceTree = "<group>"; };
-               0C7C004B1DD553490078BA89 /* mdns_macosx_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mdns_macosx_ut.c; path = ../unittests/mdns_macosx_ut.c; sourceTree = "<group>"; };
-               0C7C004C1DD553490078BA89 /* mdns_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = mdns_ut.c; path = ../unittests/mdns_ut.c; sourceTree = "<group>"; };
-               0C7C004D1DD553490078BA89 /* uds_daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon_ut.c; path = ../unittests/uds_daemon_ut.c; sourceTree = "<group>"; };
-               0C7C004E1DD553490078BA89 /* CNameRecordTests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CNameRecordTests.h; path = ../unittests/CNameRecordTests.h; sourceTree = "<group>"; };
-               0C7C004F1DD553490078BA89 /* CNameRecordTests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = CNameRecordTests.c; path = ../unittests/CNameRecordTests.c; sourceTree = "<group>"; };
-               0C84A2911E786AFF00E8B4C7 /* daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = daemon_ut.c; path = ../unittests/daemon_ut.c; sourceTree = "<group>"; };
                21070E5D16486B9000A69507 /* DNSSECSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSSECSupport.c; sourceTree = "<group>"; };
                21070E5E16486B9000A69507 /* DNSSECSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSSECSupport.h; sourceTree = "<group>"; };
                2124FA2B1471E98C0021D7BB /* nsec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nsec.h; path = ../mDNSCore/nsec.h; sourceTree = "<group>"; };
                21A57F4B145B2AE100939099 /* CryptoAlg.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CryptoAlg.h; path = ../mDNSCore/CryptoAlg.h; sourceTree = "<group>"; };
                21A57F51145B2B1400939099 /* CryptoSupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CryptoSupport.c; sourceTree = "<group>"; };
                21A57F52145B2B1400939099 /* CryptoSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoSupport.h; sourceTree = "<group>"; };
-               21DD8FBD161E9A250033C8F8 /* anonymous.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = anonymous.c; path = ../mDNSCore/anonymous.c; sourceTree = "<group>"; };
-               21DD8FBE161E9A250033C8F8 /* anonymous.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = anonymous.h; path = ../mDNSCore/anonymous.h; sourceTree = "<group>"; };
                21DED43415702C0F0060B6B9 /* DNSProxySupport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSProxySupport.c; sourceTree = "<group>"; };
-               21F432971134AA6800581B69 /* WebFilterDNS.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebFilterDNS.framework; path = /System/Library/PrivateFrameworks/WebFilterDNS.framework; sourceTree = "<absolute>"; };
                21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.dnsextd.plist; sourceTree = "<group>"; };
                21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponderHelper.plist; sourceTree = "<group>"; };
                21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; 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>"; };
-               371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = InterfaceTest.c; path = ../unittests/InterfaceTest.c; sourceTree = "<group>"; };
-               371D0FBB1BF545FA00E5DB26 /* InterfaceTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = InterfaceTest.h; path = ../unittests/InterfaceTest.h; sourceTree = "<group>"; };
-               371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ResourceRecordTest.c; path = ../unittests/ResourceRecordTest.c; sourceTree = "<group>"; };
-               371D0FBE1BF666EB00E5DB26 /* ResourceRecordTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResourceRecordTest.h; path = ../unittests/ResourceRecordTest.h; sourceTree = "<group>"; };
-               3732020F1BAB4349007DE806 /* DNSMessageTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DNSMessageTest.c; path = ../unittests/DNSMessageTest.c; sourceTree = "<group>"; };
-               373202111BAB63E8007DE806 /* DNSMessageTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSMessageTest.h; path = ../unittests/DNSMessageTest.h; sourceTree = "<group>"; };
                37538E131D7A43B600226BE4 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
-               37AF802A1BF699AF00D657F6 /* DomainNameTest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = DomainNameTest.c; path = ../unittests/DomainNameTest.c; sourceTree = "<group>"; };
-               37AF802B1BF699AF00D657F6 /* DomainNameTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DomainNameTest.h; path = ../unittests/DomainNameTest.h; sourceTree = "<group>"; };
-               37DDE9271BA3825C0092AC61 /* unittest.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = unittest.c; path = ../unittests/unittest.c; sourceTree = "<group>"; };
-               37DDE9281BA382670092AC61 /* unittest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest.h; path = ../unittests/unittest.h; sourceTree = "<group>"; };
-               37DDE92D1BA383610092AC61 /* unittests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = unittests; sourceTree = BUILT_PRODUCTS_DIR; };
-               37DDE9351BA386E70092AC61 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = main.c; path = ../unittests/main.c; sourceTree = "<group>"; };
                4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uds_daemon.h; path = ../mDNSShared/uds_daemon.h; sourceTree = SOURCE_ROOT; };
                4A3600DF0F34F8CD00453EFB /* DeviceToDeviceManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceToDeviceManager.framework; path = /System/Library/PrivateFrameworks/DeviceToDeviceManager.framework; sourceTree = "<absolute>"; };
-               4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = mDNSResponder.txt; sourceTree = "<group>"; };
-               4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; 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; };
                4ADB5F230F6AB9F400B95BF3 /* helper-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "helper-entitlements.plist"; sourceTree = "<group>"; };
                4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = P2PPacketFilter.c; sourceTree = "<group>"; };
                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 = 0; };
                6575FBEB022EAF7200000109 /* mDNSMacOSX.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = mDNSMacOSX.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
                6575FBEC022EAF7200000109 /* daemon.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = daemon.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 0; };
-               72FB545A166D5F960090B2D9 /* dnsctl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dnsctl.c; path = ../Clients/dnsctl.c; sourceTree = "<group>"; };
-               72FB545F166D5FB00090B2D9 /* dnsctl */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnsctl; sourceTree = BUILT_PRODUCTS_DIR; };
                789036911F7AC1F90077A962 /* libnetwork.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libnetwork.tbd; path = usr/lib/libnetwork.tbd; sourceTree = SDKROOT; };
                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; };
                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; };
                8415A6561897109000BDBA26 /* libdns_services.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libdns_services.dylib; path = /usr/lib/libdns_services.dylib; sourceTree = "<absolute>"; };
-               8417375A1B967CBE000CD5C2 /* dnsctl_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsctl_server.c; path = Private/dnsctl_server.c; sourceTree = "<group>"; };
-               848DA5C6165477E000D2E8B4 /* xpc_services.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = xpc_services.c; path = Private/xpc_services.c; sourceTree = "<group>"; };
-               848DA5C9165477EB00D2E8B4 /* xpc_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = xpc_services.h; path = Private/xpc_services.h; sourceTree = "<group>"; };
-               848DA5D516547F7200D2E8B4 /* dns_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_xpc.h; path = Private/dns_xpc.h; sourceTree = "<group>"; };
+               848DA5D516547F7200D2E8B4 /* xpc_clients.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xpc_clients.h; sourceTree = "<group>"; };
                84C5B3351665529800C324A8 /* libdns_services.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdns_services.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
                84C5B339166553AF00C324A8 /* dns_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = dns_services.c; path = Private/dns_services.c; sourceTree = "<group>"; };
                84F4C08F188F04CF00D1E1DE /* dns_services.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_services.h; path = Private/dns_services.h; sourceTree = "<group>"; };
+               894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = bats_test_proxy.sh; sourceTree = "<group>"; };
+               897729AE2202A5370018FAEB /* dso.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dso.c; path = ../DSO/dso.c; sourceTree = "<group>"; };
+               897729AF2202A5370018FAEB /* dso-transport.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "dso-transport.c"; path = "../DSO/dso-transport.c"; sourceTree = "<group>"; };
+               897729B02202A5370018FAEB /* dso-transport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "dso-transport.h"; path = "../DSO/dso-transport.h"; sourceTree = "<group>"; };
+               897729B12202A5370018FAEB /* dso.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dso.h; path = ../DSO/dso.h; sourceTree = "<group>"; };
+               897729B62202A5480018FAEB /* dnssd_clientshim.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd_clientshim.c; path = ../mDNSShared/dnssd_clientshim.c; sourceTree = "<group>"; };
                B7016F4F1D5D0D1900107E7C /* DomainBrowser.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = DomainBrowser.strings; sourceTree = "<group>"; };
                B7016F511D5D0D2900107E7C /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = Localizable.strings; path = ../SettingsBundle/Localizable.strings; sourceTree = "<group>"; };
                B701E7031D9DD811008F3022 /* BonjourSCStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BonjourSCStore.m; path = ../SettingsBundle/BonjourSCStore.m; sourceTree = "<group>"; };
                B716801A1E8330B400459A35 /* entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = entitlements.plist; sourceTree = "<group>"; };
                B72C96091D6236A500AD682A /* BonjourSCStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = BonjourSCStore.h; path = ../SettingsBundle/BonjourSCStore.h; sourceTree = "<group>"; };
+               B72D38B31ECB96ED00B10E39 /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
                B7325FE61DA4737400663834 /* CNBrowseDomainsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CNBrowseDomainsController.h; path = ../SettingsBundle/CNBrowseDomainsController.h; sourceTree = "<group>"; };
                B7325FE71DA4737400663834 /* CNBrowseDomainsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CNBrowseDomainsController.m; path = ../SettingsBundle/CNBrowseDomainsController.m; sourceTree = "<group>"; };
                B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+               B735A2EE21B8293900025BB0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+               B7473E611EC3954400D31B9D /* Bonjour Safari Menu.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Bonjour Safari Menu.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+               B7473E641EC3954400D31B9D /* BonjourSafariMenu.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BonjourSafariMenu.entitlements; sourceTree = "<group>"; };
+               B7473E651EC3954400D31B9D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
+               B7473E661EC3954400D31B9D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
+               B7473E681EC3954400D31B9D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+               B7473E6A1EC3954400D31B9D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
+               B7473E6B1EC3954400D31B9D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
+               B7473E6D1EC3954400D31B9D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+               B7473E701EC3954400D31B9D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
+               B7473E721EC3954400D31B9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Bonjour Safari Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
+               B7473E801EC395C300D31B9D /* BonjourSafariExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BonjourSafariExtension.entitlements; sourceTree = "<group>"; };
+               B7473E811EC395C300D31B9D /* SafariExtensionHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SafariExtensionHandler.h; sourceTree = "<group>"; };
+               B7473E821EC395C300D31B9D /* SafariExtensionHandler.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SafariExtensionHandler.m; sourceTree = "<group>"; };
+               B7473E841EC395C300D31B9D /* SafariExtensionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SafariExtensionViewController.h; sourceTree = "<group>"; };
+               B7473E851EC395C300D31B9D /* SafariExtensionViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SafariExtensionViewController.m; sourceTree = "<group>"; };
+               B7473E881EC395C300D31B9D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SafariExtensionViewController.xib; sourceTree = "<group>"; };
+               B7473E8A1EC395C300D31B9D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               B7473E8B1EC395C300D31B9D /* script.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = script.js; sourceTree = "<group>"; };
                B74A96251DD4EDE60084A8C5 /* Preferences.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Preferences.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS10.0.Internal.sdk/System/Library/PrivateFrameworks/Preferences.framework; sourceTree = DEVELOPER_DIR; };
                B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BonjourSettings.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
                B74EC11B1D47FC7800A1D155 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = ../SettingsBundle/Info.plist; sourceTree = "<group>"; };
                B74EC1281D494C5800A1D155 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                B74EC1291D494C6700A1D155 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                B74EC12B1D494C7200A1D155 /* DomainBrowser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DomainBrowser.h; sourceTree = "<group>"; };
+               B74F16EB2114E49C00BEBE84 /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+               B74F16EF2114E49D00BEBE84 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+               B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DNSMessageTest.m; sourceTree = "<group>"; };
                B75700231E8347A6005CD56C /* InfoPlist.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = InfoPlist.strings; sourceTree = "<group>"; };
+               B76373741ECA25DE00B9404A /* CNServiceBrowserView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNServiceBrowserView.h; sourceTree = "<group>"; };
+               B76373751ECA25DE00B9404A /* CNServiceBrowserView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNServiceBrowserView.m; sourceTree = "<group>"; };
                B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */ = {isa = PBXFileReference; explicitFileType = "wrapper.xpc-service"; includeInIndex = 0; path = com.apple.preference.bonjour.tool.xpc; sourceTree = BUILT_PRODUCTS_DIR; };
                B76783BB1E82D8F500DA271E /* BonjourPrefTool-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourPrefTool-Info.plist"; sourceTree = "<group>"; };
                B76783BC1E82D8F500DA271E /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
                B778EE4B1D51113800C814A2 /* HostnameController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HostnameController.m; path = ../SettingsBundle/HostnameController.m; sourceTree = "<group>"; };
                B778EE4E1D51287100C814A2 /* BonjourSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BonjourSettingsController.h; path = ../SettingsBundle/BonjourSettingsController.h; sourceTree = "<group>"; };
                B778EE4F1D51287100C814A2 /* BonjourSettingsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BonjourSettingsController.m; path = ../SettingsBundle/BonjourSettingsController.m; sourceTree = "<group>"; };
+               B78A9C2F223941A900BFB0C6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/DNSServiceDiscoveryPref.xib; sourceTree = "<group>"; };
+               B78A9C322239485E00BFB0C6 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
                B799209D1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserPathUtils.h; sourceTree = "<group>"; };
                B799209E1DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserPathUtils.m; sourceTree = "<group>"; };
                B79920A31DA6C49700C6E02B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ../SettingsBundle/Assets.xcassets; sourceTree = "<group>"; };
+               B79FA153211CF0AF00B7861E /* dnsproxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dnsproxy.h; sourceTree = "<group>"; };
+               B79FA154211CF0AF00B7861E /* uDNS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = uDNS.h; sourceTree = "<group>"; };
+               B79FA155211CF0AF00B7861E /* nsec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nsec.h; sourceTree = "<group>"; };
+               B79FA156211CF0AF00B7861E /* DNSCommon.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = DNSCommon.c; sourceTree = "<group>"; };
+               B79FA157211CF0AF00B7861E /* mDNSDebug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mDNSDebug.h; sourceTree = "<group>"; };
+               B79FA158211CF0AF00B7861E /* dnssec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dnssec.c; sourceTree = "<group>"; };
+               B79FA159211CF0AF00B7861E /* CryptoAlg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CryptoAlg.h; sourceTree = "<group>"; };
+               B79FA15A211CF0AF00B7861E /* nsec3.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nsec3.h; sourceTree = "<group>"; };
+               B79FA15B211CF0AF00B7861E /* Implementer Notes.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Implementer Notes.txt"; sourceTree = "<group>"; };
+               B79FA15C211CF0AF00B7861E /* nsec.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nsec.c; sourceTree = "<group>"; };
+               B79FA15D211CF0AF00B7861E /* uDNS.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = uDNS.c; sourceTree = "<group>"; };
+               B79FA15E211CF0AF00B7861E /* dnsproxy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = dnsproxy.c; sourceTree = "<group>"; };
+               B79FA15F211CF0AF00B7861E /* dnssec.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = dnssec.h; sourceTree = "<group>"; };
+               B79FA160211CF0AF00B7861E /* mDNS.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mDNS.c; sourceTree = "<group>"; };
+               B79FA162211CF0AF00B7861E /* DNSCommon.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DNSCommon.h; sourceTree = "<group>"; };
+               B79FA163211CF0AF00B7861E /* CryptoAlg.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = CryptoAlg.c; sourceTree = "<group>"; };
+               B79FA164211CF0AF00B7861E /* mDNSEmbeddedAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mDNSEmbeddedAPI.h; sourceTree = "<group>"; };
+               B79FA165211CF0AF00B7861E /* nsec3.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = nsec3.c; sourceTree = "<group>"; };
+               B79FA166211CF0AF00B7861E /* DNSDigest.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = DNSDigest.c; sourceTree = "<group>"; };
                B7A214081D1B29D6005F7DD9 /* CNDomainBrowserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserViewController.h; sourceTree = "<group>"; };
                B7A214091D1B29D6005F7DD9 /* CNDomainBrowserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserViewController.m; sourceTree = "<group>"; };
+               B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ResourceRecordTest.m; sourceTree = "<group>"; };
+               B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = mDNSCoreReceiveTest.m; sourceTree = "<group>"; };
+               B7A861962127845700E81CC3 /* CNameRecordTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CNameRecordTest.m; sourceTree = "<group>"; };
+               B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LocalOnlyTimeoutTest.m; sourceTree = "<group>"; };
+               B7A8619A212B34CF00E81CC3 /* unittest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unittest.h; path = ../unittests/unittest.h; sourceTree = "<group>"; };
+               B7A8619E212B368700E81CC3 /* daemon_ut.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = daemon_ut.c; path = ../unittests/daemon_ut.c; sourceTree = "<group>"; };
+               B7A8619F212B36EC00E81CC3 /* mdns_macosx_ut.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mdns_macosx_ut.c; path = ../unittests/mdns_macosx_ut.c; sourceTree = "<group>"; };
+               B7A861A0212B370700E81CC3 /* mdns_ut.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = mdns_ut.c; path = ../unittests/mdns_ut.c; sourceTree = "<group>"; };
+               B7A861A4212B40BC00E81CC3 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = usr/lib/libxml2.tbd; sourceTree = SDKROOT; };
+               B7A861A5212B40BC00E81CC3 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };
+               B7A861A6212B40BC00E81CC3 /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = usr/lib/libicucore.tbd; sourceTree = SDKROOT; };
+               B7CEF6121F635404008B08D3 /* ToolbarItemIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = ToolbarItemIcon.png; sourceTree = "<group>"; };
                B7D566A51E81D6A900E43008 /* BonjourPrefRemoteViewService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "BonjourPrefRemoteViewService-Info.plist"; sourceTree = "<group>"; };
                B7D566A71E81D6A900E43008 /* BonjourPrefRemoteViewService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BonjourPrefRemoteViewService.h; sourceTree = "<group>"; };
                B7D566A81E81D6A900E43008 /* BonjourPrefRemoteViewService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BonjourPrefRemoteViewService.m; sourceTree = "<group>"; };
                B7D6CA681D1076C6005E24CF /* CNDomainBrowserView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CNDomainBrowserView.h; sourceTree = "<group>"; };
                B7D6CA691D1076C6005E24CF /* CNDomainBrowserView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CNDomainBrowserView.m; sourceTree = "<group>"; };
                B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; };
-               B7E5920F1DB687A700A38085 /* Base */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = Base; path = Base.lproj/DNSServiceDiscoveryPref.nib; sourceTree = "<group>"; };
                BD03E88C1AD31278005E8A81 /* SymptomReporter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SymptomReporter.c; sourceTree = "<group>"; };
+               BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_xpc.h; sourceTree = "<group>"; };
+               BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssd_xpc.c; sourceTree = "<group>"; };
+               BD11266F21DB1AFE006115E6 /* dnssd_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssd_server.c; sourceTree = "<group>"; };
+               BD11267021DB1AFE006115E6 /* dnssd_server.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_server.h; sourceTree = "<group>"; };
+               BD11267521DB2A9A006115E6 /* dnssd_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_private.h; sourceTree = "<group>"; };
+               BD11267621DB2A9A006115E6 /* dnssd_object.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = dnssd_object.m; sourceTree = "<group>"; };
+               BD11267721DB2A9A006115E6 /* dnssd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssd.c; sourceTree = "<group>"; };
+               BD11267B21DB2C7C006115E6 /* dnssd_object.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dnssd_object.h; sourceTree = "<group>"; };
+               BD1628CD2168B02600020528 /* ClientRequests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ClientRequests.h; path = ../mDNSShared/ClientRequests.h; sourceTree = "<group>"; };
+               BD1628CE2168B02700020528 /* ClientRequests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ClientRequests.c; path = ../mDNSShared/ClientRequests.c; sourceTree = "<group>"; };
                BD28AE8E207B88F600F0B257 /* bonjour-mcast-diagnose */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "bonjour-mcast-diagnose"; sourceTree = "<group>"; };
+               BD2A15B5225ED2E500BEA50A /* mdns_object.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = mdns_object.m; sourceTree = "<group>"; };
+               BD2A15B6225ED2E500BEA50A /* mdns_object.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mdns_object.h; sourceTree = "<group>"; };
+               BD2A15B7225ED2E500BEA50A /* mdns.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mdns.c; sourceTree = "<group>"; };
+               BD2A15B8225ED2E500BEA50A /* mdns_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mdns_private.h; sourceTree = "<group>"; };
                BD41F9C3209B60AC0077F8B6 /* libpcap.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpcap.tbd; path = usr/lib/libpcap.tbd; sourceTree = SDKROOT; };
+               BD42EE1F21DB41970053A651 /* libobjc.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libobjc.tbd; path = usr/lib/libobjc.tbd; sourceTree = SDKROOT; };
                BD691B281ED2F43200E6F317 /* DNS64.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNS64.c; sourceTree = "<group>"; };
                BD691B291ED2F43200E6F317 /* DNS64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS64.h; sourceTree = "<group>"; };
                BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
                BD893CE6206C0EAF0055F9E7 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+               BD97754B221D643500F68FFC /* dnssdutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = dnssdutil.c; sourceTree = "<group>"; };
+               BD97754D221D64BF00F68FFC /* DNSMessage.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = DNSMessage.c; sourceTree = "<group>"; usesTabs = 1; };
+               BD97754E221D64BF00F68FFC /* DNSMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNSMessage.h; sourceTree = "<group>"; };
+               BD98A796213A3EAE0002EC47 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
                BD9BA7531EAF90E400658CCF /* dnssdutil */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dnssdutil; sourceTree = BUILT_PRODUCTS_DIR; };
-               BD9BA7541EAF91E700658CCF /* dnssdutil.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssdutil.c; path = ../Clients/dnssdutil.c; sourceTree = "<group>"; };
                BD9BA7571EAF929C00658CCF /* CoreUtils.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreUtils.framework; path = System/Library/PrivateFrameworks/CoreUtils.framework; sourceTree = SDKROOT; };
                BDA3F0871C48DB6D0054FB4B /* Metrics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Metrics.h; sourceTree = "<group>"; };
                BDA3F0881C48DB6D0054FB4B /* Metrics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Metrics.m; sourceTree = "<group>"; };
                BDA3F0891C48DB910054FB4B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
+               BDA82B8922BF8A7000A31CBE /* libdns_services.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libdns_services.tbd; path = usr/lib/libdns_services.tbd; sourceTree = SDKROOT; };
                BDA9A7871B3A923600523835 /* dns_sd_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = dns_sd_private.h; path = ../mDNSShared/dns_sd_private.h; sourceTree = "<group>"; };
                BDAF4BBF20B52D3D0062219E /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
                BDB61843206ADB7700AFF600 /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = "<group>"; };
                BDB61846206ADDDF00AFF600 /* com.apple.mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = com.apple.mDNSResponder.plist; sourceTree = "<group>"; };
                BDBF9B931ED74B8C001498A8 /* DNS64State.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DNS64State.h; sourceTree = "<group>"; };
                BDE238C11DF69D8300B9F696 /* dns_sd_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dns_sd_internal.h; path = ../mDNSShared/dns_sd_internal.h; sourceTree = "<group>"; };
-               BDE5BCC9226D7181009C723C /* DNSCommon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DNSCommon.h; path = ../mDNSCore/DNSCommon.h; sourceTree = "<group>"; };
-               BDE5BCCB226D7197009C723C /* uDNS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uDNS.h; path = ../mDNSCore/uDNS.h; sourceTree = "<group>"; };
-               BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = mDNSResponder.plist; sourceTree = "<group>"; };
+               BDF2D02B2169B77B00D0DBF5 /* SymptomReporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymptomReporter.h; sourceTree = "<group>"; };
+               BDF2D02D216A25E800D0DBF5 /* ApplePlatformFeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplePlatformFeatures.h; sourceTree = "<group>"; };
                D284BE730ADD80740027CCDF /* mDNSResponder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = mDNSResponder; 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; };
                D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Bonjour.prefPane; sourceTree = BUILT_PRODUCTS_DIR; };
+               D408BAAF221243DA00139EDA /* libarchive.2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.2.tbd; path = usr/lib/libarchive.2.tbd; sourceTree = SDKROOT; };
+               D421B3DD22178BE700D35C20 /* system_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = system_utilities.h; sourceTree = "<group>"; };
+               D421B3DE22178BE700D35C20 /* system_utilities.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = system_utilities.c; sourceTree = "<group>"; };
+               D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = bats_test_state_dump.sh; sourceTree = "<group>"; };
+               D448F7AB222DCB5B0069E1D2 /* libarchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/usr/lib/libarchive.tbd; sourceTree = DEVELOPER_DIR; };
+               D448F7AD222DCC0A0069E1D2 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS13.0.Internal.sdk/System/Library/Frameworks/CoreFoundation.framework; sourceTree = DEVELOPER_DIR; };
+               D448F7B0222E035A0069E1D2 /* uds_daemon_ut.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = uds_daemon_ut.c; path = ../unittests/uds_daemon_ut.c; sourceTree = "<group>"; };
+               D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HelperFunctionTest.m; sourceTree = "<group>"; };
+               D461F9482203A6B400A88910 /* xpc_services.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_services.h; sourceTree = "<group>"; };
+               D461F9492203A6B400A88910 /* xpc_services.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xpc_services.c; sourceTree = "<group>"; };
+               D461F94D2203A8AA00A88910 /* xpc_service_dns_proxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_service_dns_proxy.h; sourceTree = "<group>"; };
+               D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xpc_service_dns_proxy.c; sourceTree = "<group>"; };
+               D470807222123E44006BAB32 /* libarchive.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libarchive.tbd; path = usr/lib/libarchive.tbd; sourceTree = SDKROOT; };
+               D49ECA17220BBAC400655887 /* dns-sd-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "dns-sd-entitlements.plist"; sourceTree = "<group>"; };
+               D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = posix_utilities.c; path = ../mDNSPosix/posix_utilities.c; sourceTree = "<group>"; };
+               D4BFF8DA22B1C52100A0BA86 /* posix_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = posix_utilities.h; path = ../mDNSPosix/posix_utilities.h; sourceTree = "<group>"; };
+               D4C2AED32203E4F900B35685 /* xpc_service_log_utility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_service_log_utility.h; sourceTree = "<group>"; };
+               D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = xpc_service_log_utility.c; sourceTree = "<group>"; };
+               D4C2AED822050E8800B35685 /* xpc_client_dns_proxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_client_dns_proxy.h; sourceTree = "<group>"; };
+               D4C2AEDA22050F4E00B35685 /* xpc_client_log_utility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = xpc_client_log_utility.h; sourceTree = "<group>"; };
+               D4CFA7CC21E7B95E00F5AD0E /* liblog_mdnsresponder.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = liblog_mdnsresponder.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+               D4CFA7D021E7BA0E00F5AD0E /* liblog_mdnsresponder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = liblog_mdnsresponder.m; sourceTree = "<group>"; };
+               D4CFA7D221E7BA8F00F5AD0E /* mDNSFeatures.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mDNSFeatures.h; path = ../mDNSShared/mDNSFeatures.h; 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; };
                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; };
-               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; };
                FF485D5105632E0000130380 /* mDNSResponder.8 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = mDNSResponder.8; path = ../mDNSShared/mDNSResponder.8; sourceTree = SOURCE_ROOT; };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               37DDE92A1BA383610092AC61 /* Frameworks */ = {
+               84C5B3321665529800C324A8 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               37538E1B1D7A442300226BE4 /* Foundation.framework in Frameworks */,
-                               21B830A31D8A63AE00AE2001 /* SystemConfiguration.framework in Frameworks */,
-                               21B830A61D8A63E400AE2001 /* CoreFoundation.framework in Frameworks */,
-                               21B830A21D8A63A300AE2001 /* libxml2.dylib in Frameworks */,
-                               37538E141D7A43B600226BE4 /* libicucore.dylib in Frameworks */,
-                               789036931F7AC2050077A962 /* libnetwork.tbd in Frameworks */,
-                               21B830A41D8A63BB00AE2001 /* Security.framework in Frameworks */,
-                               21B830A51D8A63CB00AE2001 /* IOKit.framework in Frameworks */,
+                               BD42EE2021DB41970053A651 /* libobjc.tbd in Frameworks */,
+                               BD93516E21E369B90078582E /* Foundation.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               72FB545C166D5FB00090B2D9 /* Frameworks */ = {
+               B7325FEA1DA47EBA00663834 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               8415A6571897109000BDBA26 /* libdns_services.dylib in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               84C5B3321665529800C324A8 /* Frameworks */ = {
+               B7473E5E1EC3954400D31B9D /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               B7325FEA1DA47EBA00663834 /* Frameworks */ = {
+               B7473E771EC395C300D31B9D /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               B7A861A1212B3FF400E81CC3 /* Cocoa.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               B74F16E82114E49C00BEBE84 /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D448F7AC222DCB5C0069E1D2 /* libarchive.tbd in Frameworks */,
+                               B7A861A3212B409200E81CC3 /* IOKit.framework in Frameworks */,
+                               B7A861A8212B411200E81CC3 /* libicucore.tbd in Frameworks */,
+                               B7A861A7212B410D00E81CC3 /* libxml2.tbd in Frameworks */,
+                               B7A861A2212B408D00E81CC3 /* Security.framework in Frameworks */,
+                               B7EEF7C4212603B20093828F /* SystemConfiguration.framework in Frameworks */,
+                               B7A861A9212B411600E81CC3 /* Network.framework in Frameworks */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                B76783A91E82D65900DA271E /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               BDA82B8A22BF8A7000A31CBE /* libdns_services.tbd in Frameworks */,
                                BD41F9C4209B60AC0077F8B6 /* libpcap.tbd in Frameworks */,
                                BDAF4BC020B52D3D0062219E /* CFNetwork.framework in Frameworks */,
                                BD893CE7206C0EAF0055F9E7 /* CoreFoundation.framework in Frameworks */,
                                BD9BA7581EAF929C00658CCF /* CoreUtils.framework in Frameworks */,
+                               BD2A15BC225ED38600BEA50A /* Network.framework in Frameworks */,
                                BD893CE5206C0D980055F9E7 /* SystemConfiguration.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D470807322123E44006BAB32 /* libarchive.tbd in Frameworks */,
                                D284BE650ADD80740027CCDF /* CoreFoundation.framework in Frameworks */,
                                BDA3F08A1C48DB920054FB4B /* Foundation.framework in Frameworks */,
                                D284BE670ADD80740027CCDF /* IOKit.framework in Frameworks */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               D4CFA7CA21E7B95E00F5AD0E /* Frameworks */ = {
+                       isa = PBXFrameworksBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                FFA572360AF18F1C0055A0F1 /* Frameworks */ = {
                        isa = PBXFrameworksBuildPhase;
                        buildActionMask = 2147483647;
                08FB7794FE84155DC02AAC07 /* mDNSResponder */ = {
                        isa = PBXGroup;
                        children = (
+                               B79FA152211CF0AF00B7861E /* mDNSCore */,
+                               BD11266C21DB1AB3006115E6 /* mDNSMacOSX */,
+                               D4BFF8D822B1C29E00A0BA86 /* mDNSPosix */,
                                08FB7795FE84155DC02AAC07 /* mDNS Server Sources */,
                                6575FC1F022EB78C00000109 /* Command-Line Clients */,
                                213FB20912028902002B3A08 /* Bonjour Events Plugin */,
                                B7D6CA511D107573005E24CF /* DomainBrowser */,
                                B74EC11A1D47FC7800A1D155 /* SettingsBundle */,
                                FFFB0DA407B43BED00B88D48 /* PreferencePane */,
+                               B7473E621EC3954400D31B9D /* Bonjour Safari Menu */,
+                               B7473E7E1EC395C300D31B9D /* Bonjour Safari Extension */,
                                08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
                                0C1596AD1D773FE300E09998 /* mDNSNetMonitor */,
                                0C635A771E9418A60026C796 /* BonjourTop */,
+                               B74F16EC2114E49D00BEBE84 /* Tests */,
                                19C28FBDFE9D53C911CA2CBB /* Products */,
-                               37DDE9241BA382280092AC61 /* Unit Tests */,
                                BD9BA7561EAF929C00658CCF /* Frameworks */,
                                BDB61842206ADB7700AFF600 /* LoggingProfiles */,
                                BD28AE8D207B88F600F0B257 /* Scripts */,
-                               BDF8BB8E2208E26E00419B62 /* BATS */,
                        );
                        name = mDNSResponder;
                        sourceTree = "<group>";
                08FB7795FE84155DC02AAC07 /* mDNS Server Sources */ = {
                        isa = PBXGroup;
                        children = (
+                               897729B62202A5480018FAEB /* dnssd_clientshim.c */,
+                               897729AF2202A5370018FAEB /* dso-transport.c */,
+                               897729B02202A5370018FAEB /* dso-transport.h */,
+                               897729AE2202A5370018FAEB /* dso.c */,
+                               897729B12202A5370018FAEB /* dso.h */,
+                               D461F9472203A59200A88910 /* xpc_services */,
+                               D4CFA7D221E7BA8F00F5AD0E /* mDNSFeatures.h */,
+                               BD1628CE2168B02700020528 /* ClientRequests.c */,
+                               BD1628CD2168B02600020528 /* ClientRequests.h */,
                                220ABBF11D78F102008423A7 /* D2D.h */,
                                22C7633D1D777B8C0077AFCA /* D2D.c */,
                                22448EA51C90A82D004F25CC /* coreBLE.h */,
                                222A3C571C1B743B003A6FFD /* DNSServiceDiscovery.h */,
                                222A3C581C1B743B003A6FFD /* DNSServiceDiscoveryDefines.h */,
                                222A3C561C1B7415003A6FFD /* DNSServiceDiscovery.c */,
-                               21DD8FBD161E9A250033C8F8 /* anonymous.c */,
-                               21DD8FBE161E9A250033C8F8 /* anonymous.h */,
                                21F51DBD1B3540DB0070B05C /* com.apple.dnsextd.plist */,
                                21F51DBF1B35412D0070B05C /* com.apple.mDNSResponder.plist */,
                                21F51DBE1B3541030070B05C /* com.apple.mDNSResponderHelper.plist */,
                                BDA9A7871B3A923600523835 /* dns_sd_private.h */,
                                84C5B339166553AF00C324A8 /* dns_services.c */,
                                84F4C08F188F04CF00D1E1DE /* dns_services.h */,
-                               848DA5D516547F7200D2E8B4 /* dns_xpc.h */,
                                7F18A9F60587CEF6001880B3 /* DNSCommon.c */,
-                               BDE5BCC9226D7181009C723C /* DNSCommon.h */,
                                7F461DB5062DBF2900672BF3 /* DNSDigest.c */,
                                FF13FFEA0A5DA44A00897C81 /* dnsextd_lexer.l */,
                                FF13FFEC0A5DA45500897C81 /* dnsextd_parser.y */,
                                2E0405F40C3195F700F13B59 /* helper.c */,
                                2E96A5250C39BE480087C4D2 /* helper.h */,
                                2ECC11A50C4FEC3800CB1885 /* helpermsg-types.h */,
-                               4A8202510C56C36500DDFD48 /* ipsec_strerror.h */,
                                7FC8F9D406D14E66007E879D /* LegacyNATTraversal.c */,
-                               4A8202520C56C36500DDFD48 /* libpfkey.h */,
                                6575FBE9022EAF5A00000109 /* mDNS.c */,
                                DBAAFE29057E8F4D0085CAD0 /* mDNSDebug.c */,
                                654BE65002B63B93000001D1 /* mDNSDebug.h */,
                                6575FBEB022EAF7200000109 /* mDNSMacOSX.c */,
                                000753D303367C1C0CCA2C71 /* mDNSMacOSX.h */,
                                FF485D5105632E0000130380 /* mDNSResponder.8 */,
-                               4A7B9E7E14FDA1BB00B84CC1 /* mDNSResponder.plist */,
                                FF85880B0BD599F40080D89F /* mDNSResponder.sb */,
-                               4A7B9E7C14FDA19F00B84CC1 /* mDNSResponder.txt */,
                                4AAE0C7A0C68E97F003882A5 /* mDNSResponderHelper.8 */,
                                BDA3F0871C48DB6D0054FB4B /* Metrics.h */,
                                BDA3F0881C48DB6D0054FB4B /* Metrics.m */,
                                2127A47615C3C7B900A857FC /* nsec3.h */,
                                4BD2B638134FE09F002B96D5 /* P2PPacketFilter.c */,
                                4BD2B639134FE09F002B96D5 /* P2PPacketFilter.h */,
-                               4A8202530C56C36600DDFD48 /* pfkey.c */,
                                FFCB6D73075D539900B8AF62 /* PlatformCommon.c */,
                                BD03E88C1AD31278005E8A81 /* SymptomReporter.c */,
+                               BDF2D02B2169B77B00D0DBF5 /* SymptomReporter.h */,
                                7F18A9F70587CEF6001880B3 /* uDNS.c */,
-                               BDE5BCCB226D7197009C723C /* uDNS.h */,
                                216D9ACD1720C9F5008066E1 /* uDNSPathEvalulation.c */,
                                F525E72804AA167501F1CF4D /* uds_daemon.c */,
                                4A2E69DD0F5475A3004A87B0 /* uds_daemon.h */,
-                               8417375A1B967CBE000CD5C2 /* dnsctl_server.c */,
-                               848DA5C6165477E000D2E8B4 /* xpc_services.c */,
-                               848DA5C9165477EB00D2E8B4 /* xpc_services.h */,
                        );
                        name = "mDNS Server Sources";
                        sourceTree = "<group>";
                                8415A6561897109000BDBA26 /* libdns_services.dylib */,
                                37538E131D7A43B600226BE4 /* libicucore.dylib */,
                                2E8165F60C59835F00485EB2 /* libipsec.dylib */,
+                               B7A861A6212B40BC00E81CC3 /* libicucore.tbd */,
+                               B7A861A4212B40BC00E81CC3 /* libxml2.tbd */,
                                219D5541149ED645004464AE /* libxml2.dylib */,
+                               B7A861A5212B40BC00E81CC3 /* Network.framework */,
                                B74A96251DD4EDE60084A8C5 /* Preferences.framework */,
                                FF260A1F07B4436900CE10E5 /* PreferencePanes.framework */,
                                B7D566D41E81E14E00E43008 /* ViewBridge.framework */,
                                7F869685066EE02400D2A2DC /* Security.framework */,
                                65713D46025A293200000109 /* SystemConfiguration.framework */,
-                               21F432971134AA6800581B69 /* WebFilterDNS.framework */,
                        );
                        name = "External Frameworks and Libraries";
                        sourceTree = "<group>";
                                D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */,
                                213FB21812028A7A002B3A08 /* BonjourEvents.plugin */,
                                D284BEB00ADD80920027CCDF /* dns-sd */,
-                               72FB545F166D5FB00090B2D9 /* dnsctl */,
                                D284BED90ADD80A20027CCDF /* dnsextd */,
                                2141DD1D123FFCDB0086D23E /* libdns_sd.a */,
                                2141DD24123FFD0F0086D23E /* libdns_sd_debug.a */,
                                FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */,
                                D284BE730ADD80740027CCDF /* mDNSResponder */,
                                2E0405F00C31955500F13B59 /* mDNSResponderHelper */,
-                               37DDE92D1BA383610092AC61 /* unittests */,
                                0C1596AC1D773FE300E09998 /* mDNSNetMonitor */,
                                B7D6CA701D1076F3005E24CF /* DomainBrowser.framework */,
                                B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */,
                                B76783AC1E82D65900DA271E /* com.apple.preference.bonjour.tool.xpc */,
                                0C635A761E9418A60026C796 /* bonjourtop */,
                                BD9BA7531EAF90E400658CCF /* dnssdutil */,
+                               B7473E611EC3954400D31B9D /* Bonjour Safari Menu.app */,
+                               B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */,
+                               B74F16EB2114E49C00BEBE84 /* Tests.xctest */,
+                               D4CFA7CC21E7B95E00F5AD0E /* liblog_mdnsresponder.dylib */,
                        );
                        name = Products;
                        sourceTree = "<group>";
                        name = "Bonjour Events Plugin";
                        sourceTree = "<group>";
                };
-               37DDE9241BA382280092AC61 /* Unit Tests */ = {
+               37DDE9241BA382280092AC61 /* Unit Test Utilities */ = {
                        isa = PBXGroup;
                        children = (
-                               0C84A2911E786AFF00E8B4C7 /* daemon_ut.c */,
-                               0C10EC261DDB956000D7A0E3 /* LocalOnlyTimeoutTests.c */,
-                               0C10EC271DDB956000D7A0E3 /* LocalOnlyTimeoutTests.h */,
-                               0C7C00491DD553490078BA89 /* unittest_common.c */,
+                               B7A8619A212B34CF00E81CC3 /* unittest.h */,
+                               D448F7B0222E035A0069E1D2 /* uds_daemon_ut.c */,
+                               B7A8619E212B368700E81CC3 /* daemon_ut.c */,
+                               B7A8619F212B36EC00E81CC3 /* mdns_macosx_ut.c */,
+                               B7A861A0212B370700E81CC3 /* mdns_ut.c */,
                                0C7C004A1DD553490078BA89 /* unittest_common.h */,
-                               0C7C004B1DD553490078BA89 /* mdns_macosx_ut.c */,
-                               0C7C004C1DD553490078BA89 /* mdns_ut.c */,
-                               0C7C004D1DD553490078BA89 /* uds_daemon_ut.c */,
-                               0C7C004E1DD553490078BA89 /* CNameRecordTests.h */,
-                               0C7C004F1DD553490078BA89 /* CNameRecordTests.c */,
-                               0C5674B11DA2BF6300AF3367 /* mDNSCoreReceiveTest.h */,
-                               0C5674B21DA2BF6300AF3367 /* mDNSCoreReceiveTest.c */,
-                               37AF802A1BF699AF00D657F6 /* DomainNameTest.c */,
-                               37AF802B1BF699AF00D657F6 /* DomainNameTest.h */,
-                               371D0FBD1BF666EB00E5DB26 /* ResourceRecordTest.c */,
-                               371D0FBE1BF666EB00E5DB26 /* ResourceRecordTest.h */,
-                               373202111BAB63E8007DE806 /* DNSMessageTest.h */,
-                               3732020F1BAB4349007DE806 /* DNSMessageTest.c */,
-                               37DDE9351BA386E70092AC61 /* main.c */,
-                               37DDE9271BA3825C0092AC61 /* unittest.c */,
-                               37DDE9281BA382670092AC61 /* unittest.h */,
-                               371D0FBA1BF545FA00E5DB26 /* InterfaceTest.c */,
-                               371D0FBB1BF545FA00E5DB26 /* InterfaceTest.h */,
-                       );
-                       name = "Unit Tests";
+                               0C7C00491DD553490078BA89 /* unittest_common.c */,
+                       );
+                       name = "Unit Test Utilities";
+                       path = ..;
                        sourceTree = "<group>";
                };
                6575FC1F022EB78C00000109 /* Command-Line Clients */ = {
                        isa = PBXGroup;
                        children = (
+                               BD97754A221D643500F68FFC /* dnssdutil */,
+                               D49ECA15220BBA2D00655887 /* command_line_client_entitlements */,
                                FF1C919D07021D77001048AB /* dns-sd.1 */,
                                FF1C919F07021E3F001048AB /* dns-sd.c */,
-                               72FB545A166D5F960090B2D9 /* dnsctl.c */,
                                FF5852100DD27BD300862BDF /* ClientCommon.c */,
-                               BD9BA7541EAF91E700658CCF /* dnssdutil.c */,
                        );
                        name = "Command-Line Clients";
                        sourceTree = "<group>";
                };
+               B7473E621EC3954400D31B9D /* Bonjour Safari Menu */ = {
+                       isa = PBXGroup;
+                       children = (
+                               B7473E651EC3954400D31B9D /* AppDelegate.h */,
+                               B7473E661EC3954400D31B9D /* AppDelegate.m */,
+                               B7473E6A1EC3954400D31B9D /* ViewController.h */,
+                               B7473E6B1EC3954400D31B9D /* ViewController.m */,
+                               B7473E6D1EC3954400D31B9D /* Assets.xcassets */,
+                               B7473E6F1EC3954400D31B9D /* Main.storyboard */,
+                               B7473E721EC3954400D31B9D /* Info.plist */,
+                               B7473E631EC3954400D31B9D /* Supporting Files */,
+                       );
+                       path = "Bonjour Safari Menu";
+                       sourceTree = "<group>";
+               };
+               B7473E631EC3954400D31B9D /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               B7473E641EC3954400D31B9D /* BonjourSafariMenu.entitlements */,
+                               B7473E681EC3954400D31B9D /* main.m */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
+               B7473E7E1EC395C300D31B9D /* Bonjour Safari Extension */ = {
+                       isa = PBXGroup;
+                       children = (
+                               B76373741ECA25DE00B9404A /* CNServiceBrowserView.h */,
+                               B76373751ECA25DE00B9404A /* CNServiceBrowserView.m */,
+                               B7473E811EC395C300D31B9D /* SafariExtensionHandler.h */,
+                               B7473E821EC395C300D31B9D /* SafariExtensionHandler.m */,
+                               B7473E841EC395C300D31B9D /* SafariExtensionViewController.h */,
+                               B7473E851EC395C300D31B9D /* SafariExtensionViewController.m */,
+                               B7473E871EC395C300D31B9D /* SafariExtensionViewController.xib */,
+                               B7473E8A1EC395C300D31B9D /* Info.plist */,
+                               B7473E7F1EC395C300D31B9D /* Supporting Files */,
+                       );
+                       path = "Bonjour Safari Extension";
+                       sourceTree = "<group>";
+               };
+               B7473E7F1EC395C300D31B9D /* Supporting Files */ = {
+                       isa = PBXGroup;
+                       children = (
+                               B7473E8B1EC395C300D31B9D /* script.js */,
+                               B7CEF6121F635404008B08D3 /* ToolbarItemIcon.png */,
+                               B72D38B31ECB96ED00B10E39 /* Localizable.strings */,
+                               B7473E801EC395C300D31B9D /* BonjourSafariExtension.entitlements */,
+                       );
+                       name = "Supporting Files";
+                       sourceTree = "<group>";
+               };
                B74EC11A1D47FC7800A1D155 /* SettingsBundle */ = {
                        isa = PBXGroup;
                        children = (
                        path = SettingsBundle;
                        sourceTree = "<group>";
                };
+               B74F16EC2114E49D00BEBE84 /* Tests */ = {
+                       isa = PBXGroup;
+                       children = (
+                               B74F16EF2114E49D00BEBE84 /* Info.plist */,
+                               BD98A796213A3EAE0002EC47 /* mDNSResponder.plist */,
+                               B7A86198212B074500E81CC3 /* LocalOnlyTimeoutTest.m */,
+                               B7A861962127845700E81CC3 /* CNameRecordTest.m */,
+                               B7A8618A21274FA200E81CC3 /* mDNSCoreReceiveTest.m */,
+                               B7A8618821274BFC00E81CC3 /* ResourceRecordTest.m */,
+                               B74F16F3211BA55400BEBE84 /* DNSMessageTest.m */,
+                               D459F0D3222862BA0056AC5B /* HelperFunctionTest.m */,
+                               D448F7A6222DA98E0069E1D2 /* BATS Scripts */,
+                               37DDE9241BA382280092AC61 /* Unit Test Utilities */,
+                       );
+                       path = Tests;
+                       sourceTree = "<group>";
+               };
                B76783BA1E82D8F500DA271E /* BonjourPrefTool */ = {
                        isa = PBXGroup;
                        children = (
                        path = BonjourPrefTool;
                        sourceTree = "<group>";
                };
+               B79FA152211CF0AF00B7861E /* mDNSCore */ = {
+                       isa = PBXGroup;
+                       children = (
+                               B79FA153211CF0AF00B7861E /* dnsproxy.h */,
+                               B79FA154211CF0AF00B7861E /* uDNS.h */,
+                               B79FA155211CF0AF00B7861E /* nsec.h */,
+                               B79FA156211CF0AF00B7861E /* DNSCommon.c */,
+                               B79FA157211CF0AF00B7861E /* mDNSDebug.h */,
+                               B79FA158211CF0AF00B7861E /* dnssec.c */,
+                               B79FA159211CF0AF00B7861E /* CryptoAlg.h */,
+                               B79FA15A211CF0AF00B7861E /* nsec3.h */,
+                               B79FA15B211CF0AF00B7861E /* Implementer Notes.txt */,
+                               B79FA15C211CF0AF00B7861E /* nsec.c */,
+                               B79FA15D211CF0AF00B7861E /* uDNS.c */,
+                               B79FA15E211CF0AF00B7861E /* dnsproxy.c */,
+                               B79FA15F211CF0AF00B7861E /* dnssec.h */,
+                               B79FA160211CF0AF00B7861E /* mDNS.c */,
+                               B79FA162211CF0AF00B7861E /* DNSCommon.h */,
+                               B79FA163211CF0AF00B7861E /* CryptoAlg.c */,
+                               B79FA164211CF0AF00B7861E /* mDNSEmbeddedAPI.h */,
+                               B79FA165211CF0AF00B7861E /* nsec3.c */,
+                               B79FA166211CF0AF00B7861E /* DNSDigest.c */,
+                       );
+                       name = mDNSCore;
+                       path = ../mDNSCore;
+                       sourceTree = "<group>";
+               };
                B7A214061D1B29D6005F7DD9 /* iOS */ = {
                        isa = PBXGroup;
                        children = (
                        path = macOS;
                        sourceTree = "<group>";
                };
+               BD11266C21DB1AB3006115E6 /* mDNSMacOSX */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D421B3DC22178B7800D35C20 /* utilities */,
+                               BDF2D02D216A25E800D0DBF5 /* ApplePlatformFeatures.h */,
+                               BD11267721DB2A9A006115E6 /* dnssd.c */,
+                               BD11267B21DB2C7C006115E6 /* dnssd_object.h */,
+                               BD11267621DB2A9A006115E6 /* dnssd_object.m */,
+                               BD11267521DB2A9A006115E6 /* dnssd_private.h */,
+                               BD11266F21DB1AFE006115E6 /* dnssd_server.c */,
+                               BD11267021DB1AFE006115E6 /* dnssd_server.h */,
+                               BD11266E21DB1AFE006115E6 /* dnssd_xpc.c */,
+                               BD11266D21DB1AFE006115E6 /* dnssd_xpc.h */,
+                               BD2A15B7225ED2E500BEA50A /* mdns.c */,
+                               BD2A15B6225ED2E500BEA50A /* mdns_object.h */,
+                               BD2A15B5225ED2E500BEA50A /* mdns_object.m */,
+                               BD2A15B8225ED2E500BEA50A /* mdns_private.h */,
+                       );
+                       name = mDNSMacOSX;
+                       sourceTree = "<group>";
+                       usesTabs = 1;
+               };
                BD28AE8D207B88F600F0B257 /* Scripts */ = {
                        isa = PBXGroup;
                        children = (
                        path = Scripts;
                        sourceTree = "<group>";
                };
+               BD97754A221D643500F68FFC /* dnssdutil */ = {
+                       isa = PBXGroup;
+                       children = (
+                               BD97754D221D64BF00F68FFC /* DNSMessage.c */,
+                               BD97754E221D64BF00F68FFC /* DNSMessage.h */,
+                               BD97754B221D643500F68FFC /* dnssdutil.c */,
+                       );
+                       name = dnssdutil;
+                       path = ../Clients/dnssdutil;
+                       sourceTree = "<group>";
+               };
                BD9BA7561EAF929C00658CCF /* Frameworks */ = {
                        isa = PBXGroup;
                        children = (
+                               BDA82B8922BF8A7000A31CBE /* libdns_services.tbd */,
+                               D448F7AD222DCC0A0069E1D2 /* CoreFoundation.framework */,
+                               D448F7AB222DCB5B0069E1D2 /* libarchive.tbd */,
+                               D408BAAF221243DA00139EDA /* libarchive.2.tbd */,
+                               D470807222123E44006BAB32 /* libarchive.tbd */,
+                               BD42EE1F21DB41970053A651 /* libobjc.tbd */,
                                BDAF4BBF20B52D3D0062219E /* CFNetwork.framework */,
                                BD41F9C3209B60AC0077F8B6 /* libpcap.tbd */,
                                BD893CE6206C0EAF0055F9E7 /* CoreFoundation.framework */,
                                BD893CE4206C0D980055F9E7 /* SystemConfiguration.framework */,
                                789036911F7AC1F90077A962 /* libnetwork.tbd */,
                                BD9BA7571EAF929C00658CCF /* CoreUtils.framework */,
+                               B735A2EE21B8293900025BB0 /* Foundation.framework */,
                        );
                        name = Frameworks;
                        sourceTree = "<group>";
                BDB61842206ADB7700AFF600 /* LoggingProfiles */ = {
                        isa = PBXGroup;
                        children = (
+                               D4CFA7D021E7BA0E00F5AD0E /* liblog_mdnsresponder.m */,
                                BDB61843206ADB7700AFF600 /* com.apple.mDNSResponder.plist */,
                                BDB61844206ADB7700AFF600 /* AppleInternal */,
                        );
                        path = AppleInternal;
                        sourceTree = "<group>";
                };
-               BDF8BB8E2208E26E00419B62 /* BATS */ = {
+               D421B3DC22178B7800D35C20 /* utilities */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D421B3DD22178BE700D35C20 /* system_utilities.h */,
+                               D421B3DE22178BE700D35C20 /* system_utilities.c */,
+                       );
+                       path = utilities;
+                       sourceTree = "<group>";
+               };
+               D448F7A6222DA98E0069E1D2 /* BATS Scripts */ = {
+                       isa = PBXGroup;
+                       children = (
+                               894A55D622C438AF008CDEA1 /* bats_test_proxy.sh */,
+                               D448F7A7222DAA1F0069E1D2 /* bats_test_state_dump.sh */,
+                       );
+                       path = "BATS Scripts";
+                       sourceTree = "<group>";
+               };
+               D461F9472203A59200A88910 /* xpc_services */ = {
+                       isa = PBXGroup;
+                       children = (
+                               848DA5D516547F7200D2E8B4 /* xpc_clients.h */,
+                               D461F9482203A6B400A88910 /* xpc_services.h */,
+                               D461F9492203A6B400A88910 /* xpc_services.c */,
+                               D461F94D2203A8AA00A88910 /* xpc_service_dns_proxy.h */,
+                               D461F94E2203A8AA00A88910 /* xpc_service_dns_proxy.c */,
+                               D4C2AED822050E8800B35685 /* xpc_client_dns_proxy.h */,
+                               D4C2AED32203E4F900B35685 /* xpc_service_log_utility.h */,
+                               D4C2AED42203E4F900B35685 /* xpc_service_log_utility.c */,
+                               D4C2AEDA22050F4E00B35685 /* xpc_client_log_utility.h */,
+                       );
+                       path = xpc_services;
+                       sourceTree = "<group>";
+               };
+               D49ECA15220BBA2D00655887 /* command_line_client_entitlements */ = {
+                       isa = PBXGroup;
+                       children = (
+                               D49ECA17220BBAC400655887 /* dns-sd-entitlements.plist */,
+                       );
+                       path = command_line_client_entitlements;
+                       sourceTree = "<group>";
+               };
+               D4BFF8D822B1C29E00A0BA86 /* mDNSPosix */ = {
                        isa = PBXGroup;
                        children = (
-                               BDF8BB8F2208E26E00419B62 /* mDNSResponder.plist */,
+                               D4BFF8D922B1C52100A0BA86 /* posix_utilities.c */,
+                               D4BFF8DA22B1C52100A0BA86 /* posix_utilities.h */,
                        );
-                       path = BATS;
+                       name = mDNSPosix;
                        sourceTree = "<group>";
                };
                DB2CC4420662DCE500335AB3 /* Java Support */ = {
                                FF260A2A07B4464B00CE10E5 /* failure.tiff */,
                                FF260A3207B4466900CE10E5 /* BonjourPref.icns */,
                                FF260A3307B4466900CE10E5 /* BonjourPref.tiff */,
-                               FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */,
+                               B78A9C2E223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib */,
                                FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */,
                        );
                        name = Resources;
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               BDA9A7891B3A92A500523835 /* dns_sd_private.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                2EC8F8EC0C39CCAC003C9C48 /* helper.h in Headers */,
                                2EDC5E730C39EA640092701B /* helper-server.h in Headers */,
                                2ECC11A80C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
-                               2E8165E80C5980E300485EB2 /* libpfkey.h in Headers */,
-                               2E8165EA0C5980F700485EB2 /* ipsec_strerror.h in Headers */,
                                4BD2B63B134FE09F002B96D5 /* P2PPacketFilter.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               37538DFB1D7A421500226BE4 /* Headers */ = {
-                       isa = PBXHeadersBuildPhase;
-                       buildActionMask = 2147483647;
-                       files = (
-                               37538E0D1D7A437300226BE4 /* DNSSECSupport.h in Headers */,
-                               37538E0C1D7A435200226BE4 /* dnssec.h in Headers */,
-                               37538E0B1D7A432200226BE4 /* Metrics.h in Headers */,
-                               37538E0A1D7A430600226BE4 /* anonymous.h in Headers */,
-                               37538E091D7A42FC00226BE4 /* xpc_services.h in Headers */,
-                               37538E081D7A42F000226BE4 /* dns_xpc.h in Headers */,
-                               37538E071D7A42E200226BE4 /* coreBLE.h in Headers */,
-                               37538E061D7A42DA00226BE4 /* dnsproxy.h in Headers */,
-                               37538E051D7A42D000226BE4 /* DNSServiceDiscoveryDefines.h in Headers */,
-                               37538E041D7A42BE00226BE4 /* BLE.h in Headers */,
-                               37538E021D7A42B000226BE4 /* nsec.h in Headers */,
-                               37538E031D7A42B000226BE4 /* nsec3.h in Headers */,
-                               37538E001D7A429900226BE4 /* CryptoAlg.h in Headers */,
-                               37538E011D7A429900226BE4 /* CryptoSupport.h in Headers */,
-                               37538DFF1D7A428500226BE4 /* helpermsg-types.h in Headers */,
-                               37538DFE1D7A427B00226BE4 /* helper-server.h in Headers */,
-                               37538DFD1D7A425700226BE4 /* helper.h in Headers */,
-                               37538DFC1D7A424500226BE4 /* dnssd_ipc.h in Headers */,
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-               };
                84C5B3331665529800C324A8 /* Headers */ = {
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               D4C2AEDD22052A3400B35685 /* xpc_clients.h in Headers */,
                                84F4C090188F050200D1E1DE /* dns_services.h in Headers */,
+                               BD11267821DB2A9B006115E6 /* dnssd_private.h in Headers */,
+                               BD11267C21DB2C7C006115E6 /* dnssd_object.h in Headers */,
+                               BD11267E21DB3019006115E6 /* dnssd_xpc.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               BD977550221D64BF00F68FFC /* DNSMessage.h in Headers */,
+                               D4A9F60521FA797F0079D0C6 /* dns_sd_private.h in Headers */,
+                               BD2A15B9225ED30C00BEA50A /* mdns_private.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        files = (
                                D284BE540ADD80740027CCDF /* dnssd_ipc.h in Headers */,
                                BDBF9B941ED74B9C001498A8 /* DNS64State.h in Headers */,
+                               D4C2AED922050E8800B35685 /* xpc_client_dns_proxy.h in Headers */,
+                               D4C2AEDB22050F4E00B35685 /* xpc_client_log_utility.h in Headers */,
                                2E96A5260C39BE480087C4D2 /* helper.h in Headers */,
+                               BDF2D02E216A25E800D0DBF5 /* ApplePlatformFeatures.h in Headers */,
+                               BDF2D02C2169B77C00D0DBF5 /* SymptomReporter.h in Headers */,
+                               BD1628CF2168B02700020528 /* ClientRequests.h in Headers */,
+                               BD11267121DB1B25006115E6 /* dnssd_server.h in Headers */,
+                               D421B3DF22178BE700D35C20 /* system_utilities.h in Headers */,
                                2EDC5E750C39EA640092701B /* helper-server.h in Headers */,
                                2ECC11A60C4FEC3800CB1885 /* helpermsg-types.h in Headers */,
                                21A57F4E145B2AE100939099 /* CryptoAlg.h in Headers */,
                                21A57F55145B2B1400939099 /* CryptoSupport.h in Headers */,
-                               BDE5BCCA226D7181009C723C /* DNSCommon.h in Headers */,
                                2124FA2C1471E98C0021D7BB /* nsec.h in Headers */,
-                               BDE5BCCC226D7198009C723C /* uDNS.h in Headers */,
+                               D4CFA7D421E7BA9700F5AD0E /* mDNSFeatures.h in Headers */,
+                               D401238D22728506006C9BBE /* mdns_private.h in Headers */,
+                               D4BFF8DC22B1C52100A0BA86 /* posix_utilities.h in Headers */,
+                               897729B42202A5370018FAEB /* dso-transport.h in Headers */,
                                2124FA301471E9B50021D7BB /* dnssec.h in Headers */,
+                               D461F94F2203A8AA00A88910 /* xpc_service_dns_proxy.h in Headers */,
+                               B7A8619B212B34CF00E81CC3 /* unittest.h in Headers */,
                                BD691B2B1ED2F4AB00E6F317 /* DNS64.h in Headers */,
+                               BD11267221DB1B29006115E6 /* dnssd_xpc.h in Headers */,
                                218E8E53156D8C0300720DA0 /* dnsproxy.h in Headers */,
                                2127A47915C3C7B900A857FC /* nsec3.h in Headers */,
                                222A3C5B1C1B75F2003A6FFD /* DNSServiceDiscoveryDefines.h in Headers */,
-                               21DD8FC1161E9A250033C8F8 /* anonymous.h in Headers */,
+                               897729B52202A5370018FAEB /* dso.h in Headers */,
                                21070E6116486B9000A69507 /* DNSSECSupport.h in Headers */,
-                               848DA5CA165477EB00D2E8B4 /* xpc_services.h in Headers */,
                                BDA3F08E1C48DCA50054FB4B /* Metrics.h in Headers */,
                                22448EA71C90A837004F25CC /* coreBLE.h in Headers */,
                                220ABBF21D78F10F008423A7 /* D2D.h in Headers */,
                                22448EA41C90A7CB004F25CC /* BLE.h in Headers */,
-                               848DA5D616547F7200D2E8B4 /* dns_xpc.h in Headers */,
+                               D461F94A2203A6B400A88910 /* xpc_services.h in Headers */,
+                               848DA5D616547F7200D2E8B4 /* xpc_clients.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               D4CFA7C821E7B95E00F5AD0E /* Headers */ = {
+                       isa = PBXHeadersBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D4A1591822E27F61002F6278 /* DNSMessage.h in Headers */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                FFA572310AF18F1C0055A0F1 /* Headers */ = {
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               BDB04221203FEF4C00419961 /* dns_sd.h in Headers */,
-                               BDB04223203FF18000419961 /* dns_sd_private.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXHeadersBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               BDB04222203FEF4D00419961 /* dns_sd.h in Headers */,
-                               BDB04224203FF18000419961 /* dns_sd_private.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        productReference = 2E0405F00C31955500F13B59 /* mDNSResponderHelper */;
                        productType = "com.apple.product-type.tool";
                };
-               37DDE92C1BA383610092AC61 /* unittests */ = {
+               84C5B3341665529800C324A8 /* dns_services */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 37DDE9311BA383610092AC61 /* Build configuration list for PBXNativeTarget "unittests" */;
+                       buildConfigurationList = 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */;
                        buildPhases = (
-                               37DDE9291BA383610092AC61 /* Sources */,
-                               37DDE92A1BA383610092AC61 /* Frameworks */,
-                               37DDE9341BA384000092AC61 /* ShellScript */,
-                               37538DFB1D7A421500226BE4 /* Headers */,
+                               84C5B3311665529800C324A8 /* Sources */,
+                               84C5B3321665529800C324A8 /* Frameworks */,
+                               84C5B3331665529800C324A8 /* Headers */,
                        );
                        buildRules = (
                        );
                        dependencies = (
                        );
-                       name = unittests;
-                       productName = unittests;
-                       productReference = 37DDE92D1BA383610092AC61 /* unittests */;
-                       productType = "com.apple.product-type.tool";
+                       name = dns_services;
+                       productName = dns_services;
+                       productReference = 84C5B3351665529800C324A8 /* libdns_services.dylib */;
+                       productType = "com.apple.product-type.library.dynamic";
                };
-               72FB545E166D5FB00090B2D9 /* dnsctl */ = {
+               B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */;
+                       buildConfigurationList = B7325FF31DA47EBA00663834 /* Build configuration list for PBXNativeTarget "DomainBrowser-iOS" */;
                        buildPhases = (
-                               72FB545B166D5FB00090B2D9 /* Sources */,
-                               72FB545C166D5FB00090B2D9 /* Frameworks */,
-                               72FB545D166D5FB00090B2D9 /* CopyFiles */,
-                       );
+                               B7325FE91DA47EBA00663834 /* Sources */,
+                               B7325FEA1DA47EBA00663834 /* Frameworks */,
+                               B7325FEB1DA47EBA00663834 /* Headers */,
+                               B7325FEC1DA47EBA00663834 /* Resources */,
+                       );
                        buildRules = (
                        );
                        dependencies = (
-                               0C2AAB321B6929F300113637 /* PBXTargetDependency */,
                        );
-                       name = dnsctl;
-                       productName = dnsctl;
-                       productReference = 72FB545F166D5FB00090B2D9 /* dnsctl */;
-                       productType = "com.apple.product-type.tool";
+                       name = "DomainBrowser-iOS";
+                       productName = BonjourBrowser;
+                       productReference = B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */;
+                       productType = "com.apple.product-type.framework";
                };
-               84C5B3341665529800C324A8 /* dns_services */ = {
+               B7473E601EC3954400D31B9D /* Bonjour Safari Menu */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = 84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */;
+                       buildConfigurationList = B7473E751EC3954400D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Menu" */;
                        buildPhases = (
-                               84C5B3311665529800C324A8 /* Sources */,
-                               84C5B3321665529800C324A8 /* Frameworks */,
-                               84C5B3331665529800C324A8 /* Headers */,
+                               B7473E5D1EC3954400D31B9D /* Sources */,
+                               B7473E5E1EC3954400D31B9D /* Frameworks */,
+                               B7473E5F1EC3954400D31B9D /* Resources */,
+                               B7473E951EC395C300D31B9D /* Embed App Extensions */,
                        );
                        buildRules = (
                        );
                        dependencies = (
+                               B7473E901EC395C300D31B9D /* PBXTargetDependency */,
                        );
-                       name = dns_services;
-                       productName = dns_services;
-                       productReference = 84C5B3351665529800C324A8 /* libdns_services.dylib */;
-                       productType = "com.apple.product-type.library.dynamic";
+                       name = "Bonjour Safari Menu";
+                       productName = "Bonjour Browser";
+                       productReference = B7473E611EC3954400D31B9D /* Bonjour Safari Menu.app */;
+                       productType = "com.apple.product-type.application";
                };
-               B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */ = {
+               B7473E791EC395C300D31B9D /* Bonjour Safari Extension */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = B7325FF31DA47EBA00663834 /* Build configuration list for PBXNativeTarget "DomainBrowser-iOS" */;
+                       buildConfigurationList = B7473E921EC395C300D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Extension" */;
                        buildPhases = (
-                               B7325FE91DA47EBA00663834 /* Sources */,
-                               B7325FEA1DA47EBA00663834 /* Frameworks */,
-                               B7325FEB1DA47EBA00663834 /* Headers */,
-                               B7325FEC1DA47EBA00663834 /* Resources */,
+                               B7473E761EC395C300D31B9D /* Sources */,
+                               B7473E771EC395C300D31B9D /* Frameworks */,
+                               B7473E781EC395C300D31B9D /* Resources */,
                        );
                        buildRules = (
                        );
                        dependencies = (
                        );
-                       name = "DomainBrowser-iOS";
-                       productName = BonjourBrowser;
-                       productReference = B7325FEE1DA47EBA00663834 /* DomainBrowser.framework */;
-                       productType = "com.apple.product-type.framework";
+                       name = "Bonjour Safari Extension";
+                       productName = "Bonjour Extension";
+                       productReference = B7473E7A1EC395C300D31B9D /* Bonjour Safari Extension.appex */;
+                       productType = "com.apple.product-type.app-extension";
                };
                B74EC1151D47FC7700A1D155 /* BonjourSettings */ = {
                        isa = PBXNativeTarget;
                        productReference = B74EC1161D47FC7700A1D155 /* BonjourSettings.bundle */;
                        productType = "com.apple.product-type.bundle";
                };
+               B74F16EA2114E49C00BEBE84 /* Tests */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = B74F16F02114E49D00BEBE84 /* Build configuration list for PBXNativeTarget "Tests" */;
+                       buildPhases = (
+                               B74F16E72114E49C00BEBE84 /* Sources */,
+                               B74F16E82114E49C00BEBE84 /* Frameworks */,
+                               B74F16E92114E49C00BEBE84 /* Resources */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = Tests;
+                       productName = Tests;
+                       productReference = B74F16EB2114E49C00BEBE84 /* Tests.xctest */;
+                       productType = "com.apple.product-type.bundle.unit-test";
+               };
                B76783AB1E82D65900DA271E /* BonjourPrefsTool */ = {
                        isa = PBXNativeTarget;
                        buildConfigurationList = B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */;
                                D284BE550ADD80740027CCDF /* Sources */,
                                D284BE640ADD80740027CCDF /* Frameworks */,
                                D284BE6A0ADD80740027CCDF /* CopyFiles */,
-                               4A7B9E7F14FDA21B00B84CC1 /* CopyFiles */,
-                               4A7B9E8114FDA25500B84CC1 /* CopyFiles */,
                                D284BE6C0ADD80740027CCDF /* Run Script */,
                                21F51DC01B35418C0070B05C /* CopyFiles */,
                                8418673D15AB8BFF00BB7F70 /* Copy Base Logging Profile */,
                                BD75E93F206ADEAD00656ED3 /* Copy AppleInternal Logging Profile */,
                                BD28AE8C207B888E00F0B257 /* Copy diagnose scripts */,
-                               BDF8BB8A2208E09D00419B62 /* Copy BATS test plist */,
+                               D448F7A5222DA8E20069E1D2 /* Copy script-based unit tests */,
+                               BD98A797213A41240002EC47 /* Copy BATS test plist */,
+                               D4C07948220A180000E485FF /* Create Log Directory  for mDNSResponder */,
                        );
                        buildRules = (
                        );
                        buildConfigurationList = D284BED60ADD80A20027CCDF /* Build configuration list for PBXNativeTarget "dnsextd" */;
                        buildPhases = (
                                D284BEC20ADD80A20027CCDF /* Headers */,
-                               4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */,
+                               4A4EE3A413CB8E82005C624B /* Pre-generate dnsextd_parser.h file for dnsextd_lexer.c */,
                                D284BEC40ADD80A20027CCDF /* Sources */,
                                D284BECE0ADD80A20027CCDF /* Frameworks */,
                                D284BED40ADD80A20027CCDF /* CopyFiles */,
                        productReference = D284BF0C0ADD80B00027CCDF /* Bonjour.prefPane */;
                        productType = "com.apple.product-type.bundle";
                };
-               FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */ = {
+               D4CFA7CB21E7B95E00F5AD0E /* liblog_mdnsresponder */ = {
+                       isa = PBXNativeTarget;
+                       buildConfigurationList = D4CFA7CF21E7B95E00F5AD0E /* Build configuration list for PBXNativeTarget "liblog_mdnsresponder" */;
+                       buildPhases = (
+                               D4CFA7C821E7B95E00F5AD0E /* Headers */,
+                               D4CFA7C921E7B95E00F5AD0E /* Sources */,
+                               D4CFA7CA21E7B95E00F5AD0E /* Frameworks */,
+                       );
+                       buildRules = (
+                       );
+                       dependencies = (
+                       );
+                       name = liblog_mdnsresponder;
+                       productName = liblog_mdnsresponder;
+                       productReference = D4CFA7CC21E7B95E00F5AD0E /* liblog_mdnsresponder.dylib */;
+                       productType = "com.apple.product-type.library.dynamic";
+               };
+               FFA572300AF18F1C0055A0F1 /* libsystem_dnssd_debug */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */;
+                       buildConfigurationList = FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_debug" */;
                        buildPhases = (
                                FFA572310AF18F1C0055A0F1 /* Headers */,
                                FFA572320AF18F1C0055A0F1 /* Sources */,
                        );
                        dependencies = (
                        );
-                       name = libdns_sd_debug_dynamic;
+                       name = libsystem_dnssd_debug;
                        productName = libdns_sd.dylib;
                        productReference = FFA572390AF18F1C0055A0F1 /* libsystem_dnssd_debug.dylib */;
                        productType = "com.apple.product-type.library.dynamic";
                };
-               FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */ = {
+               FFA5723C0AF18F450055A0F1 /* libsystem_dnssd_profile */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */;
+                       buildConfigurationList = FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_profile" */;
                        buildPhases = (
                                FFA5723D0AF18F450055A0F1 /* Headers */,
                                FFA5723E0AF18F450055A0F1 /* Sources */,
                        );
                        dependencies = (
                        );
-                       name = libdns_sd_profile_dynamic;
+                       name = libsystem_dnssd_profile;
                        productName = libdns_sd.dylib;
                        productReference = FFA572450AF18F450055A0F1 /* libsystem_dnssd_profile.dylib */;
                        productType = "com.apple.product-type.library.dynamic";
                };
-               FFB765830AEED9C700583A2C /* libdns_sd_dynamic */ = {
+               FFB765830AEED9C700583A2C /* libsystem_dnssd */ = {
                        isa = PBXNativeTarget;
-                       buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */;
+                       buildConfigurationList = FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libsystem_dnssd" */;
                        buildPhases = (
                                FFB765800AEED9C700583A2C /* Headers */,
                                FFB765810AEED9C700583A2C /* Sources */,
                        );
                        dependencies = (
                        );
-                       name = libdns_sd_dynamic;
+                       name = libsystem_dnssd;
                        productName = libdns_sd.dylib;
                        productReference = FFB765840AEED9C700583A2C /* libsystem_dnssd.dylib */;
                        productType = "com.apple.product-type.library.dynamic";
                08FB7793FE84155DC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        attributes = {
+                               DefaultBuildSystemTypeForWorkspace = Latest;
                                LastUpgradeCheck = 0700;
                                TargetAttributes = {
                                        0C635A751E9418A60026C796 = {
                                                DevelopmentTeam = 63ZFQSB63Y;
                                                ProvisioningStyle = Automatic;
                                        };
-                                       37DDE92C1BA383610092AC61 = {
-                                               CreatedOnToolsVersion = 7.0;
+                                       B70F38A5217AA6CE00612D3A = {
+                                               ProvisioningStyle = Automatic;
                                        };
                                        B7325FED1DA47EBA00663834 = {
                                                CreatedOnToolsVersion = 8.0;
                                                ProvisioningStyle = Automatic;
                                        };
+                                       B7473E601EC3954400D31B9D = {
+                                               CreatedOnToolsVersion = 9.0;
+                                               ProvisioningStyle = Automatic;
+                                       };
+                                       B7473E791EC395C300D31B9D = {
+                                               CreatedOnToolsVersion = 9.0;
+                                               ProvisioningStyle = Automatic;
+                                       };
                                        B74EC1151D47FC7700A1D155 = {
                                                CreatedOnToolsVersion = 8.0;
                                                DevelopmentTeam = 6DMBYZ9NJ7;
                                                DevelopmentTeamName = "Apple Inc. - Embedded Platform";
                                                ProvisioningStyle = Automatic;
                                        };
+                                       B74F16EA2114E49C00BEBE84 = {
+                                               CreatedOnToolsVersion = 10.0;
+                                       };
                                        B76783AB1E82D65900DA271E = {
                                                CreatedOnToolsVersion = 8.3;
                                                ProvisioningStyle = Automatic;
                                        };
-                                       B7C4B7251E71BD5000136C7A = {
-                                               CreatedOnToolsVersion = 9.0;
-                                               ProvisioningStyle = Automatic;
-                                       };
                                        B7D566B91E81D8FD00E43008 = {
                                                CreatedOnToolsVersion = 8.3;
                                                ProvisioningStyle = Automatic;
                                                CreatedOnToolsVersion = 8.0;
                                                ProvisioningStyle = Automatic;
                                        };
+                                       B7DB5895215EB4DD0054CD46 = {
+                                               CreatedOnToolsVersion = 10.0;
+                                               ProvisioningStyle = Automatic;
+                                       };
+                                       B7DB589D215EB61C0054CD46 = {
+                                               ProvisioningStyle = Automatic;
+                                       };
+                                       D4CFA7CB21E7B95E00F5AD0E = {
+                                               CreatedOnToolsVersion = 11.0;
+                                               ProvisioningStyle = Automatic;
+                                       };
                                };
                        };
                        buildConfigurationList = D284BE2B0ADD78180027CCDF /* Build configuration list for PBXProject "mDNSResponder" */;
                        projectDirPath = "";
                        projectRoot = "";
                        targets = (
-                               00AD62BB032D7A0C0CCA2C71 /* Build More */,
-                               B7C4B7251E71BD5000136C7A /* Build Some iOS */,
-                               03067D640C83A3700022BE1F /* Build Some */,
+                               03067D640C83A3700022BE1F /* Build Core */,
+                               B718416921F8D0A600CA42AD /* Build Services */,
+                               B7DB589D215EB61C0054CD46 /* Build Extras-macOS */,
+                               B7DB5895215EB4DD0054CD46 /* Build Extras-iOS */,
+                               B70F38A5217AA6CE00612D3A /* Build Extras */,
                                FFB7657B0AEED96B00583A2C /* Build All */,
                                D284BE500ADD80740027CCDF /* mDNSResponder */,
                                2E0405EF0C31955500F13B59 /* mDNSResponderHelper */,
                                D284BEA50ADD80920027CCDF /* dns-sd tool */,
-                               72FB545E166D5FB00090B2D9 /* dnsctl */,
                                D284BEBF0ADD80A20027CCDF /* dnsextd */,
                                B7325FED1DA47EBA00663834 /* DomainBrowser-iOS */,
                                B7D6CA6F1D1076F3005E24CF /* DomainBrowser-macOS */,
                                D284BEEA0ADD80B00027CCDF /* PreferencePane */,
                                B76783AB1E82D65900DA271E /* BonjourPrefsTool */,
                                B7D566B91E81D8FD00E43008 /* RemoteViewService */,
+                               B7473E601EC3954400D31B9D /* Bonjour Safari Menu */,
+                               B7473E791EC395C300D31B9D /* Bonjour Safari Extension */,
                                213FB21712028A7A002B3A08 /* BonjourEvents */,
                                2141DCF8123FFB5D0086D23E /* SystemLibraries */,
                                2141DD0B123FFC7F0086D23E /* SystemLibrariesStatic */,
                                2141DD1C123FFCDB0086D23E /* libdns_sd_static */,
                                2141DD23123FFD0F0086D23E /* libdns_sd_debug_static */,
                                2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */,
-                               FFB765830AEED9C700583A2C /* libdns_sd_dynamic */,
-                               FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */,
-                               FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */,
+                               FFB765830AEED9C700583A2C /* libsystem_dnssd */,
+                               FFA572300AF18F1C0055A0F1 /* libsystem_dnssd_debug */,
+                               FFA5723C0AF18F450055A0F1 /* libsystem_dnssd_profile */,
                                84C5B3341665529800C324A8 /* dns_services */,
                                D284BEB20ADD809A0027CCDF /* libjdns_sd.jnilib */,
                                4AE471670EAFF81900A6C5AD /* dns_sd.jar */,
-                               37DDE92C1BA383610092AC61 /* unittests */,
+                               B74F16EA2114E49C00BEBE84 /* Tests */,
                                0C1596AB1D773FE300E09998 /* mDNSNetMonitor */,
                                0C635A751E9418A60026C796 /* BonjourTop */,
                                BD9BA7481EAF90E400658CCF /* dnssdutil */,
+                               D4CFA7CB21E7B95E00F5AD0E /* liblog_mdnsresponder */,
                        );
                };
 /* End PBXProject section */
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               B7473E5F1EC3954400D31B9D /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               B7473E6E1EC3954400D31B9D /* Assets.xcassets in Resources */,
+                               B7473E711EC3954400D31B9D /* Main.storyboard in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
+               B7473E781EC395C300D31B9D /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               B7CEF6131F6354AA008B08D3 /* ToolbarItemIcon.png in Resources */,
+                               B72D38B41ECB96ED00B10E39 /* Localizable.strings in Resources */,
+                               B7473E891EC395C300D31B9D /* SafariExtensionViewController.xib in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                B74EC1141D47FC7700A1D155 /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               B74F16E92114E49C00BEBE84 /* Resources */ = {
+                       isa = PBXResourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D4E219202268E09F00F06AA5 /* bats_test_state_dump.sh in Resources */,
+                               894A55D722C438AF008CDEA1 /* bats_test_proxy.sh in Resources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                B76783AA1E82D65900DA271E /* Resources */ = {
                        isa = PBXResourcesBuildPhase;
                        buildActionMask = 2147483647;
                                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 */,
+                               B78A9C30223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib in Resources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        shellPath = "/bin/bash -e -x";
                        shellScript = "DSTROOT=${DSTROOT}\n\nif [[ \"${ACTION}\" == \"installhdrs\" ]] || [[ \"${ACTION}\" == \"installapi\" ]]; then\n    exit 0\nfi\n\nif [[ \"${PLATFORM_NAME}\" =~ \"simulator\" ]]; then\n    ln -s libsystem_dnssd.dylib ${DSTROOT}${INSTALL_PATH}/libsystem_sim_dnssd.dylib\nfi\n";
                };
-               37DDE9341BA384000092AC61 /* ShellScript */ = {
-                       isa = PBXShellScriptBuildPhase;
-                       buildActionMask = 12;
-                       files = (
-                       );
-                       inputPaths = (
-                               "$(TARGET_BUILD_DIR)/$(TARGET_NAME)",
-                       );
-                       outputPaths = (
-                               "$(TARGET_BUILD_DIR)/unittest_success",
-                       );
-                       runOnlyForDeploymentPostprocessing = 0;
-                       shellPath = /bin/sh;
-                       shellScript = "cd \"$TARGET_BUILD_DIR\"\n./\"$TARGET_NAME\"\n# touch unittest_success\nif [ ! -f unittest_success ] ; then exit -1; fi";
-               };
-               4A4EE3A413CB8E82005C624B /* Build yacc file into derived source files */ = {
+               4A4EE3A413CB8E82005C624B /* Pre-generate dnsextd_parser.h file for dnsextd_lexer.c */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
                        inputPaths = (
                                "$(SRCROOT)/../mDNSShared/dnsextd_parser.y",
                        );
-                       name = "Build yacc file into derived source files";
+                       name = "Pre-generate dnsextd_parser.h file for dnsextd_lexer.c";
                        outputPaths = (
-                               "$(DERIVED_FILE_DIR)/dnsextd_parser.c",
                                "$(DERIVED_FILE_DIR)/dnsextd_parser.h",
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "/usr/bin/bison -o ${SCRIPT_OUTPUT_FILE_0} -d ${SCRIPT_INPUT_FILE_0}";
+                       shellScript = "/usr/bin/bison -o ${SCRIPT_OUTPUT_FILE_0} -d ${SCRIPT_INPUT_FILE_0}\n";
                };
-               B7E2951A1E259AA000C42F6D /* ShellScript */ = {
+               B7E2951A1E259AA000C42F6D /* Copy Sandbox Profile */ = {
                        isa = PBXShellScriptBuildPhase;
                        buildActionMask = 8;
                        files = (
                        );
                        inputPaths = (
+                               "$(SRCROOT)/mDNSResponder.sb",
                        );
+                       name = "Copy Sandbox Profile";
                        outputPaths = (
                        );
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/sh;
-                       shellScript = "# Copy Sandbox profile\nif [[ ! \"${PLATFORM_NAME}\" =~ \"simulator\" ]] ; then\n    if [ -z \"${IPHONEOS_DEPLOYMENT_TARGET}\" -a -z \"${TVOS_DEPLOYMENT_TARGET}\"  -a -z \"${WATCHOS_DEPLOYMENT_TARGET}\"  ] ; then\n        SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\n    else\n        SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\n    fi\n    (umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\n    cp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\nfi";
+                       shellScript = "# Copy Sandbox profile\n[[ \"${PLATFORM_NAME}\" =~ \"simulator\" ]] && exit 0\n\nif [[ \"${PLATFORM_NAME}\" == \"macosx\" || \"${PLATFORM_NAME}\" == \"bridgeos\" ]] ; then\n    SANDBOXDST=\"${DSTROOT}/usr/share/sandbox\"\nelse\n    SANDBOXDST=\"${DSTROOT}/usr/local/share/sandbox/profiles/embedded/builtin\"\nfi\n(umask 022; mkdir -p -m 0755 \"$SANDBOXDST\")\ncp \"${SRCROOT}/mDNSResponder.sb\" \"${SANDBOXDST}/mDNSResponder.sb\"\n";
                };
                D284BE510ADD80740027CCDF /* ShellScript */ = {
                        isa = PBXShellScriptBuildPhase;
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                        shellPath = /bin/sh;
-                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/WebFilterDNS.framework/Headers/WebFilterDNS.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS\"\necho \"#define NO_WCF 1\" > \"${CONFIGURATION_TEMP_DIR}/WebFilterDNS/WebFilterDNS.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi\n";
+                       shellScript = "if [ -e \"${SDKROOT}/usr/local/include/dnsinfo.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/dnsinfo.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nelse\necho \"#define MDNS_NO_DNSINFO 1\" > ${CONFIGURATION_TEMP_DIR}/dnsinfo.h\ntouch \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/empty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libdnsinfo.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/empty.c\"\nfi\n\nif [ -e \"${SDKROOT}/usr/include/sandbox.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nelse\necho \"#define MDNS_NO_SANDBOX 1\" > \"${CONFIGURATION_TEMP_DIR}/sandbox.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/vproc.h\" -o -e \"${SDKROOT}/usr/include/vproc.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nelse\ntouch \"${CONFIGURATION_TEMP_DIR}/vproc.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/Frameworks/IOKit.framework/PrivateHeaders/pwr_mgt/IOPMLibPrivate.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/IOKit\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt\"\ntouch \"${CONFIGURATION_TEMP_DIR}/IOKit/pwr_mgt/IOPMLibPrivate.h\"\nfi\n\nif [ -e \"${SDKROOT}/System/Library/PrivateFrameworks/DeviceToDeviceManager.framework/Headers/DeviceToDeviceManager.h\" ]\nthen\nrm -rf \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\nelse\nmkdir -p \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager\"\necho \"#define NO_D2D 1\" > \"${CONFIGURATION_TEMP_DIR}/DeviceToDeviceManager/DeviceToDeviceManager.h\"\nfi\n\nif [ -e \"${SDKROOT}/usr/local/include/AWACS.h\" ]\nthen\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nelse\necho \"#define NO_AWACS 1\" > \"${CONFIGURATION_TEMP_DIR}/AWACS.h\"\ntouch \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfor i in ${ARCHS}\ndo\nccflags=\"-arch $i $ccflags\"\ndone\ncc ${ccflags} \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\" -c -o \"${CONFIGURATION_TEMP_DIR}/libAWACS.a\"\nrm -f \"${CONFIGURATION_TEMP_DIR}/AWACSempty.c\"\nfi\n";
                };
                D284BE6C0ADD80740027CCDF /* Run Script */ = {
                        isa = PBXShellScriptBuildPhase;
                        name = "Run Script";
                        runOnlyForDeploymentPostprocessing = 1;
                        shellPath = /bin/bash;
-                       shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj";
+                       shellScript = "# Install mDNSResponder.bundle containing language localizations\nmkdir -p ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices\ncp -R ${SRCROOT}/mDNSResponder-bundle ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle\n\n# Remove unwanted CVS directories\nfind ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -depth -name CVS -exec rm -rf {} \\;\n\n# Expand UTF-8 files to UTF-16 (at one time this appeared to be necessary, but it's not, so we don't do it any more)\n#foreach file (`find ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle -name Localizable.strings`)\n#iconv -f utf-8 -t utf-16 ${file} > ${file}.new\n#mv -f ${file}.new ${file}\n#end\n\n# Remove French localization (not wanted for Apple B&I builds)\nrm -rf ${DSTROOT}${SYSTEM_LIBRARY_DIR}/CoreServices/mDNSResponder.bundle/Resources/French.lproj\n";
+               };
+               D4C07948220A180000E485FF /* Create Log Directory  for mDNSResponder */ = {
+                       isa = PBXShellScriptBuildPhase;
+                       buildActionMask = 8;
+                       files = (
+                       );
+                       inputFileListPaths = (
+                       );
+                       inputPaths = (
+                       );
+                       name = "Create Log Directory  for mDNSResponder";
+                       outputFileListPaths = (
+                       );
+                       outputPaths = (
+                       );
+                       runOnlyForDeploymentPostprocessing = 1;
+                       shellPath = "/bin/bash -x";
+                       shellScript = "#!/bin/bash -x\n\n# Created by Joey Deng on 02/05/2019\n# Copyright 2019 Apple, Inc. All rights reserved.\n\n# This script creates the mdnsresponder directory in DSTROOT\n# with appropriate ownership and permissions\n\nMDNSRESPONDER_LOG_DIR=\"/private/var/log/mDNSResponder\"\nMDNSRESPONDER_USER=\"_mdnsresponder\"\nMDNSRESPONDER_USER_UID=65\n# MDNSRESPONDER_USER_UID is only used as a fallback\n# when the build machine does not have the right user\n\n\n[ \"$DSTROOT\" != \"\" ] && [ \"$DSTROOT\" != \"/\" ] && [ -d \"$DSTROOT\" ] || exit 1\n[ \"$(/usr/bin/whoami)\" == \"root\" ] || exit 0\n\nMDNSRESPONDER_LOG_DIR_TO_CREATE=\"${DSTROOT}${MDNSRESPONDER_LOG_DIR}\"\n\n/bin/mkdir -p -m 755 \"$MDNSRESPONDER_LOG_DIR_TO_CREATE\"\n\n/usr/bin/id \"$MDNSRESPONDER_USER\" >/dev/null 2>/dev/null\nif [ \"$?\" != \"0\" ] ; then\nMDNSRESPONDER_USER=\"$MDNSRESPONDER_USER_UID\"\nfi\n\n/usr/sbin/chown \"${MDNSRESPONDER_USER}:wheel\" \"$MDNSRESPONDER_LOG_DIR_TO_CREATE\"\n\n/bin/ls -ld \"$MDNSRESPONDER_LOG_DIR_TO_CREATE\"\n\nexit 0\n";
+                       showEnvVarsInLog = 0;
                };
 /* End PBXShellScriptBuildPhase section */
 
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               898E98342203619800812DC6 /* dso-transport.c in Sources */,
+                               898E98352203619800812DC6 /* dso.c in Sources */,
                                0C1596B61D7740B500E09998 /* NetMonitor.c in Sources */,
                                0C1596BB1D7740D700E09998 /* DNSDigest.c in Sources */,
                                0C1596B81D7740C100E09998 /* mDNSUNP.c in Sources */,
                                0C1596BC1D7740DC00E09998 /* DNSCommon.c in Sources */,
                                0C1596C01D77410A00E09998 /* GenLinkedList.c in Sources */,
                                0C1596BE1D7740E900E09998 /* mDNSDebug.c in Sources */,
-                               0C1596B91D7740CD00E09998 /* anonymous.c in Sources */,
                                0C1596BF1D7740EF00E09998 /* PlatformCommon.c in Sources */,
                                0C1596BA1D7740D200E09998 /* CryptoAlg.c in Sources */,
                                0C1596B51D7740B500E09998 /* mDNSPosix.c in Sources */,
                        files = (
                                2E0405F50C3195F700F13B59 /* helper.c in Sources */,
                                2E96A51D0C39BDAC0087C4D2 /* helper-main.c in Sources */,
-                               2E8165E90C5980EE00485EB2 /* pfkey.c in Sources */,
                                4BD2B63A134FE09F002B96D5 /* P2PPacketFilter.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               37DDE9291BA383610092AC61 /* Sources */ = {
+               84C5B3311665529800C324A8 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               0CB1C7FC1D9C5C1100A5939F /* D2D.c in Sources */,
-                               37538E1F1D7A504F00226BE4 /* helper-stubs.c in Sources */,
-                               37538E1E1D7A4F9D00226BE4 /* anonymous.c in Sources */,
-                               37538E1D1D7A449D00226BE4 /* coreBLE.m in Sources */,
-                               37538E1C1D7A449000226BE4 /* Metrics.m in Sources */,
-                               37812CD41D7A307200F34505 /* BLE.c in Sources */,
-                               37812CD71D7A307200F34505 /* CryptoAlg.c in Sources */,
-                               37812CD81D7A307200F34505 /* CryptoSupport.c in Sources */,
-                               37812CD91D7A307200F34505 /* daemon.c in Sources */,
-                               37812CDA1D7A307200F34505 /* dns_services.c in Sources */,
-                               37812CDB1D7A307200F34505 /* DNSDigest.c in Sources */,
-                               37812CDE1D7A307200F34505 /* dnsproxy.c in Sources */,
-                               37812CDF1D7A307200F34505 /* DNSProxySupport.c in Sources */,
-                               37812CE01D7A307200F34505 /* dnssd_clientlib.c in Sources */,
-                               37812CE11D7A307300F34505 /* dnssd_clientstub.c in Sources */,
-                               37812CE21D7A307300F34505 /* dnssd_ipc.c in Sources */,
-                               37812CE31D7A307300F34505 /* dnssec.c in Sources */,
-                               37812CE41D7A307300F34505 /* DNSSECSupport.c in Sources */,
-                               37812CE51D7A307300F34505 /* GenLinkedList.c in Sources */,
-                               37812CE91D7A307300F34505 /* LegacyNATTraversal.c in Sources */,
-                               37812CEA1D7A307300F34505 /* mDNS.c in Sources */,
-                               37812CEB1D7A307300F34505 /* mDNSDebug.c in Sources */,
-                               37812CEC1D7A307300F34505 /* mDNSMacOSX.c in Sources */,
-                               37812CED1D7A307300F34505 /* nsec.c in Sources */,
-                               37812CEE1D7A307300F34505 /* nsec3.c in Sources */,
-                               37812CEF1D7A307300F34505 /* P2PPacketFilter.c in Sources */,
-                               37812CF11D7A307300F34505 /* PlatformCommon.c in Sources */,
-                               37812CF21D7A307300F34505 /* SymptomReporter.c in Sources */,
-                               37812CF31D7A307300F34505 /* uDNS.c in Sources */,
-                               37812CF41D7A307300F34505 /* uDNSPathEvalulation.c in Sources */,
-                               37812CF51D7A307300F34505 /* uds_daemon.c in Sources */,
-                               37812CF61D7A307300F34505 /* dnsctl_server.c in Sources */,
-                               37812CF71D7A307300F34505 /* xpc_services.c in Sources */,
-                               371D0FBF1BF666EB00E5DB26 /* ResourceRecordTest.c in Sources */,
-                               37FEBD581BC789AA00638EA4 /* DNSCommon.c in Sources */,
-                               37DDE9331BA383D30092AC61 /* unittest.c in Sources */,
-                               371D0FBC1BF545FA00E5DB26 /* InterfaceTest.c in Sources */,
-                               373202101BAB4444007DE806 /* DNSMessageTest.c in Sources */,
-                               0C7C00501DD553640078BA89 /* unittest_common.c in Sources */,
-                               0C5674B41DA2BF8600AF3367 /* mDNSCoreReceiveTest.c in Sources */,
-                               0C10EC281DDB956E00D7A0E3 /* LocalOnlyTimeoutTests.c in Sources */,
-                               0C7C00511DD5536E0078BA89 /* CNameRecordTests.c in Sources */,
-                               3771F67D1BA387DD0072355E /* main.c in Sources */,
+                               84C5B33C166553F100C324A8 /* dns_services.c in Sources */,
+                               BD11267A21DB2A9B006115E6 /* dnssd.c in Sources */,
+                               BD11267921DB2A9B006115E6 /* dnssd_object.m in Sources */,
+                               BD11267F21DB303F006115E6 /* dnssd_xpc.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               72FB545B166D5FB00090B2D9 /* Sources */ = {
+               B7325FE91DA47EBA00663834 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               72FB5467166D5FCA0090B2D9 /* dnsctl.c in Sources */,
+                               B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */,
+                               B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */,
+                               B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */,
+                               B76431A01DB0423900DB376D /* ClientCommon.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               84C5B3311665529800C324A8 /* Sources */ = {
+               B7473E5D1EC3954400D31B9D /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               84C5B33C166553F100C324A8 /* dns_services.c in Sources */,
+                               B7473E6C1EC3954400D31B9D /* ViewController.m in Sources */,
+                               B7473E691EC3954400D31B9D /* main.m in Sources */,
+                               B7473E671EC3954400D31B9D /* AppDelegate.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
-               B7325FE91DA47EBA00663834 /* Sources */ = {
+               B7473E761EC395C300D31B9D /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               B7325FF81DA47FB000663834 /* CNDomainBrowserViewController.m in Sources */,
-                               B79920A11DA6BA8E00C6E02B /* CNDomainBrowserPathUtils.m in Sources */,
-                               B7325FF91DA47FB000663834 /* _CNDomainBrowser.m in Sources */,
-                               B76431A01DB0423900DB376D /* ClientCommon.c in Sources */,
+                               B7473E971EC3C77D00D31B9D /* CNDomainBrowserPathUtils.m in Sources */,
+                               B7473E861EC395C300D31B9D /* SafariExtensionViewController.m in Sources */,
+                               B7473E831EC395C300D31B9D /* SafariExtensionHandler.m in Sources */,
+                               B7473E981EC3C78300D31B9D /* _CNDomainBrowser.m in Sources */,
+                               B7473E961EC3C77800D31B9D /* CNDomainBrowserView.m in Sources */,
+                               B7473E991EC3C86600D31B9D /* ClientCommon.c in Sources */,
+                               B76373761ECA25DE00B9404A /* CNServiceBrowserView.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               B74F16E72114E49C00BEBE84 /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               898E98392203633800812DC6 /* dnssd_clientshim.c in Sources */,
+                               D459F0D4222862BA0056AC5B /* HelperFunctionTest.m in Sources */,
+                               898E983A2203633800812DC6 /* dso-transport.c in Sources */,
+                               898E983B2203633800812DC6 /* dso.c in Sources */,
+                               B7EEF7C1212601460093828F /* mDNSMacOSX.c in Sources */,
+                               B7EEF7CC212604A80093828F /* LegacyNATTraversal.c in Sources */,
+                               B7A86199212B074500E81CC3 /* LocalOnlyTimeoutTest.m in Sources */,
+                               B7EEF7CB2126048F0093828F /* SymptomReporter.c in Sources */,
+                               B7EEF7D6212606F50093828F /* uDNSPathEvalulation.c in Sources */,
+                               B7EEF7EA212613260093828F /* uds_daemon.c in Sources */,
+                               B7A861952127806600E81CC3 /* unittest_common.c in Sources */,
+                               B7EEF7E921260E4C0093828F /* CryptoSupport.c in Sources */,
+                               B7EEF7D9212607C40093828F /* nsec.c in Sources */,
+                               D40123912272B6E3006C9BBE /* mdns_object.m in Sources */,
+                               D461F9512203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */,
+                               B7A861972127845800E81CC3 /* CNameRecordTest.m in Sources */,
+                               B7EEF7C5212603D50093828F /* CryptoAlg.c in Sources */,
+                               D461F94C2203A6B400A88910 /* xpc_services.c in Sources */,
+                               B7EEF7EC212613D10093828F /* dnsproxy.c in Sources */,
+                               B7EEF7D7212607520093828F /* mDNSDebug.c in Sources */,
+                               B7EEF7E421260DC90093828F /* dnssd_ipc.c in Sources */,
+                               B7EEF7E221260A610093828F /* PlatformCommon.c in Sources */,
+                               B7EEF7E521260DE80093828F /* daemon.c in Sources */,
+                               B7EEF7C2212602EC0093828F /* mDNS.c in Sources */,
+                               B7EEF7ED212613D50093828F /* DNSProxySupport.c in Sources */,
+                               D40123922272B7A7006C9BBE /* mdns.c in Sources */,
+                               B7EEF7CA2126046A0093828F /* uDNS.c in Sources */,
+                               D4F2BB2822CD21CB00234A38 /* posix_utilities.c in Sources */,
+                               B7EEF7D82126076F0093828F /* dnssec.c in Sources */,
+                               B7EEF7E021260A1F0093828F /* helper-stubs.c in Sources */,
+                               B79FA14B211CE8CA00B7861E /* DNSCommon.c in Sources */,
+                               B7EEF7CD212604CB0093828F /* DNSDigest.c in Sources */,
+                               B7A8618B21274FA200E81CC3 /* mDNSCoreReceiveTest.m in Sources */,
+                               B7EEF7DA212608F50093828F /* nsec3.c in Sources */,
+                               B7EEF7DB2126090D0093828F /* DNSSECSupport.c in Sources */,
+                               BDF2D02A2169961900D0DBF5 /* ClientRequests.c in Sources */,
+                               B7EEF7D0212605170093828F /* D2D.c in Sources */,
+                               B74F16F4211BA55400BEBE84 /* DNSMessageTest.m in Sources */,
+                               D448F7AF222DCC8F0069E1D2 /* system_utilities.c in Sources */,
+                               D4C2AED72203E4F900B35685 /* xpc_service_log_utility.c in Sources */,
+                               B7A8618921274BFC00E81CC3 /* ResourceRecordTest.m in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                B76783A81E82D65900DA271E /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
-                               BD9BA7551EAF91FB00658CCF /* dnssdutil.c in Sources */,
+                               BD97754C221D643600F68FFC /* dnssdutil.c in Sources */,
+                               BD97754F221D64BF00F68FFC /* DNSMessage.c in Sources */,
+                               BD2A15BA225ED31C00BEA50A /* mdns.c in Sources */,
+                               BD2A15BB225ED33C00BEA50A /* mdns_object.m in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        files = (
                                22C7633E1D777B940077AFCA /* D2D.c in Sources */,
                                227687F31C90AD580019382D /* coreBLE.m in Sources */,
+                               BD11267421DB1B4D006115E6 /* dnssd_xpc.c in Sources */,
+                               897729B32202A5370018FAEB /* dso-transport.c in Sources */,
                                D284BE580ADD80740027CCDF /* mDNS.c in Sources */,
                                BD691B2A1ED2F47100E6F317 /* DNS64.c in Sources */,
+                               BD11267321DB1B34006115E6 /* dnssd_server.c in Sources */,
                                D284BE590ADD80740027CCDF /* uDNS.c in Sources */,
                                D284BE5A0ADD80740027CCDF /* DNSCommon.c in Sources */,
                                D284BE5B0ADD80740027CCDF /* DNSDigest.c in Sources */,
                                D284BE5D0ADD80740027CCDF /* mDNSDebug.c in Sources */,
+                               D401238B227284FE006C9BBE /* mdns.c in Sources */,
+                               897729B22202A5370018FAEB /* dso.c in Sources */,
+                               D401238F227286BE006C9BBE /* mdns_object.m in Sources */,
+                               D461F9502203A8AA00A88910 /* xpc_service_dns_proxy.c in Sources */,
                                D284BE5E0ADD80740027CCDF /* uds_daemon.c in Sources */,
                                22448EA31C90A7BE004F25CC /* BLE.c in Sources */,
+                               D461F94B2203A6B400A88910 /* xpc_services.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 */,
                                2E96A5320C39C1A50087C4D2 /* helper-stubs.c in Sources */,
+                               897729B72202A5480018FAEB /* dnssd_clientshim.c in Sources */,
                                21A57F4C145B2AE100939099 /* CryptoAlg.c in Sources */,
+                               BD1628D02168B02700020528 /* ClientRequests.c in Sources */,
                                21A57F53145B2B1400939099 /* CryptoSupport.c in Sources */,
                                2124FA331471E9DE0021D7BB /* nsec.c in Sources */,
                                213BDC6D147319F400000896 /* dnssec.c in Sources */,
                                218E8E51156D8C0300720DA0 /* dnsproxy.c in Sources */,
+                               D4BFF8DB22B1C52100A0BA86 /* posix_utilities.c in Sources */,
                                21DED43515702C0F0060B6B9 /* DNSProxySupport.c in Sources */,
                                216D9ACE1720C9F5008066E1 /* uDNSPathEvalulation.c in Sources */,
                                BD03E88D1AD31278005E8A81 /* SymptomReporter.c in Sources */,
                                2127A47715C3C7B900A857FC /* nsec3.c in Sources */,
-                               21DD8FBF161E9A250033C8F8 /* anonymous.c in Sources */,
+                               D421B3E022178BE700D35C20 /* system_utilities.c in Sources */,
                                21070E5F16486B9000A69507 /* DNSSECSupport.c in Sources */,
-                               848DA5C7165477E000D2E8B4 /* xpc_services.c in Sources */,
-                               8417375C1B967D37000CD5C2 /* dnsctl_server.c in Sources */,
+                               D4C2AED62203E4F900B35685 /* xpc_service_log_utility.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        files = (
+                               898E98362203621200812DC6 /* dnssd_clientshim.c in Sources */,
+                               898E98372203621200812DC6 /* dso-transport.c in Sources */,
+                               898E98382203621200812DC6 /* dso.c in Sources */,
                                21DCD05C1461B23700702FC8 /* CryptoAlg.c in Sources */,
                                D284BEC50ADD80A20027CCDF /* DNSCommon.c in Sources */,
                                D284BEC60ADD80A20027CCDF /* DNSDigest.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
+               D4CFA7C921E7B95E00F5AD0E /* Sources */ = {
+                       isa = PBXSourcesBuildPhase;
+                       buildActionMask = 2147483647;
+                       files = (
+                               D4CFA7D121E7BA0E00F5AD0E /* liblog_mdnsresponder.m in Sources */,
+                               D4A1591622E27D43002F6278 /* DNSMessage.c in Sources */,
+                       );
+                       runOnlyForDeploymentPostprocessing = 0;
+               };
                FFA572320AF18F1C0055A0F1 /* Sources */ = {
                        isa = PBXSourcesBuildPhase;
                        buildActionMask = 2147483647;
                        target = D284BE500ADD80740027CCDF /* mDNSResponder */;
                        targetProxy = 03067D670C83A3830022BE1F /* 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 */;
-               };
-               0C1596C71D7751AD00E09998 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 0C1596AB1D773FE300E09998 /* mDNSNetMonitor */;
-                       targetProxy = 0C1596C61D7751AD00E09998 /* PBXContainerItemProxy */;
-               };
-               0C2AAB321B6929F300113637 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 84C5B3341665529800C324A8 /* dns_services */;
-                       targetProxy = 0C2AAB311B6929F300113637 /* PBXContainerItemProxy */;
-               };
-               0C4F36B41E206711005A536B /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 37DDE92C1BA383610092AC61 /* unittests */;
-                       targetProxy = 0C4F36B31E206711005A536B /* PBXContainerItemProxy */;
-               };
-               0C52E92F1E96AD74006EFE7B /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 0C635A751E9418A60026C796 /* BonjourTop */;
-                       targetProxy = 0C52E92E1E96AD74006EFE7B /* PBXContainerItemProxy */;
-               };
                2130257112400E9300AC839F /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = FFA572650AF190F10055A0F1 /* SystemLibrariesDynamic */;
                        target = 2141DD29123FFD2C0086D23E /* libdns_sd_profile_static */;
                        targetProxy = 215FFB1C124002CC00470DE1 /* PBXContainerItemProxy */;
                };
-               217A4C49138EE14C000A5BA8 /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 213FB21712028A7A002B3A08 /* BonjourEvents */;
-                       targetProxy = 217A4C48138EE14C000A5BA8 /* PBXContainerItemProxy */;
-               };
                4AE4716A0EAFF83800A6C5AD /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 4AE471670EAFF81900A6C5AD /* dns_sd.jar */;
                        targetProxy = 4AE471690EAFF83800A6C5AD /* PBXContainerItemProxy */;
                };
-               84C5B3411665544B00C324A8 /* PBXTargetDependency */ = {
+               B70F38A6217AA6CE00612D3A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = B74F16EA2114E49C00BEBE84 /* Tests */;
+                       targetProxy = B70F38A7217AA6CE00612D3A /* PBXContainerItemProxy */;
+               };
+               B70F38A8217AA6CE00612D3A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = BD9BA7481EAF90E400658CCF /* dnssdutil */;
+                       targetProxy = B70F38A9217AA6CE00612D3A /* PBXContainerItemProxy */;
+               };
+               B70F38AE217AA6CE00612D3A /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D284BEA50ADD80920027CCDF /* dns-sd tool */;
+                       targetProxy = B70F38AF217AA6CE00612D3A /* PBXContainerItemProxy */;
+               };
+               B718416E21F8D0A600CA42AD /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = 84C5B3341665529800C324A8 /* dns_services */;
-                       targetProxy = 84C5B3401665544B00C324A8 /* PBXContainerItemProxy */;
+                       targetProxy = B718416F21F8D0A600CA42AD /* PBXContainerItemProxy */;
                };
-               B76783B91E82D83800DA271E /* PBXTargetDependency */ = {
+               B7237FDA2194D0EF00B113B1 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = B76783AB1E82D65900DA271E /* BonjourPrefsTool */;
-                       targetProxy = B76783B81E82D83800DA271E /* PBXContainerItemProxy */;
+                       target = 0C1596AB1D773FE300E09998 /* mDNSNetMonitor */;
+                       targetProxy = B7237FD92194D0EF00B113B1 /* PBXContainerItemProxy */;
                };
-               B7C4B72C1E71BD6000136C7A /* PBXTargetDependency */ = {
+               B7237FDC2194D16900B113B1 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = B74EC1151D47FC7700A1D155 /* BonjourSettings */;
-                       targetProxy = B7C4B72B1E71BD6000136C7A /* PBXContainerItemProxy */;
+                       target = B70F38A5217AA6CE00612D3A /* Build Extras */;
+                       targetProxy = B7237FDB2194D16900B113B1 /* PBXContainerItemProxy */;
+               };
+               B7237FDE2194D16E00B113B1 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = B70F38A5217AA6CE00612D3A /* Build Extras */;
+                       targetProxy = B7237FDD2194D16E00B113B1 /* PBXContainerItemProxy */;
+               };
+               B7237FE62194D99200B113B1 /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = 213FB21712028A7A002B3A08 /* BonjourEvents */;
+                       targetProxy = B7237FE52194D99200B113B1 /* PBXContainerItemProxy */;
+               };
+               B7473E901EC395C300D31B9D /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = B7473E791EC395C300D31B9D /* Bonjour Safari Extension */;
+                       targetProxy = B7473E8F1EC395C300D31B9D /* PBXContainerItemProxy */;
                };
-               B7C4B72E1E71BE3500136C7A /* PBXTargetDependency */ = {
+               B76783B91E82D83800DA271E /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = 03067D640C83A3700022BE1F /* Build Some */;
-                       targetProxy = B7C4B72D1E71BE3500136C7A /* PBXContainerItemProxy */;
+                       target = B76783AB1E82D65900DA271E /* BonjourPrefsTool */;
+                       targetProxy = B76783B81E82D83800DA271E /* PBXContainerItemProxy */;
                };
                B7D566C81E81D9E700E43008 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
                        target = B7D566B91E81D8FD00E43008 /* RemoteViewService */;
                        targetProxy = B7D566C71E81D9E700E43008 /* PBXContainerItemProxy */;
                };
-               BD7833F01ABA5E3500EC51ED /* PBXTargetDependency */ = {
+               B7DB589A215EB4F70054CD46 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = 72FB545E166D5FB00090B2D9 /* dnsctl */;
-                       targetProxy = BD7833EF1ABA5E3500EC51ED /* PBXContainerItemProxy */;
+                       target = B74EC1151D47FC7700A1D155 /* BonjourSettings */;
+                       targetProxy = B7DB5899215EB4F70054CD46 /* PBXContainerItemProxy */;
                };
-               BD9BA7721EAFA3D500658CCF /* PBXTargetDependency */ = {
+               B7DB58A0215EB61C0054CD46 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = BD9BA7481EAF90E400658CCF /* dnssdutil */;
-                       targetProxy = BD9BA7711EAFA3D500658CCF /* PBXContainerItemProxy */;
+                       target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
+                       targetProxy = B7DB58A1215EB61C0054CD46 /* PBXContainerItemProxy */;
                };
-               D284BF2C0ADD815A0027CCDF /* PBXTargetDependency */ = {
+               B7DB58A6215ED26D0054CD46 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = D284BEBF0ADD80A20027CCDF /* dnsextd */;
-                       targetProxy = D284BF2B0ADD815A0027CCDF /* PBXContainerItemProxy */;
+                       target = B7473E601EC3954400D31B9D /* Bonjour Safari Menu */;
+                       targetProxy = B7DB58A5215ED26D0054CD46 /* PBXContainerItemProxy */;
                };
-               D284BF300ADD81630027CCDF /* PBXTargetDependency */ = {
+               B7DB58C2215F04490054CD46 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = D284BEEA0ADD80B00027CCDF /* PreferencePane */;
-                       targetProxy = D284BF2F0ADD81630027CCDF /* PBXContainerItemProxy */;
+                       target = 0C635A751E9418A60026C796 /* BonjourTop */;
+                       targetProxy = B7DB58C1215F04490054CD46 /* PBXContainerItemProxy */;
+               };
+               D4528FFE21F91263004D61BF /* PBXTargetDependency */ = {
+                       isa = PBXTargetDependency;
+                       target = D4CFA7CB21E7B95E00F5AD0E /* liblog_mdnsresponder */;
+                       targetProxy = D4528FFD21F91263004D61BF /* PBXContainerItemProxy */;
                };
                FFA572690AF190FF0055A0F1 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = FFB765830AEED9C700583A2C /* libdns_sd_dynamic */;
+                       target = FFB765830AEED9C700583A2C /* libsystem_dnssd */;
                        targetProxy = FFA572680AF190FF0055A0F1 /* PBXContainerItemProxy */;
                };
                FFA5726B0AF191010055A0F1 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = FFA572300AF18F1C0055A0F1 /* libdns_sd_debug_dynamic */;
+                       target = FFA572300AF18F1C0055A0F1 /* libsystem_dnssd_debug */;
                        targetProxy = FFA5726A0AF191010055A0F1 /* PBXContainerItemProxy */;
                };
                FFA5726D0AF191020055A0F1 /* PBXTargetDependency */ = {
                        isa = PBXTargetDependency;
-                       target = FFA5723C0AF18F450055A0F1 /* libdns_sd_profile_dynamic */;
+                       target = FFA5723C0AF18F450055A0F1 /* libsystem_dnssd_profile */;
                        targetProxy = FFA5726C0AF191020055A0F1 /* PBXContainerItemProxy */;
                };
-               FFB7657D0AEED97F00583A2C /* PBXTargetDependency */ = {
-                       isa = PBXTargetDependency;
-                       target = 00AD62BB032D7A0C0CCA2C71 /* Build More */;
-                       targetProxy = FFB7657C0AEED97F00583A2C /* PBXContainerItemProxy */;
-               };
 /* End PBXTargetDependency section */
 
 /* Begin PBXVariantGroup section */
-               FF260A4807B4475600CE10E5 /* DNSServiceDiscoveryPref.nib */ = {
+               B7473E6F1EC3954400D31B9D /* Main.storyboard */ = {
                        isa = PBXVariantGroup;
                        children = (
-                               B7E5920F1DB687A700A38085 /* Base */,
+                               B7473E701EC3954400D31B9D /* Base */,
                        );
-                       name = DNSServiceDiscoveryPref.nib;
-                       path = PreferencePane;
-                       sourceTree = SOURCE_ROOT;
+                       name = Main.storyboard;
+                       sourceTree = "<group>";
+               };
+               B7473E871EC395C300D31B9D /* SafariExtensionViewController.xib */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               B7473E881EC395C300D31B9D /* Base */,
+                       );
+                       name = SafariExtensionViewController.xib;
+                       sourceTree = "<group>";
+               };
+               B78A9C2E223941A900BFB0C6 /* DNSServiceDiscoveryPref.xib */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               B78A9C2F223941A900BFB0C6 /* Base */,
+                       );
+                       name = DNSServiceDiscoveryPref.xib;
+                       sourceTree = "<group>";
                };
                FF260A4B07B4477F00CE10E5 /* InfoPlist.strings */ = {
                        isa = PBXVariantGroup;
                        children = (
-                               FF260A4C07B4477F00CE10E5 /* English */,
+                               B78A9C322239485E00BFB0C6 /* en */,
                        );
                        name = InfoPlist.strings;
                        path = PreferencePane;
                0C1596B01D773FE300E09998 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                GCC_NO_COMMON_BLOCKS = YES;
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "USE_LIBIDN=1",
-                                       "USE_AWD=0",
                                        "__MAC_OS_X_VERSION_MIN_REQUIRED=1",
                                        "IPV6_PKTINFO=1",
                                        "HAVE_IPV6=1",
                0C1596B11D773FE300E09998 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                        "DEBUG=1",
                                        "HAVE_IPV6=1",
                                        "_BUILDING_XCODE_PROJECT_=1",
-                                       "USE_AWD=0",
                                        "__MAC_OS_X_VERSION_MIN_REQUIRED=1",
                                        "IPV6_PKTINFO=1",
                                );
                0C419F121BA20DF600A70FF7 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Debug";
                                CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)/Debug";
                                COPY_PHASE_STRIP = NO;
                                        "mDNSResponderVersion=${MVERS}",
                                        _LEGACY_NAT_TRAVERSAL_,
                                        "_BUILDING_XCODE_PROJECT_=1",
-                                       "BONJOUR_ON_DEMAND=1",
                                        "USE_LIBIDN=1",
-                                       "USE_AWD=1",
                                        "DEBUG=1",
                                );
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                SDKROOT = macosx.internal;
                                STRIP_INSTALLED_PRODUCT = NO;
                                STRIP_STYLE = debugging;
-                               SUPPORTED_PLATFORMS = "macosx iphoneos";
+                               SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos";
                                WARNING_CFLAGS = (
                                        "-W",
                                        "-Wall",
                        };
                        name = Debug;
                };
-               0C419F131BA20DF600A70FF7 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               PRODUCT_NAME = "Build All";
-                       };
-                       name = Debug;
-               };
                0C419F141BA20DF600A70FF7 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                "APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES;
                                "APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES;
                                "APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
                                CODE_SIGN_ENTITLEMENTS = "mDNSResponder-entitlements.plist";
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = (
                                );
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "$(inherited)",
-                                       "HAVE_DNS64=1",
+                                       "MDNSRESPONDER_PLATFORM_APPLE=1",
+                                       DSO_USES_NETWORK_FRAMEWORK,
                                );
-                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                                HEADER_SEARCH_PATHS = (
-                                       "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
                                        ../mDNSShared,
                                        "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
                                        "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
                                );
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
                                OTHER_LDFLAGS = "";
                                "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
                                        "-weak_framework",
                                        DeviceToDeviceManager,
-                                       "-lMobileGestalt",
                                );
                                "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
                                        "-weak_framework",
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
                                PRODUCT_NAME = mDNSResponder;
                                PROVISIONING_PROFILE = "";
+                               WARNING_CFLAGS = (
+                                       "-W",
+                                       "-Wall",
+                                       "-Wmissing-prototypes",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                                       "-Wshadow",
+                                       "-Wno-format",
+                                       "-Wformat-security",
+                               );
                        };
                        name = Debug;
                };
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
                                MACOSX_DEPLOYMENT_TARGET = 10.10;
-                               OTHER_LDFLAGS = "-lipsec";
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=appletvos*]" = binary;
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary;
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
                0C419F181BA20DF600A70FF7 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               CODE_SIGN_ENTITLEMENTS = "command_line_client_entitlements/dns-sd-entitlements.plist";
+                               CODE_SIGN_IDENTITY = "-";
                                HEADER_SEARCH_PATHS = (
                                        ../mDNSShared,
                                        "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
                        };
                        name = Debug;
                };
-               0C419F191BA20DF600A70FF7 /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               CODE_SIGN_ENTITLEMENTS = "dnsctl-entitlements.plist";
-                               CODE_SIGN_IDENTITY = "-";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_ENABLE_OBJC_EXCEPTIONS = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_STRICT_ALIASING = YES;
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               INSTALL_PATH = /usr/local/bin;
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE = "";
-                               SDKROOT = macosx;
-                       };
-                       name = Debug;
-               };
                0C419F1A1BA20DF600A70FF7 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                        "mDNSResponderVersion=${MVERS}",
                                        _LEGACY_NAT_TRAVERSAL_,
                                        "_BUILDING_XCODE_PROJECT_=1",
-                                       "BONJOUR_ON_DEMAND=1",
                                        "USE_LIBIDN=1",
-                                       "USE_AWD=1",
                                );
                                HEADER_SEARCH_PATHS = (
+                                       "$(SRCROOT)/../mDNSShared",
                                        "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
                                        "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
                                        "${CONFIGURATION_TEMP_DIR}",
                                );
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                OTHER_CFLAGS = "-UAPPLE_OSX_mDNSResponder";
                                PRODUCT_NAME = dnsextd;
                        };
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
                                INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                ONLY_ACTIVE_ARCH = YES;
                                PRODUCT_NAME = Bonjour;
                                SUPPORTED_PLATFORMS = macosx;
                0C419F1D1BA20DF600A70FF7 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                BUNDLE_LOADER = /usr/libexec/UserEventAgent;
-                               CODE_SIGN_IDENTITY = "-";
                                INFOPLIST_FILE = "BonjourEvents-Info.plist";
                                INSTALL_PATH = /System/Library/UserEventPlugins/;
                                PRODUCT_NAME = BonjourEvents;
                                INSTALL_PATH = /usr/lib/system;
                                INTERPOSITION_SIM_SUFFIX = "";
                                "INTERPOSITION_SIM_SUFFIX[sdk=iphonesimulator*]" = _sim;
-                               IS_ZIPPERED = YES;
+                               "IS_ZIPPERED[sdk=macosx*]" = YES;
                                LINK_WITH_STANDARD_LIBRARIES = NO;
                                OTHER_LDFLAGS = (
                                        "-Wl,-umbrella,System",
                                        "-lsystem_c",
                                        "-lsystem_blocks",
                                        "-ldispatch",
-                                       "-llaunch",
                                        "-lsystem_asl",
                                );
                                OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
                                        "-lsystem_c",
                                        "-lsystem_blocks",
                                        "-ldispatch",
-                                       "-llaunch",
                                        "-lsystem_asl",
                                );
-                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
                                PRODUCT_NAME = libsystem_dnssd_debug;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
                                SUPPORTS_TEXT_BASED_API = YES;
                                        "-lsystem_c",
                                        "-lsystem_blocks",
                                        "-ldispatch",
-                                       "-llaunch",
                                        "-lsystem_asl",
                                );
-                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
                                PRODUCT_NAME = libsystem_dnssd_profile;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
                                SUPPORTS_TEXT_BASED_API = YES;
                0C419F271BA20DF600A70FF7 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+                               CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
+                               CLANG_WARN_ASSIGN_ENUM = YES;
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_CXX0X_EXTENSIONS = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
                                CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_FLOAT_CONVERSION = YES;
+                               CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_INTERFACE_IVARS = YES;
+                               CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+                               CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
+                               CLANG_WARN_STRICT_PROTOTYPES = YES;
+                               CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
                                EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
                                GCC_ENABLE_OBJC_EXCEPTIONS = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
+                               GCC_PREPROCESSOR_DEFINITIONS = "DEBUG=1";
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+                               GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+                               GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+                               GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
                                GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+                               GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+                               GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+                               GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+                               GCC_WARN_PEDANTIC = YES;
+                               GCC_WARN_SHADOW = YES;
+                               GCC_WARN_SIGN_COMPARE = YES;
+                               GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNKNOWN_PRAGMAS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_LABEL = YES;
+                               GCC_WARN_UNUSED_PARAMETER = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INSTALL_PATH = /usr/lib;
-                               MACOSX_DEPLOYMENT_TARGET = 10.8;
+                               "IS_ZIPPERED[sdk=macosx*]" = YES;
+                               LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
+                               LLVM_LTO = YES;
                                ONLY_ACTIVE_ARCH = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               SDKROOT = macosx;
+                               SDKROOT = macosx.internal;
+                               SUPPORTS_TEXT_BASED_API = YES;
+                               TAPI_VERIFY_MODE = Pedantic;
+                               WARNING_CFLAGS = (
+                                       "$(inherited)",
+                                       "-Wall",
+                                       "-Warc-repeated-use-of-weak",
+                                       "-Wassign-enum",
+                                       "-Wconditional-uninitialized",
+                                       "-Wconversion",
+                                       "-Werror",
+                                       "-Werror-implicit-function-declaration",
+                                       "-Wextra",
+                                       "-Wfour-char-constants",
+                                       "-Wpedantic",
+                                       "-Wsign-compare",
+                                       "-Wsign-conversion",
+                                       "-Wundef",
+                                       "-Wuninitialized",
+                                       "-Wunreachable-code",
+                                       "-Wunused-parameter",
+                                       "-Wunused-parameter",
+                                       "-Wstrict-selector-match",
+                                       "-Wexplicit-ownership-type",
+                                       "-pedantic",
+                                       "-Wno-nullability-extension",
+                               );
                        };
                        name = Debug;
                };
                0C635A7A1E9418A60026C796 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                OTHER_LDFLAGS = "-lncurses";
                                PRODUCT_NAME = bonjourtop;
                0C635A7B1E9418A60026C796 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                OTHER_LDFLAGS = "-lncurses";
                213FB21A12028A7B002B3A08 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                BUNDLE_LOADER = /usr/libexec/UserEventAgent;
-                               CODE_SIGN_IDENTITY = "-";
                                INFOPLIST_FILE = "BonjourEvents-Info.plist";
                                INSTALL_PATH = /System/Library/UserEventPlugins/;
                                PRODUCT_NAME = BonjourEvents;
                                );
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
-                               OTHER_LDFLAGS = "-lipsec";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=appletvos*]" = binary;
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=iphoneos*]" = binary;
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
                        };
                        name = Release;
                };
-               37AF80281BF6997A00D657F6 /* Release */ = {
+               84C5B3371665529800C324A8 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = YES;
-                               DEAD_CODE_STRIPPING = YES;
-                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
-                                       "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
-                               );
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "__APPLE_USE_RFC_3542=1",
-                                       "APPLE_OSX_mDNSResponder=1",
-                                       "__MigTypeCheck=1",
-                                       "mDNSResponderVersion=${MVERS}",
-                                       _LEGACY_NAT_TRAVERSAL_,
-                                       "_BUILDING_XCODE_PROJECT_=1",
-                                       "BONJOUR_ON_DEMAND=1",
-                                       "USE_LIBIDN=1",
-                                       "USE_AWD=1",
-                                       "UNIT_TEST=1",
-                                       "NO_AWACS=1",
-                               );
-                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
-                               HEADER_SEARCH_PATHS = (
-                                       "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
-                                       ../mDNSShared,
-                                       "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
-                                       "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
-                                       "${CONFIGURATION_TEMP_DIR}",
-                                       "$(SDKROOT)/usr/include/libxml2",
-                                       "$(SDKROOT)/usr/local/include/",
-                                       "$(SDKROOT)/usr/include/",
-                               );
-                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
+                               CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
+                               CLANG_WARN_ASSIGN_ENUM = YES;
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_CXX0X_EXTENSIONS = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_FLOAT_CONVERSION = YES;
+                               CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_ATOMIC_PROPERTIES = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_INTERFACE_IVARS = YES;
+                               CLANG_WARN_OBJC_MISSING_PROPERTY_SYNTHESIS = YES;
+                               CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
+                               CLANG_WARN_STRICT_PROTOTYPES = YES;
+                               CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
+                               EXECUTABLE_PREFIX = lib;
+                               GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = "";
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+                               GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
+                               GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
+                               GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
+                               GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
+                               GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES;
+                               GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
+                               GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
+                               GCC_WARN_NON_VIRTUAL_DESTRUCTOR = YES;
+                               GCC_WARN_PEDANTIC = YES;
+                               GCC_WARN_SHADOW = YES;
+                               GCC_WARN_SIGN_COMPARE = YES;
+                               GCC_WARN_STRICT_SELECTOR_MATCH = YES;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNKNOWN_PRAGMAS = YES;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_LABEL = YES;
+                               GCC_WARN_UNUSED_PARAMETER = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INSTALL_PATH = /usr/lib;
+                               "IS_ZIPPERED[sdk=macosx*]" = YES;
+                               LD_DYLIB_INSTALL_NAME = "$(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH)";
+                               LLVM_LTO = YES;
                                ONLY_ACTIVE_ARCH = NO;
-                               OTHER_LDFLAGS = (
-                                       "-weak_framework",
-                                       WebFilterDNS,
-                                       "-weak_framework",
-                                       DeviceToDeviceManager,
-                               );
-                               PRODUCT_NAME = unittests;
-                               SKIP_INSTALL = YES;
-                               SUPPORTED_PLATFORMS = macosx;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx.internal;
+                               SUPPORTS_TEXT_BASED_API = YES;
+                               TAPI_VERIFY_MODE = Pedantic;
                                WARNING_CFLAGS = (
-                                       "-W",
+                                       "$(inherited)",
                                        "-Wall",
-                                       "-Wmissing-prototypes",
-                                       "-Wno-four-char-constants",
-                                       "-Wno-unknown-pragmas",
-                                       "-Wshadow",
-                                       "-Wno-format",
-                                       "-Wformat-security",
+                                       "-Warc-repeated-use-of-weak",
+                                       "-Wassign-enum",
+                                       "-Wconditional-uninitialized",
+                                       "-Wconversion",
+                                       "-Werror",
+                                       "-Werror-implicit-function-declaration",
+                                       "-Wextra",
+                                       "-Wfour-char-constants",
+                                       "-Wpedantic",
+                                       "-Wsign-compare",
+                                       "-Wsign-conversion",
+                                       "-Wundef",
+                                       "-Wuninitialized",
+                                       "-Wunreachable-code",
+                                       "-Wunused-parameter",
+                                       "-Wunused-parameter",
+                                       "-Wstrict-selector-match",
+                                       "-Wexplicit-ownership-type",
+                                       "-pedantic",
+                                       "-Wno-nullability-extension",
                                );
                        };
                        name = Release;
                };
-               37AF80291BF6997A00D657F6 /* Debug */ = {
+               B70F38B1217AA6CE00612D3A /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               COPY_PHASE_STRIP = NO;
-                               DEAD_CODE_STRIPPING = YES;
-                               ENABLE_TESTABILITY = YES;
-                               FRAMEWORK_SEARCH_PATHS = (
-                                       "$(inherited)",
-                                       "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
-                                       "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
-                               );
-                               GCC_DYNAMIC_NO_PIC = NO;
-                               GCC_OPTIMIZATION_LEVEL = 0;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "__APPLE_USE_RFC_3542=1",
-                                       "APPLE_OSX_mDNSResponder=1",
-                                       "__MigTypeCheck=1",
-                                       "mDNSResponderVersion=${MVERS}",
-                                       _LEGACY_NAT_TRAVERSAL_,
-                                       "_BUILDING_XCODE_PROJECT_=1",
-                                       "DEBUG=1",
-                                       "BONJOUR_ON_DEMAND=1",
-                                       "USE_LIBIDN=1",
-                                       "USE_AWD=1",
-                                       "UNIT_TEST=1",
-                                       "NO_AWACS=1",
-                               );
-                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
-                               HEADER_SEARCH_PATHS = (
-                                       "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
-                                       ../mDNSShared,
-                                       "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
-                                       "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
-                                       "${CONFIGURATION_TEMP_DIR}",
-                                       "$(SDKROOT)/usr/include/libxml2",
-                                       "$(SDKROOT)/usr/local/include/",
-                                       "$(SDKROOT)/usr/include/",
-                               );
-                               LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
-                               ONLY_ACTIVE_ARCH = NO;
-                               OTHER_LDFLAGS = (
-                                       "-weak_framework",
-                                       WebFilterDNS,
-                                       "-weak_framework",
-                                       DeviceToDeviceManager,
-                               );
-                               PRODUCT_NAME = unittests;
-                               SUPPORTED_PLATFORMS = "macosx iphoneos";
+                               CODE_SIGN_STYLE = Automatic;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
                        };
-                       name = Debug;
+                       name = Release;
                };
-               72FB5466166D5FB00090B2D9 /* Release */ = {
+               B70F38B2217AA6CE00612D3A /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_ENABLE_OBJC_ARC = YES;
-                               CLANG_WARN_CONSTANT_CONVERSION = YES;
-                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN_INT_CONVERSION = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               CODE_SIGN_ENTITLEMENTS = "dnsctl-entitlements.plist";
-                               CODE_SIGN_IDENTITY = "-";
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_ENABLE_OBJC_EXCEPTIONS = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_STRICT_ALIASING = YES;
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               INSTALL_PATH = /usr/local/bin;
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               CODE_SIGN_STYLE = Automatic;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               PROVISIONING_PROFILE = "";
-                               SDKROOT = macosx;
                        };
-                       name = Release;
+                       name = Debug;
                };
-               84C5B3371665529800C324A8 /* Release */ = {
+               B718417321F8D0A600CA42AD /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
-                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
-                               CLANG_CXX_LIBRARY = "libc++";
-                               CLANG_WARN_EMPTY_BODY = YES;
-                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
-                               EXECUTABLE_PREFIX = lib;
-                               GCC_C_LANGUAGE_STANDARD = gnu99;
-                               GCC_ENABLE_OBJC_EXCEPTIONS = YES;
-                               GCC_PREPROCESSOR_DEFINITIONS = (
-                                       "DEBUG=1",
-                                       "$(inherited)",
-                               );
-                               GCC_SYMBOLS_PRIVATE_EXTERN = NO;
-                               GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
-                               GCC_WARN_ABOUT_RETURN_TYPE = YES;
-                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
-                               GCC_WARN_UNUSED_VARIABLE = YES;
-                               INSTALL_PATH = /usr/lib;
-                               MACOSX_DEPLOYMENT_TARGET = 10.8;
-                               ONLY_ACTIVE_ARCH = NO;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               SDKROOT = macosx;
                        };
                        name = Release;
                };
-               B7325FF41DA47EBA00663834 /* Release */ = {
+               B718417421F8D0A600CA42AD /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               B7325FF41DA47EBA00663834 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                B7325FF51DA47EBA00663834 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                        };
                        name = Debug;
                };
+               B7473E731EC3954400D31B9D /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Menu/BonjourSafariMenu.entitlements";
+                               CODE_SIGN_IDENTITY = "-";
+                               COMBINE_HIDPI_IMAGES = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = "Bonjour Safari Menu/Info.plist";
+                               INSTALL_PATH = /AppleInternal/Applications;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx;
+                       };
+                       name = Release;
+               };
+               B7473E741EC3954400D31B9D /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Menu/BonjourSafariMenu.entitlements";
+                               CODE_SIGN_IDENTITY = "-";
+                               COMBINE_HIDPI_IMAGES = YES;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               ENABLE_TESTABILITY = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = "Bonjour Safari Menu/Info.plist";
+                               INSTALL_PATH = /AppleInternal/Applications;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx;
+                       };
+                       name = Debug;
+               };
+               B7473E931EC395C300D31B9D /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Extension/BonjourSafariExtension.entitlements";
+                               CODE_SIGN_IDENTITY = "-";
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = "Bonjour Safari Extension/Info.plist";
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu.BonjourSafariExtension;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx.internal;
+                               SKIP_INSTALL = YES;
+                       };
+                       name = Release;
+               };
+               B7473E941EC395C300D31B9D /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_ENTITLEMENTS = "Bonjour Safari Extension/BonjourSafariExtension.entitlements";
+                               CODE_SIGN_IDENTITY = "-";
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               ENABLE_TESTABILITY = YES;
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INFOPLIST_FILE = "Bonjour Safari Extension/Info.plist";
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @executable_path/../../../../Frameworks";
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.BonjourSafariMenu.BonjourSafariExtension;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx.internal;
+                               SKIP_INSTALL = YES;
+                       };
+                       name = Debug;
+               };
                B74EC11C1D47FC7800A1D155 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_MODULES = YES;
                B74EC11D1D47FC7800A1D155 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                CLANG_CXX_LIBRARY = "libc++";
                                CLANG_ENABLE_MODULES = YES;
                                        "DEBUG=1",
                                        "${inherited}",
                                );
-                               INFOPLIST_FILE = SettingsBundle/Info.plist;
-                               INSTALL_PATH = /AppleInternal/Library/PreferenceBundles;
-                               MTL_ENABLE_DEBUG_INFO = YES;
+                               INFOPLIST_FILE = SettingsBundle/Info.plist;
+                               INSTALL_PATH = /AppleInternal/Library/PreferenceBundles;
+                               MTL_ENABLE_DEBUG_INFO = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.network.bonjour.BonjourSettings;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = iphoneos.internal;
+                               SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
+                               TARGETED_DEVICE_FAMILY = "1,2";
+                       };
+                       name = Debug;
+               };
+               B74F16F12114E49D00BEBE84 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "UNIT_TEST=1",
+                                       "USE_XCTEST=1",
+                                       "MDNSRESPONDER_PLATFORM_APPLE=1",
+                                       "MDNSRESPONDER_SUPPORTS_APPLE_METRICS=0",
+                                       "MDNSRESPONDER_SUPPORTS_APPLE_DNS64=0",
+                                       "MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE=0",
+                                       "MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH=0",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               HEADER_SEARCH_PATHS = (
+                                       ../mDNSCore,
+                                       ../mDNSShared,
+                                       "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+                                       "$(SDKROOT)/usr/include/libxml2",
+                                       "${CONFIGURATION_TEMP_DIR}",
+                               );
+                               INFOPLIST_FILE = Tests/Info.plist;
+                               INSTALL_PATH = /AppleInternal/XCTests/com.apple.mDNSResponder/;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+                               MTL_FAST_MATH = YES;
+                               OTHER_CFLAGS = (
+                                       "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
+                                       "-DNO_SECURITYFRAMEWORK",
+                                       "-fwrapv",
+                                       "-flto=full",
+                               );
+                               OTHER_LDFLAGS = (
+                                       "-weak_framework",
+                                       WebFilterDNS,
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
+                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.Tests;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = iphoneos.internal;
+                               SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(inherited) $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+                               WARNING_CFLAGS = (
+                                       "-W",
+                                       "-Wall",
+                                       "-Wmissing-prototypes",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                                       "-Wshadow",
+                                       "-Wno-format",
+                                       "-Wformat-security",
+                               );
+                       };
+                       name = Release;
+               };
+               B74F16F22114E49D00BEBE84 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               COMBINE_HIDPI_IMAGES = YES;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               ENABLE_TESTABILITY = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "$(inherited)",
+                                       "UNIT_TEST=1",
+                                       "USE_XCTEST=1",
+                                       "MDNSRESPONDER_PLATFORM_APPLE=1",
+                                       "MDNSRESPONDER_SUPPORTS_APPLE_METRICS=0",
+                                       "MDNSRESPONDER_SUPPORTS_APPLE_DNS64=0",
+                                       "MDNSRESPONDER_SUPPORTS_APPLE_DNSSD_XPC_SERVICE=0",
+                                       "MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH=0",
+                               );
+                               GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               HEADER_SEARCH_PATHS = (
+                                       ../mDNSCore,
+                                       ../mDNSShared,
+                                       "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
+                                       "$(SDKROOT)/usr/include/libxml2",
+                                       "${CONFIGURATION_TEMP_DIR}",
+                               );
+                               INFOPLIST_FILE = Tests/Info.plist;
+                               INSTALL_PATH = /AppleInternal/XCTests/com.apple.mDNSResponder/;
+                               LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
+                               MTL_FAST_MATH = YES;
                                ONLY_ACTIVE_ARCH = YES;
-                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.network.bonjour.BonjourSettings;
+                               OTHER_CFLAGS = (
+                                       "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
+                                       "-DNO_SECURITYFRAMEWORK",
+                                       "-fwrapv",
+                               );
+                               OTHER_LDFLAGS = (
+                                       "-weak_framework",
+                                       WebFilterDNS,
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
+                               "OTHER_LDFLAGS[sdk=iphoneos*]" = (
+                                       "-weak_framework",
+                                       DeviceToDeviceManager,
+                               );
+                               PRODUCT_BUNDLE_IDENTIFIER = com.apple.bonjour.Tests;
                                PRODUCT_NAME = "$(TARGET_NAME)";
                                SDKROOT = iphoneos.internal;
-                               SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
-                               TARGETED_DEVICE_FAMILY = "1,2";
+                               SYSTEM_FRAMEWORK_SEARCH_PATHS = "$(inherited) $(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+                               WARNING_CFLAGS = (
+                                       "-W",
+                                       "-Wall",
+                                       "-Wmissing-prototypes",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                                       "-Wshadow",
+                                       "-Wno-format",
+                                       "-Wformat-security",
+                               );
                        };
                        name = Debug;
                };
                B76783B51E82D65900DA271E /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist";
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = com.apple.preference.bonjour.tool;
                                SDKROOT = macosx.internal;
                B76783B61E82D65900DA271E /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/BonjourPrefTool/BonjourPrefTool-Info.plist";
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                PRODUCT_NAME = com.apple.preference.bonjour.tool;
                        };
                        name = Debug;
                };
-               B7C4B7261E71BD5000136C7A /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Release;
-               };
-               B7C4B7271E71BD5000136C7A /* Debug */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               PRODUCT_NAME = "$(TARGET_NAME)";
-                       };
-                       name = Debug;
-               };
                B7D566C41E81D8FD00E43008 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist";
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_NAME = com.apple.preference.bonjour.remoteservice;
                                SKIP_INSTALL = YES;
                B7D566C51E81D8FD00E43008 /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNUSED_FUNCTION = YES;
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INFOPLIST_FILE = "$(SRCROOT)/PreferencePane/RemoteViewService/BonjourPrefRemoteViewService-Info.plist";
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                PRODUCT_NAME = com.apple.preference.bonjour.remoteservice;
                B7D6CA761D1076F3005E24CF /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                ASSETCATALOG_COMPRESSION = "respect-asset-catalog";
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INFOPLIST_FILE = ../mDNSUI/DomainBrowser/macOS/Info.plist;
                                INSTALL_PATH = "@rpath";
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = NO;
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.coreos.network.bonjour.DomainBrowser;
                                PRODUCT_NAME = DomainBrowser;
                B7D6CA771D1076F3005E24CF /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
                                ASSETCATALOG_COMPRESSION = lossless;
                                CLANG_ANALYZER_NONNULL = YES;
                                CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
                                GCC_WARN_UNUSED_VARIABLE = YES;
                                INFOPLIST_FILE = ../mDNSUI/DomainBrowser/macOS/Info.plist;
                                INSTALL_PATH = "@rpath";
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                MTL_ENABLE_DEBUG_INFO = YES;
                                ONLY_ACTIVE_ARCH = YES;
                                PRODUCT_BUNDLE_IDENTIFIER = com.apple.coreos.network.bonjour.DomainBrowser;
                        };
                        name = Debug;
                };
+               B7DB5896215EB4DD0054CD46 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CODE_SIGN_STYLE = Automatic;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
+               B7DB5897215EB4DD0054CD46 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CODE_SIGN_STYLE = Automatic;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
+               B7DB58A3215EB61C0054CD46 /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CODE_SIGN_STYLE = Automatic;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Release;
+               };
+               B7DB58A4215EB61C0054CD46 /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CODE_SIGN_STYLE = Automatic;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                       };
+                       name = Debug;
+               };
                BD9BA7511EAF90E400658CCF /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ANALYZER_GCD_PERFORMANCE = YES;
                                CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
                                CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
-                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = NO;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_ASSIGN_ENUM = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
-                               CODE_SIGN_ENTITLEMENTS = "dnssdutil-entitlements.plist";
+                               CODE_SIGN_ENTITLEMENTS = "../Clients/dnssdutil/dnssdutil-entitlements.plist";
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = (
                                        "$(inherited)",
                                        "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
                                );
-                               GCC_PREPROCESSOR_DEFINITIONS = "MDNSRESPONDER_PROJECT=1";
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "MDNSRESPONDER_PROJECT=1",
+                                       "DEBUG=0",
+                               );
                                GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES;
                                GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES;
                                GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
                                HEADER_SEARCH_PATHS = "$(SDKROOT)${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders";
                                INSTALL_PATH = /usr/local/bin;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               WARNING_CFLAGS = "-Wno-nullability-extension";
+                               WARNING_CFLAGS = (
+                                       "-Wall",
+                                       "-Warc-repeated-use-of-weak",
+                                       "-Wassign-enum",
+                                       "-Wconditional-uninitialized",
+                                       "-Wconversion",
+                                       "-Werror",
+                                       "-Werror-implicit-function-declaration",
+                                       "-Wextra",
+                                       "-Wfour-char-constants",
+                                       "-Wnullable-to-nonnull-conversion",
+                                       "-Wsign-compare",
+                                       "-Wsign-conversion",
+                                       "-Wundef",
+                                       "-Wuninitialized",
+                                       "-Wunreachable-code",
+                                       "-Wunused-parameter",
+                                       "-Wunused-parameter",
+                                       "-Wstrict-selector-match",
+                                       "-Wexplicit-ownership-type",
+                                       "-Wpedantic",
+                                       "-pedantic",
+                                       "-Wno-nullability-extension",
+                                       "-Wno-fixed-enum-extension",
+                               );
                        };
                        name = Release;
                };
                BD9BA7521EAF90E400658CCF /* Debug */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
-                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ANALYZER_GCD_PERFORMANCE = YES;
                                CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
                                CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
-                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = NO;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
                                CLANG_ENABLE_OBJC_ARC = YES;
                                CLANG_WARN_ASSIGN_ENUM = YES;
                                CLANG_WARN_BOOL_CONVERSION = YES;
                                CLANG_WARN_UNREACHABLE_CODE = YES_AGGRESSIVE;
                                CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
                                CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
-                               CODE_SIGN_ENTITLEMENTS = "dnssdutil-entitlements.plist";
+                               CODE_SIGN_ENTITLEMENTS = "../Clients/dnssdutil/dnssdutil-entitlements.plist";
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = (
                                        "$(inherited)",
                                HEADER_SEARCH_PATHS = "$(SDKROOT)${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders";
                                INSTALL_PATH = /usr/local/bin;
                                PRODUCT_NAME = "$(TARGET_NAME)";
-                               WARNING_CFLAGS = "-Wno-nullability-extension";
+                               WARNING_CFLAGS = (
+                                       "-Wall",
+                                       "-Warc-repeated-use-of-weak",
+                                       "-Wassign-enum",
+                                       "-Wconditional-uninitialized",
+                                       "-Wconversion",
+                                       "-Werror",
+                                       "-Werror-implicit-function-declaration",
+                                       "-Wextra",
+                                       "-Wfour-char-constants",
+                                       "-Wnullable-to-nonnull-conversion",
+                                       "-Wsign-compare",
+                                       "-Wsign-conversion",
+                                       "-Wundef",
+                                       "-Wuninitialized",
+                                       "-Wunreachable-code",
+                                       "-Wunused-parameter",
+                                       "-Wunused-parameter",
+                                       "-Wstrict-selector-match",
+                                       "-Wexplicit-ownership-type",
+                                       "-Wpedantic",
+                                       "-pedantic",
+                                       "-Wno-nullability-extension",
+                                       "-Wno-fixed-enum-extension",
+                               );
                        };
                        name = Debug;
                };
-               D284BE290ADD78180027CCDF /* Release */ = {
-                       isa = XCBuildConfiguration;
-                       buildSettings = {
-                               PRODUCT_NAME = "Build All";
-                       };
-                       name = Release;
-               };
                D284BE2C0ADD78180027CCDF /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               ALWAYS_SEARCH_USER_PATHS = NO;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
+                               CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
                                CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)/Release";
                                CONFIGURATION_TEMP_DIR = "$(PROJECT_TEMP_DIR)/Release";
                                COPY_PHASE_STRIP = NO;
                                        "mDNSResponderVersion=${MVERS}",
                                        _LEGACY_NAT_TRAVERSAL_,
                                        "_BUILDING_XCODE_PROJECT_=1",
-                                       "BONJOUR_ON_DEMAND=1",
                                        "USE_LIBIDN=1",
-                                       "USE_AWD=1",
                                );
                                GCC_TREAT_WARNINGS_AS_ERRORS = YES;
                                GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
                                OTHER_CFLAGS = (
                                        "-DUSE_SYSTEMCONFIGURATION_PRIVATE_HEADERS",
                                        "-fwrapv",
+                                       "-flto=full",
                                );
                                SDKROOT = macosx.internal;
                                STRIP_STYLE = debugging;
+                               SUPPORTED_PLATFORMS = "macosx iphoneos appletvos watchos";
                                WARNING_CFLAGS = (
                                        "-W",
                                        "-Wall",
                                "APPLY_RULES_IN_COPY_FILES[sdk=appletvos*]" = YES;
                                "APPLY_RULES_IN_COPY_FILES[sdk=iphoneos*]" = YES;
                                "APPLY_RULES_IN_COPY_FILES[sdk=watchos*]" = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
                                CODE_SIGN_ENTITLEMENTS = "mDNSResponder-entitlements.plist";
                                CODE_SIGN_IDENTITY = "-";
                                FRAMEWORK_SEARCH_PATHS = (
                                );
                                GCC_PREPROCESSOR_DEFINITIONS = (
                                        "$(inherited)",
-                                       "HAVE_DNS64=1",
+                                       "MDNSRESPONDER_PLATFORM_APPLE=1",
+                                       DSO_USES_NETWORK_FRAMEWORK,
                                );
-                               GCC_TREAT_WARNINGS_AS_ERRORS = NO;
                                HEADER_SEARCH_PATHS = (
-                                       "$(SDKROOT)/$(SYSTEM_LIBRARY_DIR)/Frameworks/Security.framework/PrivateHeaders",
                                        ../mDNSShared,
                                        "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
                                        "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
                                );
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                ORDER_FILE = "${SRCROOT}/mDNSResponder.order";
                                OTHER_LDFLAGS = "";
                                "OTHER_LDFLAGS[sdk=iphoneos*][arch=*]" = (
                                        "-weak_framework",
                                        DeviceToDeviceManager,
-                                       "-lMobileGestalt",
                                );
                                "OTHER_LDFLAGS[sdk=macosx*][arch=*]" = (
                                        "-weak_framework",
                                "PLIST_FILE_OUTPUT_FORMAT[sdk=watchos*]" = binary;
                                PRODUCT_NAME = mDNSResponder;
                                PROVISIONING_PROFILE = "";
+                               WARNING_CFLAGS = (
+                                       "-W",
+                                       "-Wall",
+                                       "-Wmissing-prototypes",
+                                       "-Wno-four-char-constants",
+                                       "-Wno-unknown-pragmas",
+                                       "-Wshadow",
+                                       "-Wno-format",
+                                       "-Wformat-security",
+                               );
                        };
                        name = Release;
                };
                D284BEAE0ADD80920027CCDF /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
+                               CODE_SIGN_ENTITLEMENTS = "command_line_client_entitlements/dns-sd-entitlements.plist";
+                               CODE_SIGN_IDENTITY = "-";
                                HEADER_SEARCH_PATHS = (
                                        ../mDNSShared,
                                        "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                HEADER_SEARCH_PATHS = (
+                                       "$(SRCROOT)/../mDNSShared",
                                        "${SYSTEM_LIBRARY_DIR}/Frameworks/System.framework/PrivateHeaders",
                                        "${APPLE_INTERNAL_DEVELOPER_DIR}/Headers",
                                        "${CONFIGURATION_TEMP_DIR}",
                                );
                                INSTALL_PATH = /usr/sbin;
                                LIBRARY_SEARCH_PATHS = "\"${CONFIGURATION_TEMP_DIR}\"";
-                               MACOSX_DEPLOYMENT_TARGET = 10.10;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                OTHER_CFLAGS = "-UAPPLE_OSX_mDNSResponder";
                                PRODUCT_NAME = dnsextd;
                        };
                                GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = NO;
                                INFOPLIST_FILE = "PreferencePane/Info-PreferencePane.plist";
                                INSTALL_PATH = /AppleInternal/Library/PreferencePanes;
-                               MACOSX_DEPLOYMENT_TARGET = 10.9;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
                                PRODUCT_NAME = Bonjour;
                                SUPPORTED_PLATFORMS = macosx;
                                WRAPPER_EXTENSION = prefPane;
                        };
                        name = Release;
                };
+               D4CFA7CD21E7B95E00F5AD0E /* Release */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_STRICT_PROTOTYPES = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_IDENTITY = "-";
+                               CODE_SIGN_STYLE = Automatic;
+                               DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               ENABLE_NS_ASSERTIONS = NO;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               EXECUTABLE_PREFIX = "";
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INSTALL_PATH = /usr/lib/log;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = NO;
+                               MTL_FAST_MATH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx.internal;
+                               SKIP_INSTALL = NO;
+                       };
+                       name = Release;
+               };
+               D4CFA7CE21E7B95E00F5AD0E /* Debug */ = {
+                       isa = XCBuildConfiguration;
+                       buildSettings = {
+                               CLANG_ANALYZER_NONNULL = YES;
+                               CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+                               CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+                               CLANG_CXX_LIBRARY = "libc++";
+                               CLANG_ENABLE_MODULES = YES;
+                               CLANG_ENABLE_OBJC_ARC = YES;
+                               CLANG_ENABLE_OBJC_WEAK = YES;
+                               CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+                               CLANG_WARN_BOOL_CONVERSION = YES;
+                               CLANG_WARN_COMMA = YES;
+                               CLANG_WARN_CONSTANT_CONVERSION = YES;
+                               CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+                               CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+                               CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+                               CLANG_WARN_EMPTY_BODY = YES;
+                               CLANG_WARN_ENUM_CONVERSION = YES;
+                               CLANG_WARN_INFINITE_RECURSION = YES;
+                               CLANG_WARN_INT_CONVERSION = YES;
+                               CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+                               CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+                               CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+                               CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+                               CLANG_WARN_STRICT_PROTOTYPES = YES;
+                               CLANG_WARN_SUSPICIOUS_MOVE = YES;
+                               CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+                               CLANG_WARN_UNREACHABLE_CODE = YES;
+                               CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+                               CODE_SIGN_IDENTITY = "-";
+                               CODE_SIGN_STYLE = Automatic;
+                               DEBUG_INFORMATION_FORMAT = dwarf;
+                               DYLIB_COMPATIBILITY_VERSION = 1;
+                               DYLIB_CURRENT_VERSION = 1;
+                               ENABLE_STRICT_OBJC_MSGSEND = YES;
+                               ENABLE_TESTABILITY = YES;
+                               EXECUTABLE_PREFIX = "";
+                               GCC_C_LANGUAGE_STANDARD = gnu11;
+                               GCC_DYNAMIC_NO_PIC = NO;
+                               GCC_NO_COMMON_BLOCKS = YES;
+                               GCC_PREPROCESSOR_DEFINITIONS = (
+                                       "DEBUG=1",
+                                       "$(inherited)",
+                               );
+                               GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+                               GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+                               GCC_WARN_UNDECLARED_SELECTOR = YES;
+                               GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+                               GCC_WARN_UNUSED_FUNCTION = YES;
+                               GCC_WARN_UNUSED_VARIABLE = YES;
+                               INSTALL_PATH = /usr/lib/log;
+                               MACOSX_DEPLOYMENT_TARGET = 10.14;
+                               MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+                               MTL_FAST_MATH = YES;
+                               ONLY_ACTIVE_ARCH = YES;
+                               PRODUCT_NAME = "$(TARGET_NAME)";
+                               SDKROOT = macosx.internal;
+                               SKIP_INSTALL = NO;
+                       };
+                       name = Debug;
+               };
                FFA572380AF18F1C0055A0F1 /* Release */ = {
                        isa = XCBuildConfiguration;
                        buildSettings = {
                                        "-lsystem_c",
                                        "-lsystem_blocks",
                                        "-ldispatch",
-                                       "-llaunch",
                                        "-lsystem_asl",
                                );
-                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
                                PRODUCT_NAME = libsystem_dnssd_debug;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
                                SUPPORTS_TEXT_BASED_API = YES;
                                        "-lsystem_c",
                                        "-lsystem_blocks",
                                        "-ldispatch",
-                                       "-llaunch",
                                        "-lsystem_asl",
                                );
-                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
+                               OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/../mDNSShared/dns_sd.h -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h -extra-private-header $(SRCROOT)/../mDNSShared/dns_sd_private.h";
                                PRODUCT_NAME = libsystem_dnssd_profile;
                                PUBLIC_HEADERS_FOLDER_PATH = /usr/include;
                                SUPPORTS_TEXT_BASED_API = YES;
                                INSTALL_PATH = /usr/lib/system;
                                INTERPOSITION_SIM_SUFFIX = "";
                                "INTERPOSITION_SIM_SUFFIX[sdk=iphonesimulator*]" = _sim;
-                               IS_ZIPPERED = YES;
+                               "IS_ZIPPERED[sdk=macosx*]" = YES;
                                LINK_WITH_STANDARD_LIBRARIES = NO;
                                OTHER_LDFLAGS = (
                                        "-Wl,-umbrella,System",
                                        "-lsystem_c",
                                        "-lsystem_blocks",
                                        "-ldispatch",
-                                       "-llaunch",
                                        "-lsystem_asl",
                                );
                                OTHER_TAPI_FLAGS = "-umbrella System -extra-public-header $(SRCROOT)/DNSServiceDiscovery.h";
 /* End XCBuildConfiguration section */
 
 /* Begin XCConfigurationList section */
-               03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Some" */ = {
+               03067D730C83A3CB0022BE1F /* Build configuration list for PBXAggregateTarget "Build Core" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                03067D740C83A3CB0022BE1F /* Release */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               37DDE9311BA383610092AC61 /* Build configuration list for PBXNativeTarget "unittests" */ = {
+               4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               37AF80281BF6997A00D657F6 /* Release */,
-                               37AF80291BF6997A00D657F6 /* Debug */,
+                               0C419F291BA20DF600A70FF7 /* Debug */,
+                               37AF80271BF6997A00D657F6 /* Release */,
                        );
                        defaultConfigurationIsVisible = 0;
-                       defaultConfigurationName = Development;
+                       defaultConfigurationName = Release;
                };
-               4AE471770EAFF84000A6C5AD /* Build configuration list for PBXLegacyTarget "dns_sd.jar" */ = {
+               84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               0C419F291BA20DF600A70FF7 /* Debug */,
-                               37AF80271BF6997A00D657F6 /* Release */,
+                               84C5B3371665529800C324A8 /* Release */,
+                               0C419F271BA20DF600A70FF7 /* Debug */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               72FB5465166D5FB00090B2D9 /* Build configuration list for PBXNativeTarget "dnsctl" */ = {
+               B70F38B0217AA6CE00612D3A /* Build configuration list for PBXAggregateTarget "Build Extras" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               72FB5466166D5FB00090B2D9 /* Release */,
-                               0C419F191BA20DF600A70FF7 /* Debug */,
+                               B70F38B1217AA6CE00612D3A /* Release */,
+                               B70F38B2217AA6CE00612D3A /* Debug */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               84C5B3361665529800C324A8 /* Build configuration list for PBXNativeTarget "dns_services" */ = {
+               B718417221F8D0A600CA42AD /* Build configuration list for PBXAggregateTarget "Build Services" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               84C5B3371665529800C324A8 /* Release */,
-                               0C419F271BA20DF600A70FF7 /* Debug */,
+                               B718417321F8D0A600CA42AD /* Release */,
+                               B718417421F8D0A600CA42AD /* Debug */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
+               B7473E751EC3954400D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Menu" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               B7473E731EC3954400D31B9D /* Release */,
+                               B7473E741EC3954400D31B9D /* Debug */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               B7473E921EC395C300D31B9D /* Build configuration list for PBXNativeTarget "Bonjour Safari Extension" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               B7473E931EC395C300D31B9D /* Release */,
+                               B7473E941EC395C300D31B9D /* Debug */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
                B74EC11E1D47FC7800A1D155 /* Build configuration list for PBXNativeTarget "BonjourSettings" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */ = {
+               B74F16F02114E49D00BEBE84 /* Build configuration list for PBXNativeTarget "Tests" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               B76783B51E82D65900DA271E /* Release */,
-                               B76783B61E82D65900DA271E /* Debug */,
+                               B74F16F12114E49D00BEBE84 /* Release */,
+                               B74F16F22114E49D00BEBE84 /* Debug */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               B7C4B7281E71BD5000136C7A /* Build configuration list for PBXAggregateTarget "Build Some iOS" */ = {
+               B76783B71E82D65900DA271E /* Build configuration list for PBXNativeTarget "BonjourPrefsTool" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               B7C4B7261E71BD5000136C7A /* Release */,
-                               B7C4B7271E71BD5000136C7A /* Debug */,
+                               B76783B51E82D65900DA271E /* Release */,
+                               B76783B61E82D65900DA271E /* Debug */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               BD9BA7501EAF90E400658CCF /* Build configuration list for PBXNativeTarget "dnssdutil" */ = {
+               B7DB5898215EB4DD0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-iOS" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               BD9BA7511EAF90E400658CCF /* Release */,
-                               BD9BA7521EAF90E400658CCF /* Debug */,
+                               B7DB5896215EB4DD0054CD46 /* Release */,
+                               B7DB5897215EB4DD0054CD46 /* Debug */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               B7DB58A2215EB61C0054CD46 /* Build configuration list for PBXAggregateTarget "Build Extras-macOS" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               B7DB58A3215EB61C0054CD46 /* Release */,
+                               B7DB58A4215EB61C0054CD46 /* Debug */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               D284BE280ADD78180027CCDF /* Build configuration list for PBXAggregateTarget "Build More" */ = {
+               BD9BA7501EAF90E400658CCF /* Build configuration list for PBXNativeTarget "dnssdutil" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
-                               D284BE290ADD78180027CCDF /* Release */,
-                               0C419F131BA20DF600A70FF7 /* Debug */,
+                               BD9BA7511EAF90E400658CCF /* Release */,
+                               BD9BA7521EAF90E400658CCF /* Debug */,
                        );
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_debug_dynamic" */ = {
+               D4CFA7CF21E7B95E00F5AD0E /* Build configuration list for PBXNativeTarget "liblog_mdnsresponder" */ = {
+                       isa = XCConfigurationList;
+                       buildConfigurations = (
+                               D4CFA7CD21E7B95E00F5AD0E /* Release */,
+                               D4CFA7CE21E7B95E00F5AD0E /* Debug */,
+                       );
+                       defaultConfigurationIsVisible = 0;
+                       defaultConfigurationName = Release;
+               };
+               FFA572370AF18F1C0055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_debug" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                FFA572380AF18F1C0055A0F1 /* Release */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libdns_sd_profile_dynamic" */ = {
+               FFA572430AF18F450055A0F1 /* Build configuration list for PBXNativeTarget "libsystem_dnssd_profile" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                FFA572440AF18F450055A0F1 /* Release */,
                        defaultConfigurationIsVisible = 0;
                        defaultConfigurationName = Release;
                };
-               FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libdns_sd_dynamic" */ = {
+               FFB765890AEED9FB00583A2C /* Build configuration list for PBXNativeTarget "libsystem_dnssd" */ = {
                        isa = XCConfigurationList;
                        buildConfigurations = (
                                FFB7658A0AEED9FB00583A2C /* Release */,
index 7ba2fe0680fdc86d7b734390c4e4e5d1c38e61e7..16b8d0a4dd08af26c85ace66660932990cb82152 100644 (file)
       buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
+      codeCoverageEnabled = "YES"
       shouldUseLaunchSchemeArgsEnv = "YES">
       <Testables>
+         <TestableReference
+            skipped = "NO">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "B74F16EA2114E49C00BEBE84"
+               BuildableName = "Tests.xctest"
+               BlueprintName = "Tests"
+               ReferencedContainer = "container:mDNSResponder.xcodeproj">
+            </BuildableReference>
+         </TestableReference>
       </Testables>
       <MacroExpansion>
          <BuildableReference
diff --git a/mDNSMacOSX/mdns.c b/mDNSMacOSX/mdns.c
new file mode 100644 (file)
index 0000000..504b8d9
--- /dev/null
@@ -0,0 +1,807 @@
+/*
+ * Copyright (c) 2019 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
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mdns_private.h"
+
+#include "mdns_object.h"
+
+#include <CoreUtils/CoreUtils.h>
+#include <network_information.h>
+#include <notify.h>
+#include <os/log.h>
+#include <os/object_private.h>
+
+//======================================================================================================================
+// MARK: - Kind Declarations
+
+#define MDNS_STRUCT(NAME)      struct mdns_ ## NAME ## _s
+
+// Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
+// comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
+// the warning hasn't been disabled.
+
+#define MDNS_BASE_CHECK(NAME, SUPER)                                                                                                                   \
+       check_compile_time(offsetof(MDNS_STRUCT(NAME), base) == 0);                                                                     \
+       check_compile_time(sizeof_field(MDNS_STRUCT(NAME), base) == sizeof(MDNS_STRUCT(SUPER)));        \
+       extern int _mdns_base_type_check[sizeof(&(((mdns_ ## NAME ## _t)0)->base) == ((mdns_ ## SUPER ## _t)0))]
+
+#define MDNS_OBJECT_SUBKIND_DEFINE(NAME)                                                                                                               \
+       static void                                                                                                                                                                     \
+       _mdns_ ## NAME ## _finalize(mdns_ ## NAME ## _t object);                                                                        \
+                                                                                                                                                                                               \
+       static char *                                                                                                                                                           \
+       _mdns_ ## NAME ## _copy_description(mdns_ ## NAME ## _t object, bool debug, bool privacy);      \
+                                                                                                                                                                                               \
+       static const struct mdns_kind_s _mdns_ ## NAME ## _kind = {                                                                     \
+               &_mdns_object_kind,                                                                                                                                             \
+               # NAME,                                                                                                                                                                 \
+               _mdns_ ## NAME ## _copy_description,                                                                                                    \
+               _mdns_ ## NAME ## _finalize                                                                                                                             \
+       };                                                                                                                                                                                      \
+                                                                                                                                                                                               \
+       static mdns_ ## NAME ## _t                                                                                                                                      \
+       _mdns_ ## NAME ## _alloc(void)                                                                                                                          \
+       {                                                                                                                                                                                       \
+               mdns_ ## NAME ## _t obj = mdns_object_ ## NAME ## _alloc(sizeof(*obj));                                 \
+               require_quiet(obj, exit);                                                                                                                               \
+                                                                                                                                                                                               \
+               const mdns_object_t base = (mdns_object_t)obj;                                                                                  \
+               base->kind = &_mdns_ ## NAME ## _kind;                                                                                                  \
+                                                                                                                                                                                               \
+       exit:                                                                                                                                                                           \
+               return obj;                                                                                                                                                             \
+       }                                                                                                                                                                                       \
+       MDNS_BASE_CHECK(NAME, object)
+
+typedef char * (*mdns_copy_description_f)(mdns_any_t object, bool debug, bool privacy);
+typedef void   (*mdns_finalize_f)(mdns_any_t object);
+
+typedef const struct mdns_kind_s *     mdns_kind_t;
+struct mdns_kind_s {
+       mdns_kind_t                             superkind;                      // This kind's superkind.
+       const char *                    name;                           // Name of this kind.
+       mdns_copy_description_f copy_description;       // Creates a textual description of object.
+       mdns_finalize_f                 finalize;                       // Releases object's resources right before the object is freed.
+};
+
+//======================================================================================================================
+// MARK: - mdns_object Kind Definition
+
+struct mdns_object_s {
+       _OS_OBJECT_HEADER(const void *_os_obj_isa, _os_obj_refcnt, _os_obj_xref_cnt);
+       mdns_kind_t     kind;   // Pointer to an object's kind.
+};
+
+static const struct mdns_kind_s _mdns_object_kind = {
+       NULL,           // No superkind.
+       "object",       // Name.
+       NULL,           // No copy_description method.
+       NULL            // No finalize method.
+};
+
+static const void *
+_mdns_cf_collection_callback_retain(CFAllocatorRef allocator, const void *object);
+
+static void
+_mdns_cf_collection_callback_release(CFAllocatorRef allocator, const void *object);
+
+static CFStringRef
+_mdns_cf_collection_callback_copy_description(const void *object);
+
+const CFArrayCallBacks mdns_cfarray_callbacks = {
+       0,                                                                                              // version
+       _mdns_cf_collection_callback_retain,                    // retain
+       _mdns_cf_collection_callback_release,                   // release
+       _mdns_cf_collection_callback_copy_description,  // copy description
+       NULL                                                                                    // equal (NULL for pointer equality)
+};
+
+//======================================================================================================================
+// MARK: - mdns_interface_monitor Kind Definition
+
+struct mdns_interface_monitor_s {
+       struct mdns_object_s                                    base;                                   // Object base.
+       mdns_interface_monitor_t                                next;                                   // Next monitor in list.
+       dispatch_queue_t                                                user_queue;                             // User's queue for invoking handlers.
+       nw_path_evaluator_t                                             path_evaluator;                 // Path evaluator for interface properties.
+       dispatch_source_t                                               update_source;                  // Data source for triggering user's update handler.
+       mdns_interface_monitor_update_handler_t update_handler;                 // User's update handler.
+       mdns_event_handler_t                                    event_handler;                  // User's event handler.
+       char *                                                                  ifname;                                 // Name of monitored interface.
+       uint32_t                                                                ifindex;                                // Index of monitored interface.
+       mdns_interface_flags_t                                  pending_flags;                  // The latest interface flags from path updates.
+       mdns_interface_flags_t                                  flags;                                  // The current interface flags made known to user.
+       bool                                                                    user_activated;                 // True if user called activate method.
+       bool                                                                    activated;                              // True if the monitor has been activated.
+       bool                                                                    invalidated;                    // True if the monitor has been invalidated.
+       bool                                                                    path_evaluator_started; // True if the path evaluator has been started.
+};
+
+MDNS_OBJECT_SUBKIND_DEFINE(interface_monitor);
+
+//======================================================================================================================
+// MARK: - Local Prototypes
+
+static dispatch_queue_t
+_mdns_internal_queue(void);
+
+static dispatch_queue_t
+_mdns_nwi_state_mutex_queue(void);
+
+static void
+_mdns_interface_monitor_activate_async(mdns_interface_monitor_t monitor);
+
+static void
+_mdns_interface_monitor_terminate(mdns_interface_monitor_t me, const OSStatus error);
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nw_path(nw_path_t path, mdns_interface_flags_t current_flags);
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nwi_state(const char *ifname, mdns_interface_flags_t current_flags);
+
+static int
+_mdns_snprintf_add(char **ptr, const char *lim, const char *fmt, ...);
+
+static void
+_mdns_start_nwi_state_monitoring(void);
+
+#if !defined(nw_forget)
+       #define nw_forget(X)    ForgetCustom(X, nw_release)
+#endif
+
+#if !defined(nw_release_null_safe)
+       #define nw_release_null_safe(X) do { if (X) { nw_release(X); } } while (0)
+#endif
+
+#if !defined(nwi_state_release_null_safe)
+       #define nwi_state_release_null_safe(X)  do { if (X) { nwi_state_release(X); } } while (0)
+#endif
+
+//======================================================================================================================
+// MARK: - Globals
+
+static mdns_interface_monitor_t        g_monitor_list  = NULL;
+static nwi_state_t                             g_nwi_state             = NULL;
+
+//======================================================================================================================
+// MARK: - Internals
+
+static dispatch_queue_t
+_mdns_internal_queue(void)
+{
+       static dispatch_once_t  s_once  = 0;
+       static dispatch_queue_t s_queue = NULL;
+       dispatch_once(&s_once,
+       ^{
+               s_queue = dispatch_queue_create("com.apple.mdns.internal_queue", DISPATCH_QUEUE_SERIAL);
+       });
+       return s_queue; 
+}
+
+//======================================================================================================================
+
+static dispatch_queue_t
+_mdns_nwi_state_mutex_queue(void)
+{
+       static dispatch_once_t  s_once  = 0;
+       static dispatch_queue_t s_queue = NULL;
+       dispatch_once(&s_once,
+       ^{
+               s_queue = dispatch_queue_create("com.apple.mdns.nwi_state_mutex", DISPATCH_QUEUE_SERIAL);
+       });
+       return s_queue;
+}
+
+//======================================================================================================================
+
+#define MDNS_LOG_CATEGORY_DEFINE(SHORT_NAME, CATEGORY_STR)                     \
+       static os_log_t                                                                                                 \
+       _mdns_ ## SHORT_NAME ## _log(void)                                                              \
+       {                                                                                                                               \
+               static dispatch_once_t  s_once  = 0;                                            \
+               static os_log_t                 s_log   = NULL;                                         \
+               dispatch_once(&s_once,                                                                          \
+               ^{                                                                                                                      \
+                       s_log = os_log_create("com.apple.mdns", CATEGORY_STR);  \
+               });                                                                                                                     \
+               return s_log;                                                                                           \
+       }                                                                                                                               \
+       extern int _mdns_dummy_variable
+
+MDNS_LOG_CATEGORY_DEFINE(ifmon, "interface_monitor");
+MDNS_LOG_CATEGORY_DEFINE(nwi,   "NWI");
+
+//======================================================================================================================
+// MARK: - mdns_object Public Methods
+
+void
+mdns_retain(mdns_any_t object)
+{
+       os_retain(object.base);
+}
+
+//======================================================================================================================
+
+void
+mdns_release(mdns_any_t object)
+{
+       os_release(object.base);
+}
+
+//======================================================================================================================
+
+char *
+mdns_copy_description(mdns_any_t object)
+{
+       return mdns_object_copy_description(object, false, false);
+}
+
+//======================================================================================================================
+// MARK: - mdns_object Private Methods
+
+char *
+mdns_object_copy_description(mdns_any_t object, bool debug, bool privacy)
+{
+       for (mdns_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+               if (kind->copy_description) {
+                       return kind->copy_description(object, debug, privacy);
+               }
+       }
+       return NULL;
+}
+
+//======================================================================================================================
+
+CFStringRef
+mdns_object_copy_description_as_cfstring(mdns_any_t object, bool debug, bool privacy)
+{
+       CFStringRef description = NULL;
+       char *cstring = mdns_object_copy_description(object, debug, privacy);
+       require_quiet(cstring, exit);
+
+       description = CFStringCreateWithCStringNoCopy(NULL, cstring, kCFStringEncodingUTF8, kCFAllocatorMalloc);
+       require_quiet(description, exit);
+       cstring = NULL;
+
+exit:
+       FreeNullSafe(cstring);
+       return description;
+}
+
+//======================================================================================================================
+
+void
+mdns_object_finalize(mdns_any_t object)
+{
+       for (mdns_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
+               if (kind->finalize) {
+                       kind->finalize(object);
+               }
+       }
+}
+
+//======================================================================================================================
+
+static const void *
+_mdns_cf_collection_callback_retain(__unused CFAllocatorRef allocator, const void *object)
+{
+       mdns_retain((mdns_object_t)object);
+       return object;
+}
+
+//======================================================================================================================
+
+static void
+_mdns_cf_collection_callback_release(__unused CFAllocatorRef allocator, const void *object)
+{
+       mdns_release((mdns_object_t)object);
+}
+
+//======================================================================================================================
+
+static CFStringRef
+_mdns_cf_collection_callback_copy_description(const void *object)
+{
+       return mdns_object_copy_description_as_cfstring((mdns_object_t)object, false, false);
+}
+
+//======================================================================================================================
+// MARK: - mdns_interface_monitor Public Methods
+
+mdns_interface_monitor_t
+mdns_interface_monitor_create(uint32_t interface_index)
+{
+       mdns_interface_monitor_t        monitor         = NULL;
+       nw_interface_t                          interface       = NULL;
+       nw_parameters_t                         params          = NULL;
+
+       mdns_interface_monitor_t obj = _mdns_interface_monitor_alloc();
+       require_quiet(obj, exit);
+
+       obj->ifindex = interface_index;
+       char ifname[IF_NAMESIZE + 1];
+       if (if_indextoname(obj->ifindex, ifname) == NULL) {
+               os_log_error(_mdns_ifmon_log(), "if_indextoname returned NULL for index %u", obj->ifindex);
+               goto exit;
+       }
+       obj->ifname = strdup(ifname);
+       require_quiet(obj->ifname, exit);
+
+       interface = nw_interface_create_with_index(obj->ifindex);
+       if (!interface) {
+               os_log_error(_mdns_ifmon_log(), "nw_interface_create_with_index returned NULL for index %u", obj->ifindex);
+               goto exit;
+       }
+
+       params = nw_parameters_create();
+       require_quiet(params, exit);
+
+       nw_parameters_require_interface(params, interface);
+       obj->path_evaluator = nw_path_create_evaluator_for_endpoint(NULL, params);
+       if (!obj->path_evaluator) {
+               os_log_error(_mdns_ifmon_log(), "nw_path_create_evaluator_for_endpoint returned NULL for params: %@", params);
+               goto exit;
+       }
+
+       nw_path_t path = nw_path_evaluator_copy_path(obj->path_evaluator);
+       require_quiet(path, exit);
+
+       obj->pending_flags = _mdns_get_interface_flags_from_nw_path(path, mdns_interface_flag_null);
+       obj->pending_flags = _mdns_get_interface_flags_from_nwi_state(obj->ifname, obj->pending_flags);
+       obj->flags = obj->pending_flags;
+       nw_forget(&path);
+
+       monitor = obj;
+       obj = NULL;
+
+exit:
+       if (obj) {
+               mdns_release(obj);
+       }
+       nw_release_null_safe(interface);
+       nw_release_null_safe(params);
+       return monitor;
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_activate(mdns_interface_monitor_t me)
+{
+       if (!me->user_activated) {
+               if (me->user_queue) {
+                       _mdns_interface_monitor_activate_async(me);
+               }
+               me->user_activated = true;
+       }
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_invalidate(mdns_interface_monitor_t me)
+{
+       mdns_retain(me);
+       dispatch_async(_mdns_internal_queue(),
+       ^{
+               if (!me->invalidated) {
+                       _mdns_interface_monitor_terminate(me, kNoErr);
+                       me->invalidated = true;
+               }
+               mdns_release(me);
+       });
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_set_queue(mdns_interface_monitor_t me, dispatch_queue_t queue)
+{
+       if (!me->user_activated) {
+               dispatch_retain(queue);
+               dispatch_release_null_safe(me->user_queue);
+               me->user_queue = queue;
+       } else if (!me->user_queue) {
+               me->user_queue = queue;
+               dispatch_retain(me->user_queue);
+               _mdns_interface_monitor_activate_async(me);
+       }
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_set_event_handler(mdns_interface_monitor_t me, mdns_event_handler_t handler)
+{
+       mdns_event_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+       if (me->event_handler) {
+               Block_release(me->event_handler);
+       }
+       me->event_handler = new_handler;
+}
+
+//======================================================================================================================
+
+void
+mdns_interface_monitor_set_update_handler(mdns_interface_monitor_t me, mdns_interface_monitor_update_handler_t handler)
+{
+       mdns_interface_monitor_update_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
+       if (me->update_handler) {
+               Block_release(me->update_handler);
+       }
+       me->update_handler = new_handler;
+}
+
+//======================================================================================================================
+
+uint32_t
+mdns_interface_monitor_get_interface_index(mdns_interface_monitor_t me)
+{
+       return me->ifindex;
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_has_ipv4_connectivity(mdns_interface_monitor_t me)
+{
+       return ((me->flags & mdns_interface_flag_ipv4_connectivity) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_has_ipv6_connectivity(mdns_interface_monitor_t me)
+{
+       return ((me->flags & mdns_interface_flag_ipv6_connectivity) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_is_expensive(mdns_interface_monitor_t me)
+{
+       return ((me->flags & mdns_interface_flag_expensive) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_is_constrained(mdns_interface_monitor_t me)
+{
+       return ((me->flags & mdns_interface_flag_constrained) ? true : false);
+}
+
+//======================================================================================================================
+
+bool
+mdns_interface_monitor_is_clat46(mdns_interface_monitor_t me)
+{
+       return ((me->flags & mdns_interface_flag_clat46) ? true : false);
+}
+
+//======================================================================================================================
+// MARK: - mdns_interface_monitor Private Methods
+
+typedef struct {
+       mdns_interface_flags_t  flag;
+       const char *                    desc;
+} mdns_interface_flag_description_t;
+
+const mdns_interface_flag_description_t        mdns_interface_flag_descriptions[] = {
+       { mdns_interface_flag_ipv4_connectivity, "IPv4" },
+       { mdns_interface_flag_ipv6_connectivity, "IPv6" },
+       { mdns_interface_flag_expensive,         "expensive" },
+       { mdns_interface_flag_constrained,       "constrained" },
+       { mdns_interface_flag_clat46,            "CLAT46" }
+};
+
+static char *
+_mdns_interface_monitor_copy_description(mdns_interface_monitor_t me, const bool debug, __unused const bool privacy)
+{
+       char *                          description     = NULL;
+       char                            buffer[128];
+       char *                          dst                     = buffer;
+       const char * const      lim                     = &buffer[countof(buffer)];
+       int                                     n;
+
+       *dst = '\0';
+       if (debug) {
+               n = _mdns_snprintf_add(&dst, lim, "mdns_%s (%p): ", me->base.kind->name, me);
+               require_quiet(n >= 0, exit);
+       }
+       n = _mdns_snprintf_add(&dst, lim, "interface %s (%u): ", me->ifname, me->ifindex);
+       require_quiet(n >= 0, exit);
+
+       const char *separator = "";
+       for (size_t i = 0; i < countof(mdns_interface_flag_descriptions); ++i) {
+               const mdns_interface_flag_description_t * const flag_desc = &mdns_interface_flag_descriptions[i];
+               if (me->flags & flag_desc->flag) {
+                       n = _mdns_snprintf_add(&dst, lim, "%s%s", separator, flag_desc->desc);
+                       require_quiet(n >= 0, exit);
+                       separator = ", ";
+               }
+       }
+       description = strdup(buffer);
+
+exit:
+       return description;
+}
+
+//======================================================================================================================
+
+static void
+_mdns_interface_monitor_finalize(mdns_interface_monitor_t me)
+{
+       dispatch_forget(&me->user_queue);
+       nw_forget(&me->path_evaluator);
+       BlockForget(&me->update_handler);
+       BlockForget(&me->event_handler);
+       ForgetMem(&me->ifname);
+}
+
+//======================================================================================================================
+
+static void
+_mdns_interface_monitor_activate_internal(mdns_interface_monitor_t monitor);
+
+static void
+_mdns_interface_monitor_activate_async(mdns_interface_monitor_t me)
+{
+       mdns_retain(me);
+       dispatch_async(_mdns_internal_queue(),
+       ^{
+               _mdns_interface_monitor_activate_internal(me);
+               mdns_release(me);               
+       });
+}
+
+static void
+_mdns_interface_monitor_activate_internal(mdns_interface_monitor_t me)
+{
+       OSStatus err;
+       require_action_quiet(!me->activated && !me->invalidated, exit, err = kNoErr);
+       me->activated = true;
+
+       me->update_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_REPLACE, 0, 0, me->user_queue);
+       require_action_quiet(me->update_source, exit, err = kNoResourcesErr);
+
+       mdns_retain(me);
+       const dispatch_source_t update_source = me->update_source;
+       dispatch_source_set_event_handler(me->update_source,
+       ^{
+               const unsigned long data = dispatch_source_get_data(update_source);
+               const mdns_interface_flags_t new_flags = ((mdns_interface_flags_t)data) & ~mdns_interface_flag_reserved;
+               const mdns_interface_flags_t changed_flags = me->flags ^ new_flags;
+               if (changed_flags != 0) {
+                       me->flags = new_flags;
+                       if (me->update_handler) {
+                               me->update_handler(changed_flags);
+                       }
+               }
+       });
+       dispatch_source_set_cancel_handler(me->update_source,
+       ^{
+               mdns_release(me);
+       });
+       dispatch_activate(me->update_source);
+
+       mdns_retain(me);
+       nw_path_evaluator_set_update_handler(me->path_evaluator, _mdns_internal_queue(),
+       ^(nw_path_t path)
+       {
+               const mdns_interface_flags_t new_flags = _mdns_get_interface_flags_from_nw_path(path, me->pending_flags);
+               if (new_flags != me->pending_flags) {
+                       me->pending_flags = new_flags;
+                       if (me->update_source) {
+                               // Note: mdns_interface_flag_reserved is used to ensure that the data is non-zero. According to the
+                               // dispatch_source_create(3) man page, if the data value is zero, the source handler won't be invoked.
+                               dispatch_source_merge_data(me->update_source, me->pending_flags | mdns_interface_flag_reserved);
+                       }
+               }
+       });
+       nw_path_evaluator_set_cancel_handler(me->path_evaluator,
+       ^{
+               mdns_release(me);
+       });
+       nw_path_evaluator_start(me->path_evaluator);
+       me->path_evaluator_started = true;
+
+       mdns_interface_monitor_t *p = &g_monitor_list;
+       while (*p != NULL) {
+               p = &(*p)->next;
+       }
+       mdns_retain(me);
+       *p = me;
+
+       // This is called after adding the monitor to the global list to ensure that the initial NWI state check is aware
+       // that the interface monitor exists.
+       _mdns_start_nwi_state_monitoring();
+       err = kNoErr;
+
+exit:
+       if (err) {
+               _mdns_interface_monitor_terminate(me, err);
+       }
+}
+
+//======================================================================================================================
+
+static void
+_mdns_interface_monitor_terminate(mdns_interface_monitor_t me, const OSStatus error)
+{
+       dispatch_source_forget(&me->update_source);
+       if (me->path_evaluator) {
+               if (me->path_evaluator_started) {
+                       nw_path_evaluator_cancel(me->path_evaluator);
+               }
+               nw_forget(&me->path_evaluator);
+       }
+       for (mdns_interface_monitor_t *p = &g_monitor_list; *p; p = &(*p)->next) {
+               if (*p == me) {
+                       *p = me->next;
+                       me->next = NULL;
+                       mdns_release(me);
+                       break;
+               }
+       }
+       mdns_retain(me);
+       dispatch_async(me->user_queue,
+       ^{
+               if (me->event_handler) {
+                       me->event_handler(error ? mdns_event_error : mdns_event_invalidated, error);
+               }
+               mdns_release(me);
+       });
+}
+
+//======================================================================================================================
+// MARK: - NW Path Helpers
+
+#define MDNS_INTERFACE_FLAGS_FROM_NWPATH               \
+       (mdns_interface_flag_ipv4_connectivity |        \
+        mdns_interface_flag_ipv6_connectivity |        \
+        mdns_interface_flag_expensive         |        \
+        mdns_interface_flag_constrained)
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nw_path(nw_path_t path, mdns_interface_flags_t current_flags)
+{
+       mdns_interface_flags_t flags = current_flags & ~MDNS_INTERFACE_FLAGS_FROM_NWPATH;
+       if (nw_path_has_ipv4(path)) {
+               flags |= mdns_interface_flag_ipv4_connectivity;
+       }
+       if (nw_path_has_ipv6(path)) {
+               flags |= mdns_interface_flag_ipv6_connectivity;
+       }
+       if (nw_path_is_expensive(path)) {
+               flags |= mdns_interface_flag_expensive;
+       }
+       if (__builtin_available(macOS 10.15, *)) {
+               if (nw_path_is_constrained(path)) {
+                       flags |= mdns_interface_flag_constrained;
+               }
+       }
+       return flags;
+}
+
+//======================================================================================================================
+// MARK: - NWI Helpers
+
+#if !defined(NWI_IFSTATE_FLAGS_HAS_CLAT46)
+       #define NWI_IFSTATE_FLAGS_HAS_CLAT46    0x0040
+#endif
+
+#define MDNS_INTERFACE_FLAGS_FROM_NWI_STATE            mdns_interface_flag_clat46
+
+static mdns_interface_flags_t
+_mdns_get_interface_flags_from_nwi_state(const char *ifname, mdns_interface_flags_t current_flags)
+{
+       __block nwi_ifstate_flags ifstate_flags = 0;
+       dispatch_sync(_mdns_nwi_state_mutex_queue(),
+       ^{
+               if (g_nwi_state) {
+                       const nwi_ifstate_t ifstate = nwi_state_get_ifstate(g_nwi_state, ifname);
+                       if (ifstate) {
+                               ifstate_flags = nwi_ifstate_get_flags(ifstate);
+                       }
+               }
+       });
+       mdns_interface_flags_t flags = current_flags & ~MDNS_INTERFACE_FLAGS_FROM_NWI_STATE;
+       if (ifstate_flags & NWI_IFSTATE_FLAGS_HAS_CLAT46) {
+               flags |= mdns_interface_flag_clat46;
+       }
+       return flags;
+}
+
+//======================================================================================================================
+
+static void
+_mdns_nwi_state_update(void);
+
+static void
+_mdns_start_nwi_state_monitoring(void)
+{
+       static int s_nwi_notify_token = NOTIFY_TOKEN_INVALID;
+       if (s_nwi_notify_token == NOTIFY_TOKEN_INVALID) {
+               const uint32_t status = notify_register_dispatch(nwi_state_get_notify_key(), &s_nwi_notify_token,
+                       _mdns_internal_queue(),
+               ^(__unused int token)
+               {
+                       _mdns_nwi_state_update();
+               });
+               if (s_nwi_notify_token == NOTIFY_TOKEN_INVALID) {
+                       os_log_error(_mdns_nwi_log(), "Failed to register for NWI state notifications (status %u)", status);
+               } else {
+                       _mdns_nwi_state_update();
+               }
+       }
+}
+
+static void
+_mdns_nwi_state_update(void)
+{
+       nwi_state_t new_state = nwi_state_copy();
+       if (!new_state) {
+               os_log_error(_mdns_nwi_log(), "Failed to copy NWI state");
+       }
+       __block nwi_state_t old_state;
+       dispatch_sync(_mdns_nwi_state_mutex_queue(),
+       ^{
+               old_state       = g_nwi_state;
+               g_nwi_state     = new_state;
+       });
+       nwi_state_release_null_safe(old_state);
+       for (mdns_interface_monitor_t m = g_monitor_list; m; m = m->next) {
+               const mdns_interface_flags_t new_flags = _mdns_get_interface_flags_from_nwi_state(m->ifname, m->pending_flags);
+               if (new_flags != m->pending_flags) {
+                       m->pending_flags = new_flags;
+                       if (m->update_source) {
+                               // Note: mdns_interface_flag_reserved is used to ensure that the data is non-zero. According to the
+                               // dispatch_source_create(3) man page, if the data value is zero, the source handler won't be invoked.
+                               dispatch_source_merge_data(m->update_source, m->pending_flags | mdns_interface_flag_reserved);
+                       }
+               }
+       }
+}
+
+//======================================================================================================================
+// MARK: - General Helpers
+
+static int
+_mdns_snprintf_add(char **ptr, const char *lim, const char *fmt, ...)
+{
+       char * const    dst = *ptr;
+       const size_t    len = (size_t)(lim - dst);
+       int                             n;
+
+       require_action_quiet(len > 0, exit, n = 0);
+
+       va_list args;
+       va_start(args, fmt);
+       n = vsnprintf(dst, len, fmt, args);
+       va_end(args);
+       require_quiet(n >= 0, exit);
+
+       if (((size_t)n) > len) {
+               n = (int)len;
+       }
+       *ptr = dst + n;
+
+exit:
+       return n;
+}
diff --git a/mDNSMacOSX/mdns_object.h b/mDNSMacOSX/mdns_object.h
new file mode 100644 (file)
index 0000000..cb3301e
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2019 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
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MDNS_OBJECT_H__
+#define __MDNS_OBJECT_H__
+
+#include "mdns_private.h"
+
+//======================================================================================================================
+// MARK: - mdns_object Private Method Declarations
+
+char *
+mdns_object_copy_description(mdns_any_t object, bool debug, bool privacy);
+
+CFStringRef
+mdns_object_copy_description_as_cfstring(mdns_any_t object, bool debug, bool privacy);
+
+void
+mdns_object_finalize(mdns_any_t object);
+
+#define MDNS_OBJECT_ALLOC_DECLARE(NAME)                \
+       mdns_ ## NAME ## _t                                             \
+       mdns_object_ ## NAME ## _alloc(size_t size)
+
+MDNS_OBJECT_ALLOC_DECLARE(interface_monitor);
+
+#endif // __MDNS_OBJECT_H__
diff --git a/mDNSMacOSX/mdns_object.m b/mDNSMacOSX/mdns_object.m
new file mode 100644 (file)
index 0000000..bdfe665
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2019 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
+ *
+ *     https://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.
+ */
+
+#import "mdns_object.h"
+
+#import <CoreUtils/CoreUtils.h>
+#import <Foundation/Foundation.h>
+#import <os/object_private.h>
+
+//======================================================================================================================
+// MARK: - Class Declarations
+
+#define MDNS_OBJECT_CLASS_DECLARE(NAME)                                                                \
+       _OS_OBJECT_DECL_SUBCLASS_INTERFACE(mdns_ ## NAME, mdns_object)  \
+       extern int _mdns_dummy_variable
+
+_OS_OBJECT_DECL_SUBCLASS_INTERFACE(mdns_object, object)
+
+MDNS_OBJECT_CLASS_DECLARE(interface_monitor);
+
+//======================================================================================================================
+// MARK: - Class Definitions
+
+@implementation OS_OBJECT_CLASS(mdns_object)
+- (void)dealloc
+{
+       mdns_object_finalize(self);
+       arc_safe_super_dealloc();
+}
+
+- (NSString *)description
+{
+       return arc_safe_autorelease((NSString *)mdns_object_copy_description_as_cfstring(self, false, false));
+}
+
+- (NSString *)debugDescription
+{
+       return arc_safe_autorelease((NSString *)mdns_object_copy_description_as_cfstring(self, true, false));
+}
+
+- (NSString *)redactedDescription
+{
+       return arc_safe_autorelease((NSString *)mdns_object_copy_description_as_cfstring(self, false, true));
+}
+@end
+
+#define MDNS_CLASS(NAME)       OS_OBJECT_CLASS(mdns_ ## NAME)
+#define MDNS_OBJECT_CLASS_DEFINE(NAME)                                                                                         \
+       @implementation MDNS_CLASS(NAME)                                                                                                \
+       @end                                                                                                                                                    \
+                                                                                                                                                                       \
+       mdns_ ## NAME ## _t                                                                                                                             \
+       mdns_object_ ## NAME ## _alloc(const size_t size)                                                               \
+       {                                                                                                                                                               \
+               return (mdns_## NAME ##_t)_os_object_alloc([MDNS_CLASS(NAME) class], size);     \
+       }                                                                                                                                                               \
+       extern int _mdns_dummy_variable
+
+MDNS_OBJECT_CLASS_DEFINE(interface_monitor);
diff --git a/mDNSMacOSX/mdns_private.h b/mDNSMacOSX/mdns_private.h
new file mode 100644 (file)
index 0000000..6000d9d
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2019 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
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MDNS_PRIVATE_H__
+#define __MDNS_PRIVATE_H__
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <dispatch/dispatch.h>
+#include <MacTypes.h>
+#include <os/object.h>
+
+#if OS_OBJECT_USE_OBJC
+       #define MDNS_DECL(NAME)                 OS_OBJECT_DECL_SUBCLASS(mdns_ ## NAME, mdns_object)
+       #define MDNS_RETURNS_RETAINED   OS_OBJECT_RETURNS_RETAINED
+
+       OS_OBJECT_DECL(mdns_object,);
+#else
+       #define MDNS_DECL(NAME)                 typedef struct mdns_ ## NAME ## _s *    mdns_ ## NAME ## _t
+       #define MDNS_RETURNS_RETAINED
+
+       MDNS_DECL(object);
+#endif
+
+// mdns Object Declarations
+
+MDNS_DECL(interface_monitor);
+
+OS_ASSUME_NONNULL_BEGIN
+
+#if OS_OBJECT_USE_OBJC
+       typedef mdns_object_t   mdns_any_t;
+#else
+       #if !defined(__cplusplus)
+               typedef union {
+                       mdns_object_t                           base;
+                       mdns_interface_monitor_t        interface_monitor;
+               } mdns_any_t __attribute__((__transparent_union__));
+       #else
+               typedef void *  mdns_any_t;
+       #endif
+#endif
+
+__BEGIN_DECLS
+
+/*!
+ *     @brief
+ *             Increments the reference count of an mdns object.
+ *
+ *     @param object
+ *             The mdns object.
+ */
+void
+mdns_retain(mdns_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+       #undef mdns_retain
+       #define mdns_retain(object)     [(object) retain]
+#endif
+
+/*!
+ *     @brief
+ *             Decrements the reference count of an mdns object.
+ *
+ *     @param object
+ *             The mdns object.
+ */
+void
+mdns_release(mdns_any_t object);
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+       #undef mdns_release
+       #define mdns_release(object)    [(object) release]
+#endif
+
+/*!
+ *     @brief
+ *             Creates a human-readable description of an mdns object as a C string.
+ *
+ *     @param object
+ *             The mdns object.
+ *
+ *     @result
+ *             A C string that must be freed with free(3).
+ */
+OS_WARN_RESULT
+char * _Nullable
+mdns_copy_description(mdns_any_t object);
+
+/*!
+ *     @brief
+ *             CFArray callbacks for mdns objects.
+ */
+extern const CFArrayCallBacks mdns_cfarray_callbacks;
+
+/*!
+ *     @brief
+ *             Creates an interface monitor.
+ *
+ *     @param interface_index
+ *             Index of the interface to monitor.
+ *
+ *     @result
+ *             A new interface monitor or NULL if there was a lack of resources.
+ *
+ *     @discussion
+ *             An interface monitor provides up-to-date information about an interface's properties, such as IPv4
+ *             connectivity, IPv6 connectivity, whether the interface is expensive, and whether the interface is constrained.
+ *
+ *             If this function returns non-NULL, then the caller has an ownership reference to the newly created interface
+ *             monitor, which can be relinquished with <code>mdns_release()</code>.
+ */
+MDNS_RETURNS_RETAINED mdns_interface_monitor_t _Nullable
+mdns_interface_monitor_create(uint32_t interface_index);
+
+/*!
+ *     @brief
+ *             Activates an interface monitor.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @discussion
+ *             Successful activation enables interface monitor updates.
+ *
+ *             This function has no effect on an interface monitor that has already been activated or one that has been
+ *             invalidated.
+ */
+void
+mdns_interface_monitor_activate(mdns_interface_monitor_t monitor);
+
+/*!
+ *     @brief
+ *             Asynchronously invalidates an interface monitor.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @discussion
+ *             This function should be called when the interface monitor is no longer needed.
+ *
+ *             As a result of calling this function, the interface monitor's event handler will be invoked with a
+ *             <code>mdns_event_invalidated</code> event, after which the interface monitor's event and update handlers will
+ *             never be invoked again.
+ *
+ *             This function has no effect on an interface monitor that has already been invalidated.
+ */
+void
+mdns_interface_monitor_invalidate(mdns_interface_monitor_t monitor);
+
+/*!
+ *     @brief
+ *             Specifies the queue on which to invoke the interface monitor's event and update handlers.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @param queue
+ *             A serial queue.
+ *
+ *     @discussion
+ *             This function must be called before activating the interface monitor.
+ *
+ *             This function has no effect on an interface monitor that has been activated or invalidated.
+ */
+void
+mdns_interface_monitor_set_queue(mdns_interface_monitor_t monitor, dispatch_queue_t queue);
+
+/*!
+ *     @brief
+ *             Generic events that can occur during the lifetime of an mdns object.
+ */
+OS_CLOSED_ENUM(mdns_event, int,
+       /*! @const mdns_event_error A fatal error has occurred. */
+       mdns_event_error                = 1,
+       /*! @const mdns_event_invalidated The object has been invalidated. */
+       mdns_event_invalidated  = 2
+);
+
+static inline const char *
+mdns_event_to_string(mdns_event_t event)
+{
+       switch (event) {
+               case mdns_event_error:                  return "Error";
+               case mdns_event_invalidated:    return "Invalidated";
+               default:                                                return "?";
+       }
+}
+
+/*!
+ *     @brief
+ *             Generic event handler for mdns objects.
+ *
+ *     @param event
+ *             The event.
+ *
+ *     @param error
+ *             The error associated with a <code>mdns_event_error</code> event. This argument should be ignored for all other
+ *             types of events.
+ *
+ *     @discussion
+ *             After an <code>mdns_event_invalidated</code> event, none of the object's handlers will ever be invoked again.
+ */
+typedef void (^mdns_event_handler_t)(mdns_event_t event, OSStatus error);
+
+/*!
+ *     @brief
+ *             Sets an interface monitor's event handler.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @param handler
+ *             The event handler.
+ *
+ *     @discussion
+ *             The event handler will never be invoked prior to activation.
+ *
+ *             The event handler will be invoked on the dispatch queue specified by
+ *             <code>mdns_interface_monitor_set_queue()</code> with event <code>mdns_event_error</code> when a fatal error
+ *             occurs and with event <code>mdns_event_invalidated</code> when the interface monitor has been invalidated.
+ *
+ *             After an <code>mdns_event_invalidated</code> event, the event handler will never be invoked again.
+ */
+void
+mdns_interface_monitor_set_event_handler(mdns_interface_monitor_t monitor, mdns_event_handler_t _Nullable handler);
+
+/*!
+ *     @brief
+ *             Flags that represent the properties of a monitored interface.
+ *
+ *     @discussion
+ *             These flags don't represent the actual values of properties. The meaning of these flags depends on the context
+ *             in which they're used. For example, as a parameter of mdns_interface_monitor_update_handler_t, a set flag
+ *             means that the value of a given property has changed.
+ */
+OS_CLOSED_OPTIONS(mdns_interface_flags, uint32_t,
+       mdns_interface_flag_null                                = 0,
+       mdns_interface_flag_ipv4_connectivity   = (1U <<  0),
+       mdns_interface_flag_ipv6_connectivity   = (1U <<  1),
+       mdns_interface_flag_expensive                   = (1U <<  2),
+       mdns_interface_flag_constrained                 = (1U <<  3),
+       mdns_interface_flag_clat46                              = (1U <<  4),
+       mdns_interface_flag_reserved                    = (1U << 31)
+);
+
+/*!
+ *     @brief
+ *             Update handler for an interface monitor.
+ *
+ *     @param change_flags
+ *             Each flag bit represents a property of a monitored interface. If the bit is set, then the value of that
+ *             property has changed. If the bit is clear, then the value of that property has not changed.
+ */
+typedef void (^mdns_interface_monitor_update_handler_t)(mdns_interface_flags_t change_flags);
+
+/*!
+ *     @brief
+ *             Sets an interface monitor's update handler.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @param handler
+ *             The update handler.
+ *
+ *     @discussion
+ *             The update handler will never be invoked prior to activation.
+ *
+ *             The update handler will be invoked on the dispatch queue specified by
+ *             <code>mdns_interface_monitor_set_queue()</code> when any of the monitored interface's properties have been
+ *             updated.
+ *
+ *             After an <code>mdns_event_invalidated</code> event, the update handler will ever be invoked again.
+ */
+void
+mdns_interface_monitor_set_update_handler(mdns_interface_monitor_t monitor,
+       mdns_interface_monitor_update_handler_t _Nullable handler);
+
+/*!
+ *     @brief
+ *             Returns the index of the monitored interface.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ */
+uint32_t
+mdns_interface_monitor_get_interface_index(mdns_interface_monitor_t monitor);
+
+/*!
+ *     @brief
+ *             Determines whether the monitored interface currently has IPv4 connectivity.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @discussion
+ *             mdns_interface_flag_ipv4_connectivity will be set in the update handler's change_flags argument when the value
+ *             of this property has changed.
+ */
+bool
+mdns_interface_monitor_has_ipv4_connectivity(mdns_interface_monitor_t monitor);
+
+/*!
+ *     @brief
+ *             Determines whether the monitored interface currently has IPv6 connectivity.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @discussion
+ *             mdns_interface_flag_ipv6_connectivity will be set in the update handler's change_flags argument when the value
+ *             of this property has changed.
+ */
+bool
+mdns_interface_monitor_has_ipv6_connectivity(mdns_interface_monitor_t monitor);
+
+/*!
+ *     @brief
+ *             Determines whether the monitored interface is currently expensive.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @discussion
+ *             mdns_interface_flag_expensive will be set in the update handler's change_flags argument when the value
+ *             of this property has changed.
+ */
+bool
+mdns_interface_monitor_is_expensive(mdns_interface_monitor_t monitor);
+
+/*!
+ *     @brief
+ *             Determines whether the monitored interface is currently constrained.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @discussion
+ *             mdns_interface_flag_constrained will be set in the update handler's change_flags argument when the value
+ *             of this property has changed.
+ */
+bool
+mdns_interface_monitor_is_constrained(mdns_interface_monitor_t monitor);
+
+/*!
+ *     @brief
+ *             Determines whether the monitored interface has CLAT46 support.
+ *
+ *     @param monitor
+ *             The interface monitor.
+ *
+ *     @discussion
+ *             mdns_interface_flag_clat46 will be set in the update handler's change_flags argument when the value
+ *             of this property has changed.
+ */
+bool
+mdns_interface_monitor_is_clat46(mdns_interface_monitor_t monitor);
+
+__END_DECLS
+
+OS_ASSUME_NONNULL_END
+
+#endif // __MDNS_PRIVATE_H__
diff --git a/mDNSMacOSX/pfkey.c b/mDNSMacOSX/pfkey.c
deleted file mode 100644 (file)
index 6e95a6b..0000000
+++ /dev/null
@@ -1,2140 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 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.
- */
-
-/*     $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 <TargetConditionals.h>
-
-#include "ipsec_strerror.h"
-#include "libpfkey.h"
-#include "ipsec_options.h"
-
-#if TARGET_OS_EMBEDDED
-#ifndef MDNS_NO_IPSEC
-#define MDNS_NO_IPSEC 1
-#endif
-#endif
-
-#ifndef MDNS_NO_IPSEC
-
-#define CALLOC(size, cast) (cast)calloc(1, (size))
-
-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);
-}
-
-#endif /* ndef MDNS_NO_IPSEC */
index e4744736af55d7170978905bf808a3942ca52796..c78e3ca541be136c1d2df16ec62ceb1536cd8e10 100644 (file)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
- * Copyright (c) 2013, 2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2013-2018 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.
@@ -22,6 +22,7 @@
     #include <nw/private.h>
 #else
     #include <network/private.h>
+    #define nw_release(X) network_release(X)
 #endif
 
 #include "dns_sd_internal.h"
 //Gets the DNSPolicy from NW PATH EVALUATOR
 mDNSexport void mDNSPlatformGetDNSRoutePolicy(DNSQuestion *q, mDNSBool *isBlocked)
 {
-    q->ServiceID = -1; // initialize the ServiceID to default value of -1
-
-    // Return for non-unicast DNS queries, invalid pid, if NWPathEvaluation is already done by the client, or NWPathEvaluation not available on this OS
-    if (mDNSOpaque16IsZero(q->TargetQID) || (q->pid < 0) || (q->flags & kDNSServiceFlagsPathEvaluationDone) || !nw_endpoint_create_host)
-    {
-        *isBlocked = mDNSfalse;
-        return;
-    }
-    
-    mDNSs32 service_id;
-    mDNSu32 client_ifindex, dnspol_ifindex;
-    int retval;
-    struct proc_uniqidentifierinfo info;
-    mDNSBool isUUIDSet;
-    
-    char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
-    ConvertDomainNameToCString(&q->qname, unenc_name);
-    
-    nw_endpoint_t host = nw_endpoint_create_host(unenc_name, "0");
-    if (host == NULL)
-        LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t host is NULL", q->qname.c,
-               DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-    
-    nw_parameters_t parameters = nw_parameters_create();
-    if (parameters == NULL)
-        LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t parameters is NULL", q->qname.c,
-               DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-    
-    // Check for all the special (negative) internal value interface indices before initializing client_ifindex
-    if (   (q->InterfaceID == mDNSInterface_Any)
-        || (q->InterfaceID == mDNSInterface_Unicast)
-        || (q->InterfaceID == mDNSInterface_LocalOnly)
-        || (q->InterfaceID == mDNSInterfaceMark)
-        || (q->InterfaceID == mDNSInterface_P2P)
-        || (q->InterfaceID == mDNSInterface_BLE)
-        || (q->InterfaceID == uDNSInterfaceMark))
-    {
-        client_ifindex = 0;
-    }
-    else
+    if (__builtin_available(macOS 10.14, *))
     {
-        client_ifindex = (mDNSu32)(uintptr_t)q->InterfaceID;
-    }
+        q->ServiceID = -1; // initialize the ServiceID to default value of -1
 
-    
-    if (client_ifindex > 0)
-    {
-        nw_interface_t client_intf = nw_interface_create_with_index(client_ifindex);
-        nw_parameters_require_interface(parameters, client_intf);
-        if (client_intf != NULL)
-            network_release(client_intf);
+        // Return for non-unicast DNS queries, invalid pid, if NWPathEvaluation is already done by the client, or NWPathEvaluation not available on this OS
+        if (mDNSOpaque16IsZero(q->TargetQID) || (q->pid < 0) || (q->flags & kDNSServiceFlagsPathEvaluationDone) || !nw_endpoint_create_host)
+        {
+            *isBlocked = mDNSfalse;
+            return;
+        }
+        
+        mDNSs32 service_id;
+        mDNSu32 client_ifindex, dnspol_ifindex;
+        int retval;
+        struct proc_uniqidentifierinfo info;
+        mDNSBool isUUIDSet;
+        
+        char unenc_name[MAX_ESCAPED_DOMAIN_NAME];
+        ConvertDomainNameToCString(&q->qname, unenc_name);
+        
+        nw_endpoint_t host = nw_endpoint_create_host(unenc_name, "0");
+        if (host == NULL)
+            LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t host is NULL", q->qname.c,
+                   DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+        
+        nw_parameters_t parameters = nw_parameters_create();
+        if (parameters == NULL)
+            LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_endpoint_t parameters is NULL", q->qname.c,
+                   DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+
+#if TARGET_OS_WATCH
+        // Companion interface on watchOS does not support DNS, so we don't want path evalution to return it to us.
+        nw_parameters_set_companion_preference(parameters, nw_parameters_agent_preference_avoid);
+#endif // TARGET_OS_WATCH
+        
+        // Check for all the special (negative) internal value interface indices before initializing client_ifindex
+        if (   (q->InterfaceID == mDNSInterface_Any)
+            || (q->InterfaceID == mDNSInterface_LocalOnly)
+            || (q->InterfaceID == mDNSInterfaceMark)
+            || (q->InterfaceID == mDNSInterface_P2P)
+            || (q->InterfaceID == mDNSInterface_BLE)
+            || (q->InterfaceID == uDNSInterfaceMark))
+        {
+            client_ifindex = 0;
+        }
         else
-            LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: client_intf returned by nw_interface_create_with_index() is NULL");
-    }
-    
-    nw_parameters_set_uid(parameters,(uid_t)q->euid);
+        {
+            client_ifindex = (mDNSu32)(uintptr_t)q->InterfaceID;
+        }
 
-    if (q->pid != 0)
-    {
-        nw_parameters_set_pid(parameters, q->pid);
-        retval = proc_pidinfo(q->pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
-        if (retval == (int)sizeof(info))
+        if (client_ifindex > 0)
         {
-            nw_parameters_set_e_proc_uuid(parameters, info.p_uuid);
-            isUUIDSet = mDNStrue;
+            nw_interface_t client_intf = nw_interface_create_with_index(client_ifindex);
+            nw_parameters_require_interface(parameters, client_intf);
+            if (client_intf != NULL)
+                nw_release(client_intf);
+            else
+                LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: client_intf returned by nw_interface_create_with_index() is NULL");
+        }
+        
+        nw_parameters_set_uid(parameters,(uid_t)q->euid);
+
+        if (q->pid != 0)
+        {
+            nw_parameters_set_pid(parameters, q->pid);
+            retval = proc_pidinfo(q->pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
+            if (retval == (int)sizeof(info))
+            {
+                nw_parameters_set_e_proc_uuid(parameters, info.p_uuid);
+                isUUIDSet = mDNStrue;
+            }
+            else
+            {
+                debugf("mDNSPlatformGetDNSRoutePolicy: proc_pidinfo returned %d", retval);
+                isUUIDSet = mDNSfalse;
+            }
         }
         else
         {
-            debugf("mDNSPlatformGetDNSRoutePolicy: proc_pidinfo returned %d", retval);
-            isUUIDSet = mDNSfalse;
+            nw_parameters_set_e_proc_uuid(parameters, q->uuid);
+            isUUIDSet = mDNStrue;
         }
-    }
-    else
-    {
-        nw_parameters_set_e_proc_uuid(parameters, q->uuid);
-        isUUIDSet = mDNStrue;
-    }
-    
-    nw_path_evaluator_t evaluator = nw_path_create_evaluator_for_endpoint(host, parameters);
-    if (evaluator == NULL)
-        LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_evaluator_t evaluator is NULL", q->qname.c, 
-                DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-    
-    if (host != NULL)
-        network_release(host);
-    if (parameters != NULL)
-        network_release(parameters);
-    
-    nw_path_t path = nw_path_evaluator_copy_path(evaluator);
-    if (path == NULL)
-        LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_t path is NULL", q->qname.c,
-               DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
-    
-    service_id = nw_path_get_flow_divert_unit(path);
-    if (service_id != 0)
-    {
-        q->ServiceID = service_id;
-        LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s service ID is set ->service_ID:[%d] ", q->qname.c, service_id);
-    }
-    else
-    {
-        nw_interface_t nwpath_intf = nw_path_copy_scoped_interface(path);
-        if (nwpath_intf != NULL)
+        
+        nw_path_evaluator_t evaluator = nw_path_create_evaluator_for_endpoint(host, parameters);
+        if (evaluator == NULL)
+            LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_evaluator_t evaluator is NULL", q->qname.c,
+                    DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+        
+        if (host != NULL)
+            nw_release(host);
+        if (parameters != NULL)
+            nw_release(parameters);
+        
+        nw_path_t path = nw_path_evaluator_copy_path(evaluator);
+        if (path == NULL)
+            LogMsg("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_path_t path is NULL", q->qname.c,
+                   DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+        
+        service_id = nw_path_get_flow_divert_unit(path);
+        if (service_id != 0)
         {
-            // Use the new scoped interface given by NW PATH EVALUATOR
-            dnspol_ifindex = nw_interface_get_index(nwpath_intf);
-            q->InterfaceID = (mDNSInterfaceID)(uintptr_t)dnspol_ifindex;
-            
-            network_release(nwpath_intf);
-            
-            if (dnspol_ifindex != client_ifindex)
-                LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy has changed the scoped ifindex from [%d] to [%d]",
-                        client_ifindex, dnspol_ifindex);
+            q->ServiceID = service_id;
+            LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy: Query for %##s service ID is set ->service_ID:[%d] ", q->qname.c, service_id);
         }
         else
         {
-            debugf("mDNSPlatformGetDNSRoutePolicy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_interface_t nwpath_intf is NULL ", q->qname.c, DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+            nw_interface_t nwpath_intf = nw_path_copy_scoped_interface(path);
+            if (nwpath_intf != NULL)
+            {
+                // Use the new scoped interface given by NW PATH EVALUATOR
+                dnspol_ifindex = nw_interface_get_index(nwpath_intf);
+                q->InterfaceID = (mDNSInterfaceID)(uintptr_t)dnspol_ifindex;
+                
+                nw_release(nwpath_intf);
+                
+                if (dnspol_ifindex != client_ifindex)
+                    LogInfo("mDNSPlatformGetDNSRoutePolicy: DNS Route Policy has changed the scoped ifindex from [%d] to [%d]",
+                            client_ifindex, dnspol_ifindex);
+            }
+            else
+            {
+                debugf("mDNSPlatformGetDNSRoutePolicy: Query for %##s (%s), PID[%d], EUID[%d], ServiceID[%d] nw_interface_t nwpath_intf is NULL ", q->qname.c, DNSTypeName(q->qtype), q->pid, q->euid, q->ServiceID);
+            }
         }
+        
+        if (isUUIDSet && path && (nw_path_get_status(path) == nw_path_status_unsatisfied) && (nw_path_get_reason(path) == nw_path_reason_policy_drop))
+            *isBlocked = mDNStrue;
+        else
+            *isBlocked = mDNSfalse;
+
+        if (path != NULL)
+            nw_release(path);
+        if (evaluator != NULL)
+            nw_release(evaluator);
     }
-    
-    if (isUUIDSet && (nw_path_get_status(path) == nw_path_status_unsatisfied) && (nw_path_get_reason(path) == nw_path_reason_policy_drop))
-        *isBlocked = mDNStrue;
     else
+    {
         *isBlocked = mDNSfalse;
-
-    if (path != NULL)
-        network_release(path);
-    if (evaluator != NULL)
-        network_release(evaluator);
-
+    }
 }
diff --git a/mDNSMacOSX/utilities/system_utilities.c b/mDNSMacOSX/utilities/system_utilities.c
new file mode 100644 (file)
index 0000000..834e8b2
--- /dev/null
@@ -0,0 +1,15 @@
+//
+//  system_utilities.c
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#include <os/variant_private.h> // os_variant_has_internal_diagnostics
+#include "mDNSEmbeddedAPI.h"
+#include "system_utilities.h"
+
+mDNSexport mDNSBool IsAppleInternalBuild(void)
+{
+       return (os_variant_has_internal_diagnostics("com.apple.mDNSResponder") ? mDNStrue : mDNSfalse);
+}
diff --git a/mDNSMacOSX/utilities/system_utilities.h b/mDNSMacOSX/utilities/system_utilities.h
new file mode 100644 (file)
index 0000000..789be42
--- /dev/null
@@ -0,0 +1,13 @@
+//
+//  system_utilities.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef SYSTEM_UTILITIES_H
+#define SYSTEM_UTILITIES_H
+
+mDNSexport mDNSBool IsAppleInternalBuild(void);
+
+#endif /* SYSTEM_UTILITIES_H */
diff --git a/mDNSMacOSX/xpc_services/xpc_client_dns_proxy.h b/mDNSMacOSX/xpc_services/xpc_client_dns_proxy.h
new file mode 100644 (file)
index 0000000..1676299
--- /dev/null
@@ -0,0 +1,22 @@
+//
+//  xpc_client_dns_proxy.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_CLIENT_DNS_PROXY_H
+#define XPC_CLIENT_DNS_PROXY_H
+
+#define kDNSProxyService        "com.apple.mDNSResponder.dnsproxy"
+#define kDNSProxyParameters     "DNSProxyParameters"
+
+#define kDNSInIfindex0          "InputArrayInterfaceIndex[0]"
+#define kDNSInIfindex1          "InputArrayInterfaceIndex[1]"
+#define kDNSInIfindex2          "InputArrayInterfaceIndex[2]"
+#define kDNSInIfindex3          "InputArrayInterfaceIndex[3]"
+#define kDNSInIfindex4          "InputArrayInterfaceIndex[4]"
+
+#define kDNSOutIfindex          "OutputInterfaceIndex"
+
+#endif /* XPC_CLIENT_DNS_PROXY_H */
diff --git a/mDNSMacOSX/xpc_services/xpc_client_log_utility.h b/mDNSMacOSX/xpc_services/xpc_client_log_utility.h
new file mode 100644 (file)
index 0000000..672e2fe
--- /dev/null
@@ -0,0 +1,52 @@
+//
+//  xpc_client_log_utility.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_CLIENT_LOG_UTILITY_H
+#define XPC_CLIENT_LOG_UTILITY_H
+
+#define kDNSLogUtilityService   "com.apple.mDNSResponder.log_utility"
+
+typedef enum
+{
+    kDNSMsg_NoError = 0,
+    kDNSMsg_Busy,
+    kDNSMsg_UnknownRequest,
+    kDNSMsg_Error
+} DaemonReplyStatusCodes;
+
+#define kDNSErrorDescription    "ErrorDescription"
+
+#define kDNSLogLevel            "DNSLoggingVerbosity"
+typedef enum
+{
+    log_level1 = 1, // logging off
+    log_level2,     // logging USR1
+    log_level3,     // logging USR2
+    log_level4,     // logging USR1/2
+} DNSLogLevels;
+
+#define kDNSStateInfo           "DNSStateInfoLevels"
+typedef enum
+{
+    full_state = 1,                     // Dump state to a plain text file
+    full_state_with_compression = 2,    // Dump state to a compressed file
+    full_state_to_stdout = 3,           // Dump state to STDOUT
+} DNSStateInfo;
+
+#define kmDNSResponderTests     "mDNSResponderTests"
+typedef enum
+{
+    test_helper_ipc = 1,   // invokes mDNSResponder to send a test msg to mDNSResponderHelper
+    test_mDNS_log,         // invokes mDNSResponder to log using different internal macros
+} mDNSTestModes;
+
+#define kDNSStateDump           "mDNSResponderStateDump"
+#define kDNSDumpFilePath        "mDNSResponderDumpFilePath"
+#define kDNSStateDumpTimeUsed   "mDNSResponderDumpTimeUsed"
+#define kDNSStateDumpFD         "mDNSResponderDumpFD"
+
+#endif /* XPC_CLIENT_LOG_UTILITY_H */
diff --git a/mDNSMacOSX/xpc_services/xpc_clients.h b/mDNSMacOSX/xpc_services/xpc_clients.h
new file mode 100644 (file)
index 0000000..7a12746
--- /dev/null
@@ -0,0 +1,16 @@
+//
+//  xpc_clients.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_CLIENTS_H
+#define XPC_CLIENTS_H
+
+#include "xpc_client_dns_proxy.h"
+#include "xpc_client_log_utility.h"
+
+#define kDNSDaemonReply "DaemonReplyStatusToClient"
+
+#endif // XPC_CLIENTS_H
diff --git a/mDNSMacOSX/xpc_services/xpc_service_dns_proxy.c b/mDNSMacOSX/xpc_services/xpc_service_dns_proxy.c
new file mode 100644 (file)
index 0000000..47e837a
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#include <xpc/private.h>
+#include "xpc_service_dns_proxy.h"
+#include "xpc_clients.h"
+
+#include "dnsproxy.h"
+#include "mDNSMacOSX.h"
+#include "xpc_services.h"
+
+extern mDNS mDNSStorage;
+static int dps_client_pid; // To track current active client using DNS Proxy Service
+static dispatch_queue_t dps_queue = NULL;
+
+mDNSlocal void accept_dps_client(xpc_connection_t conn);
+mDNSlocal void handle_dps_request(xpc_object_t req);
+mDNSlocal void handle_dps_terminate();
+mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off);
+
+mDNSexport void log_dnsproxy_info(mDNS *const m)
+{
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "----- Active XPC Clients -----");
+    if (dps_client_pid) {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]",
+                  dps_client_pid, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4],
+                  m->dp_opintf);
+    } else {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "<None>");
+    }
+}
+
+mDNSexport void log_dnsproxy_info_to_fd(int fd, mDNS *const m)
+{
+    LogToFD(fd, "----- Active XPC Clients -----");
+    if (dps_client_pid) {
+        LogToFD(fd, "DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]",
+                  dps_client_pid, m->dp_ipintf[0], m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4],
+                  m->dp_opintf);
+    } else {
+        LogToFD(fd, "<None>");
+    }
+}
+
+mDNSexport void init_dnsproxy_service(void)
+{
+    xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+    if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
+        return;
+    }
+
+    dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL);
+
+    xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg)
+        {
+            xpc_type_t type = xpc_get_type(eventmsg);
+
+            if (type == XPC_TYPE_CONNECTION) {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                          "init_dnsproxy_service: New DNSProxyService Client %p", eventmsg);
+                accept_dps_client(eventmsg);
+            }
+            else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "init_dnsproxy_service: XPCError: " PUB_S,
+                          xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
+                return;
+            }
+            else
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "init_dnsproxy_service: Unknown EventMsg type");
+                return;
+            }
+        });
+
+    xpc_connection_resume(dps_listener);
+}
+
+mDNSlocal void accept_dps_client(xpc_connection_t conn)
+{
+    uid_t c_euid;
+    int   c_pid;
+    c_euid  = xpc_connection_get_euid(conn);
+    c_pid   = xpc_connection_get_pid(conn);
+
+    if (c_euid != 0 || !IsEntitled(conn, kDNSProxyService))
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "accept_dps_client: DNSProxyService Client PID[%d] is missing Entitlement or is not running as root!",
+                  c_pid);
+        xpc_connection_cancel(conn);
+        return;
+    }
+
+    xpc_retain(conn);
+    xpc_connection_set_target_queue(conn, dps_queue);
+    xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
+        {
+            xpc_type_t type = xpc_get_type(req_msg);
+
+            if (type == XPC_TYPE_DICTIONARY)
+            {
+                handle_dps_request(req_msg);
+            }
+            else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                          "accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn);
+                // Only the Client that has activated DPS should be able to terminate it
+                if (c_pid == dps_client_pid)
+                    handle_dps_terminate();
+                xpc_release(conn);
+            }
+        });
+
+    xpc_connection_resume(conn);
+}
+
+mDNSlocal void handle_dps_request(xpc_object_t req)
+{
+    int dps_tmp_client;
+    mDNSBool proxy_off = mDNSfalse;
+    xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
+    dps_tmp_client = (int) xpc_connection_get_pid(remote_conn);
+
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "handle_dps_request: Handler for DNS Proxy Requests");
+
+    if (dps_client_pid <= 0)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "handle_dps_request: DNSProxy is not engaged (New Client)");
+        // No Active Client, save new Client's PID (also indicates DNS Proxy was OFF)
+        dps_client_pid = dps_tmp_client;
+        proxy_off = mDNStrue;
+    }
+    else
+    {
+        // We already have an active DNS Proxy Client and until that client does not terminate the connection
+        // or crashes, a new client cannot change/override the current DNS Proxy settings.
+        if (dps_client_pid != dps_tmp_client)
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                      "handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time");
+            // Return Engaged Status to the client
+            xpc_object_t reply = xpc_dictionary_create_reply(req);
+            if (reply)
+            {
+                xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_Busy);
+                xpc_connection_send_message(remote_conn, reply);
+                xpc_release(reply);
+            }
+            else
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                          "handle_dps_request: Reply Dictionary could not be created");
+                return;
+            }
+            // We do not really need to terminate the connection with the client
+            // as it may try again later which is fine
+            return;
+        }
+    }
+
+
+    xpc_object_t response = xpc_dictionary_create_reply(req);
+    // Return Success Status to the client
+    if (response)
+    {
+        xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
+        xpc_connection_send_message(remote_conn, response);
+        xpc_release(response);
+    }
+    else
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "handle_dps_request: Response Dictionary could not be created");
+        return;
+    }
+
+    // Proceed to get DNS Proxy Settings from the Client
+    if (xpc_dictionary_get_uint64(req, kDNSProxyParameters))
+    {
+        mDNSu32 inIf[MaxIp], outIf;
+
+        inIf[0]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex0);
+        inIf[1]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex1);
+        inIf[2]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex2);
+        inIf[3]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex3);
+        inIf[4]   = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex4);
+        outIf     = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSOutIfindex);
+
+        ActivateDNSProxy(inIf, outIf, proxy_off);
+    }
+}
+
+mDNSlocal void handle_dps_terminate()
+{
+
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+              "handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy",
+              dps_client_pid);
+    // Clear the Client's PID, so that we can now accept new DPS requests
+    dps_client_pid = 0;
+
+    KQueueLock();
+    mDNSPlatformCloseDNSProxySkts(&mDNSStorage);
+    // TBD: Close TCP Sockets
+    DNSProxyTerminate();
+    KQueueUnlock("DNSProxy Deactivated");
+}
+
+mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off)
+{
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+              "ActivateDNSProxy: InterfaceIndex List by Client: Input[%d, %d, %d, %d, %d] Output[%d]",
+              IpIfArr[0], IpIfArr[1], IpIfArr[2], IpIfArr[3], IpIfArr[4], OpIf);
+
+    KQueueLock();
+    DNSProxyInit(IpIfArr, OpIf);
+    if (proxy_off) // Open skts only if proxy was OFF else we may end up opening extra skts
+        mDNSPlatformInitDNSProxySkts(ProxyUDPCallback, ProxyTCPCallback);
+    KQueueUnlock("DNSProxy Activated");
+}
diff --git a/mDNSMacOSX/xpc_services/xpc_service_dns_proxy.h b/mDNSMacOSX/xpc_services/xpc_service_dns_proxy.h
new file mode 100644 (file)
index 0000000..cae8759
--- /dev/null
@@ -0,0 +1,18 @@
+//
+//  xpc_service_dns_server.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_SERVICE_DNS_PROXY_H
+#define XPC_SERVICE_DNS_PROXY_H
+
+#include "xpc_client_dns_proxy.h"
+#include "dnsproxy.h"
+
+mDNSexport void log_dnsproxy_info(mDNS *const m);
+mDNSexport void log_dnsproxy_info_to_fd(int fd, mDNS *const m);
+mDNSexport void init_dnsproxy_service(void);
+
+#endif /* XPC_SERVICE_DNS_PROXY_H */
diff --git a/mDNSMacOSX/xpc_services/xpc_service_log_utility.c b/mDNSMacOSX/xpc_services/xpc_service_log_utility.c
new file mode 100644 (file)
index 0000000..47348cb
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#include <xpc/xpc.h>
+#include <dirent.h>                     // opendir
+#include <sys/stat.h>                   // stat
+#include <archive.h>
+#include <archive_entry.h>
+#include <AssertMacros.h>               // require, require_action
+
+#include "mDNSMacOSX.h"
+#include "helper.h"
+#include "xpc_services.h"
+#include "xpc_service_log_utility.h"
+#include "xpc_clients.h"
+#include "system_utilities.h"           // IsAppleInternalBuild
+
+#define STATE_DUMP_PLAIN_SUFFIX "txt"
+#define STATE_DUMP_COMPRESSED_SUFFIX "tar.bz2"
+
+// global variables
+extern mDNS             mDNSStorage;
+static dispatch_queue_t log_utility_server_queue = NULL;
+
+// function declaration
+extern void         dump_state_to_fd(int fd);
+mDNSlocal void      accept_client(xpc_connection_t conn);
+mDNSlocal mDNSs8    handle_requests(xpc_object_t req);
+mDNSlocal mDNSs8    check_permission(xpc_connection_t connection);
+mDNSlocal mDNSs8    handle_state_dump(mDNSu32 dump_option, char *full_file_name, mDNSu32 name_buffer_len,
+                                      int client_fd, mDNSs32 *time_ms_used);
+mDNSlocal mDNSs32   find_oldest_state_dump(const char *dump_dir, const char *file_name, char *full_file_name,
+                                           mDNSu32 buffer_len, char *oldest_file_name);
+mDNSlocal mDNSs8    remove_state_dump_if_too_many(const char *dump_dir, const char *oldest_file_name, mDNSs32 dump_file_count,
+                                                  mDNSs32 max_allowed);
+mDNSlocal int       create_new_state_dump_file(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len);
+mDNSlocal mDNSs8    handle_state_dump_to_fd(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len,
+                                            mDNSBool if_compress);
+mDNSlocal mDNSs8    compress_state_dump_and_delete(char *input_file, mDNSu32 buffer_len);
+mDNSlocal mDNSs32   timediff_ms(struct timeval* t1, struct timeval* t2);
+
+// function definition
+mDNSexport void init_log_utility_service(void)
+{
+    xpc_connection_t log_utility_listener = xpc_connection_create_mach_service(kDNSLogUtilityService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
+    if (!log_utility_listener || xpc_get_type(log_utility_listener) != XPC_TYPE_CONNECTION) {
+        LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "Error Creating XPC Listener for Log Utility Server!");
+        return;
+    }
+
+    log_utility_server_queue = dispatch_queue_create("com.apple.mDNSResponder.log_utility_server_queue", NULL);
+
+    xpc_connection_set_event_handler(log_utility_listener, ^(xpc_object_t eventmsg) {
+        xpc_type_t type = xpc_get_type(eventmsg);
+
+        if (type == XPC_TYPE_CONNECTION) {
+            LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_INFO, "C%p {action='receives connection'}", eventmsg);
+            accept_client(eventmsg);
+        } else if (type == XPC_TYPE_ERROR) {
+            LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "C%p {xpc_error=\n" PUB_S "\n}", eventmsg,
+                      xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
+        } else {
+            LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "C%p {error='receives unknown xpc request'}", eventmsg);
+        }
+    });
+
+    xpc_connection_resume(log_utility_listener);
+}
+
+mDNSlocal void accept_client(xpc_connection_t conn)
+{
+    xpc_retain(conn);
+    xpc_connection_set_target_queue(conn, log_utility_server_queue);
+    xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg) {
+        xpc_type_t type = xpc_get_type(req_msg);
+
+        if (type == XPC_TYPE_DICTIONARY) {
+            handle_requests(req_msg);
+        } else { // We hit this case ONLY if Client Terminated Connection OR Crashed
+            LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT, "C%p {status='client closed the connection'}", conn);
+            xpc_release(conn);
+        }
+    });
+
+    xpc_connection_resume(conn);
+}
+
+mDNSlocal mDNSs8 handle_requests(xpc_object_t req)
+{
+    mDNSs8              ret = 0;
+    xpc_connection_t    remote_conn = xpc_dictionary_get_remote_connection(req);
+
+    LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_INFO, "C%p {action='handling log utility request'}", remote_conn);
+
+    // create the dictionary for response purpose
+    xpc_object_t response = xpc_dictionary_create_reply(req);
+    if (response == mDNSNULL) {
+        LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR, "C%p {error='cannot create reply response dictionary'}", remote_conn);
+        return -1;
+    }
+
+    mDNSu32 reply_value;
+    ret = check_permission(remote_conn);
+    if (ret < 0) {
+        // permission error
+        reply_value = kDNSMsg_Error;
+        if (ret == -1) {
+            xpc_dictionary_set_string(response, kDNSErrorDescription, "Client must be running as root");
+        } else if (ret == -2) {
+            xpc_dictionary_set_string(response, kDNSErrorDescription, "Client is missing the entitlement");
+        }
+    } else if (xpc_dictionary_get_uint64(req, kDNSStateDump)) {
+        mDNSu32     dump_option = (mDNSs32)xpc_dictionary_get_uint64(req, kDNSStateDump);
+        char        full_file_name[PATH_MAX];
+        mDNSs32     time_used;
+
+        // We do not dump state in the customer build due to privacy consideration.
+        if (IsAppleInternalBuild()) {
+            int client_fd = xpc_dictionary_dup_fd(req, kDNSStateDumpFD);
+            ret = handle_state_dump(dump_option, full_file_name, sizeof(full_file_name), client_fd, &time_used);
+            if (ret == 0) {
+                reply_value = kDNSMsg_NoError;
+                xpc_dictionary_set_int64(response, kDNSStateDumpTimeUsed, time_used);
+
+                if (dump_option != full_state_to_stdout) {
+                    xpc_dictionary_set_string(response, kDNSDumpFilePath, full_file_name);
+                }
+            } else {
+                reply_value = kDNSMsg_Error;
+                xpc_dictionary_set_string(response, kDNSErrorDescription, "State dump fails");
+            }
+            close(client_fd);
+        } else {
+            reply_value = kDNSMsg_Error;
+            xpc_dictionary_set_string(response, kDNSErrorDescription, "State dump is only enabled in internal builds");
+        }
+    } else {
+        LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_ERROR,
+                  "C%p {error='unknown log utility request from client'}", remote_conn);
+        reply_value = kDNSMsg_UnknownRequest;
+        xpc_dictionary_set_string(response, kDNSErrorDescription, "unknown log utility request from client");
+    }
+
+    xpc_dictionary_set_uint64(response, kDNSDaemonReply, reply_value);
+    xpc_connection_send_message(remote_conn, response);
+    xpc_release(response);
+
+    return 0;
+}
+
+mDNSlocal mDNSs8 check_permission(xpc_connection_t connection)
+{
+    uid_t   client_euid = xpc_connection_get_euid(connection);
+    int     client_pid = xpc_connection_get_pid(connection);
+    mDNSs8  ret = 0;
+
+    if (client_euid != 0) {
+        LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+                  "C%p {client_pid=%d,error='not running as root'}", connection, client_pid);
+        ret = -1;
+    }
+
+    if (!IsEntitled(connection, kDNSLogUtilityService)){
+        LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+                  "C%p {client_pid=%d,error='Client is missing entitlement'}", connection, client_pid);
+        ret = -2;
+    }
+
+    return ret;
+}
+
+/*
+ * pointers of full_file_name and time_used are passed into, when function returns, full_file_name will be filled
+ * with the full path to the dumped file, and time_used is filled with time duration(ms) when mDNSResponder is
+ * blocked. if_get_lock indicates if we should lock the kqueue before dumping the state.
+ */
+mDNSexport mDNSs8 handle_state_dump(mDNSu32 dump_option, char *full_file_name, mDNSu32 name_buffer_len,
+                                    int client_fd, mDNSs32 *time_ms_used)
+{
+    mDNSs8 ret;
+
+    // record the start time, and lock the kqueue
+    struct timeval time_start;
+    gettimeofday(&time_start, mDNSNULL);
+    KQueueLock();
+
+    if (dump_option == full_state_to_stdout) {
+        dump_state_to_fd(client_fd);
+        ret = 0;
+    } else {
+        // dump_option == full_state || dump_option == full_state_with_compression
+        ret = handle_state_dump_to_fd(MDSNRESPONDER_STATE_DUMP_DIR, MDSNRESPONDER_STATE_DUMP_FILE_NAME,
+                                        full_file_name, name_buffer_len,
+                                        dump_option == full_state_with_compression ? mDNStrue : mDNSfalse);
+    }
+
+    // unlock the kqueue, record the end time and calculate the duration.
+    KQueueUnlock("State Dump");
+    struct timeval time_end;
+    gettimeofday(&time_end, mDNSNULL);
+    *time_ms_used = timediff_ms(&time_end, &time_start);
+
+    return ret;
+}
+
+#define MAX_NUM_DUMP_FILES 5 // controls how many files we are allowed to created for the state dump
+mDNSlocal mDNSs8 handle_state_dump_to_fd(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 name_buffer_len,
+                                         mDNSBool if_compress)
+{
+    char            oldest_file_name[PATH_MAX];
+    mDNSs32         dump_file_count = 0;
+    int             ret;
+
+    dump_file_count = find_oldest_state_dump(dump_dir, file_name, full_file_name, name_buffer_len, oldest_file_name);
+    require_action(dump_file_count >= 0, error,
+                   LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "find_oldest_state_dump fails"));
+
+    ret = remove_state_dump_if_too_many(dump_dir, oldest_file_name, dump_file_count, MAX_NUM_DUMP_FILES);
+    require_action(ret == 0, error,
+                   LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "remove_state_dump_if_too_many fails"));
+
+    int fd = create_new_state_dump_file(dump_dir, file_name, full_file_name, name_buffer_len);
+    require_action(fd >= 0, error,
+                   LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "create_new_state_dump_file fails"));
+
+    dump_state_to_fd(fd);
+    close(fd); // create_new_state_dump_file open the file, we have to close it here
+
+    if (if_compress) {
+        ret = compress_state_dump_and_delete(full_file_name, name_buffer_len);
+        require_action(ret == 0, error,
+                       LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT, "State Dump: Error happens when trying to compress the state dump, reason: %s", strerror(errno)));
+    }
+
+    return 0;
+
+error:
+    return -1;
+}
+
+/*
+ * Scan the directory, find all the files that start with <mDNSResponder state dump file name>. Return the number of
+ * state dump files and the name of the oldest file created.
+ */
+mDNSlocal mDNSs32 find_oldest_state_dump(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len,
+                                         char *oldest_file_name)
+{
+    int ret;
+
+    full_file_name[0] = '\0';
+    full_file_name[buffer_len - 1]= '\0';
+    snprintf(full_file_name, buffer_len - 1, "%s/%s", dump_dir, file_name);
+
+    DIR *dir_p = opendir(dump_dir);
+    if (dir_p == mDNSNULL) {
+        LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+                  "State Dump: directory " PUB_S " cannot be opened, reason: " PUB_S, dump_dir, strerror(errno));
+        return -1;
+    }
+
+    // scan every entry under directory, if starts with <mDNSResponder state dump file name>, check its create time.
+    struct dirent   *dir_entry_p = mDNSNULL;
+    mDNSu32         file_name_len = strnlen(file_name, MAXPATHLEN);
+    mDNSu8          dump_file_count = 0;
+    struct timespec oldest_time = {LONG_MAX, LONG_MAX};
+
+    while ((dir_entry_p = readdir(dir_p)) != mDNSNULL) {
+        if (dir_entry_p->d_namlen <= file_name_len)
+            continue;
+
+        if (strncmp(dir_entry_p->d_name, file_name, file_name_len) == 0) {
+            struct stat file_state;
+            snprintf(full_file_name, buffer_len - 1, "%s/%s", dump_dir, dir_entry_p->d_name);
+
+            // use stat to get creation time
+            ret = stat(full_file_name, &file_state);
+            if (ret != 0) {
+                LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+                          "State Dump: error when reading file properties, reason: " PUB_S, strerror(errno));
+                return -1;
+            }
+            // if the file is older than the current record
+            if (oldest_time.tv_sec > file_state.st_birthtimespec.tv_sec
+                || (oldest_time.tv_sec == file_state.st_birthtimespec.tv_sec
+                    && oldest_time.tv_sec > file_state.st_birthtimespec.tv_sec)) {
+                oldest_time = file_state.st_birthtimespec;
+                strncpy(oldest_file_name, dir_entry_p->d_name, MIN(PATH_MAX - 1, dir_entry_p->d_namlen + 1));
+            }
+
+            dump_file_count++;
+        }
+    }
+    closedir(dir_p);
+
+    return dump_file_count;
+}
+
+mDNSlocal mDNSs8 remove_state_dump_if_too_many(const char *dump_dir, const char *oldest_file_name, mDNSs32 dump_file_count,
+                                               mDNSs32 max_allowed)
+{
+    char path_file_to_remove[PATH_MAX];
+    path_file_to_remove[PATH_MAX - 1] = '\0';
+    // If the number of state dump files has reached the maximum value, we delete the oldest one.
+    if (dump_file_count == max_allowed) {
+        // construct the full name
+        snprintf(path_file_to_remove, PATH_MAX - 1, "%s/%s", dump_dir, oldest_file_name);
+        if (remove(path_file_to_remove) != 0) {
+            LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEFAULT,
+                      "State Dump: file " PUB_S " cannot be deleted, reason: " PUB_S, path_file_to_remove, strerror(errno));
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
+/*
+ * Generate the file name of state dump with current time stamp, and return the FILE pointer, anyone who calls this
+ * function must call fclose() to release the FILE pointer.
+ */
+mDNSlocal int create_new_state_dump_file(const char *dump_dir, const char *file_name, char *full_file_name, mDNSu32 buffer_len)
+{
+    struct timeval      now;
+    struct tm           local_time;
+    char                date_time_str[32];
+    char                time_zone_str[32];
+
+    gettimeofday(&now, NULL);
+    localtime_r(&now.tv_sec, &local_time);
+
+    // 2008-08-08_20-00-00
+    strftime(date_time_str, sizeof(date_time_str), "%F_%H-%M-%S", &local_time);
+    // +0800
+    strftime(time_zone_str, sizeof(time_zone_str), "%z", &local_time);
+    // /private/var/log/mDNSResponder/mDNSResponder_state_dump_2008-08-08_20-00-00-000000+0800.txt
+    snprintf(full_file_name, buffer_len, "%s/%s_%s-%06lu%s." STATE_DUMP_PLAIN_SUFFIX,
+             dump_dir, file_name, date_time_str, (unsigned long)now.tv_usec, time_zone_str);
+
+    int fd = open(full_file_name, O_WRONLY | O_CREAT, 0644); // 0644 means * (owning) User: read & write * Group: read * Other: read
+    if (fd < 0) {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "State Dump: file " PUB_S " cannot be opened, reason: " PUB_S, full_file_name, strerror(errno));
+        return -1;
+    }
+
+    return fd;
+}
+
+/*
+ * Compress the state dump from pliantext to tar.bz2, remove the original one, and change the content of input_file to
+ * newly created compressed file if compression succeeds.
+ */
+mDNSlocal mDNSs8 compress_state_dump_and_delete(char *input_file, mDNSu32 buffer_len)
+{
+    struct archive          *a = mDNSNULL;
+    struct archive_entry    *entry = mDNSNULL;
+    struct stat             st;
+    int                     fd = -1;
+    char                    output_file[PATH_MAX];
+    void                    *mapped_pointer = mDNSNULL;
+    int                     ret;
+
+    output_file[PATH_MAX - 1] = '\0';
+
+    a = archive_write_new();
+    require_action(a != mDNSNULL, error,
+                   LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_new fails: " PUB_S, archive_error_string(a)));
+    archive_write_add_filter_bzip2(a);
+    archive_write_set_format_ustar(a);
+
+    // remove the .txt suffix, and append .tar.bz2 suffix
+    mDNSu32 plain_file_name_len = strlen(input_file); // input_file is guaranteed to be '\0'-terminated
+    strncpy(output_file, input_file, plain_file_name_len - sizeof(STATE_DUMP_PLAIN_SUFFIX));
+    output_file[plain_file_name_len - sizeof(STATE_DUMP_PLAIN_SUFFIX)] = '\0';
+    strncat(output_file, "." STATE_DUMP_COMPRESSED_SUFFIX, 1 + sizeof(STATE_DUMP_COMPRESSED_SUFFIX));
+
+    // open/create the archive for the given path name
+    ret = archive_write_open_filename(a, output_file);
+    require_action(ret == ARCHIVE_OK, error,
+                   LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_open_filename fails: " PUB_S, archive_error_string(a)));
+
+    // get the state of file to be compressed
+    stat(input_file, &st);
+
+    // entry is required to create an archive
+    entry = archive_entry_new();
+    require_action(entry != mDNSNULL, error,
+                   LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_entry_new fails: " PUB_S, strerror(errno)));
+
+    // set the name of file in the compressed file
+    const char *file_name_with_timestamp = strstr(input_file, MDSNRESPONDER_STATE_DUMP_FILE_NAME);
+    if (file_name_with_timestamp == mDNSNULL) {
+        file_name_with_timestamp = MDSNRESPONDER_STATE_DUMP_FILE_NAME "." STATE_DUMP_PLAIN_SUFFIX;
+    }
+
+    // copy the original file state to entry
+    archive_entry_copy_stat(entry, &st);
+    archive_entry_set_pathname(entry, file_name_with_timestamp);
+
+    // write entry into archive
+    do {
+        ret = archive_write_header(a, entry);
+    } while (ret == ARCHIVE_RETRY);
+    require_action(ret == ARCHIVE_OK, error,
+                   LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_header fails: " PUB_S, archive_error_string(a)));
+
+    // if the original file has something to compress, use mmap to read its content
+    if (st.st_size > 0) {
+        fd = open(input_file, O_RDONLY);
+
+        mapped_pointer = mmap(NULL, st.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+        require_action(mapped_pointer != MAP_FAILED, error,
+                       LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "mmap fails: " PUB_S, strerror(errno)));
+
+        mDNSu32 amount_written = (mDNSu32)archive_write_data(a, mapped_pointer, st.st_size);
+        require_action(amount_written == (mDNSu32)st.st_size, error,
+                       LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "archive_write_data fails: amount_written(%u) != (%u)", amount_written, (mDNSu32)st.st_size));
+
+        int munmap_result = munmap(mapped_pointer, st.st_size);
+        require_action(munmap_result == 0, error,
+                       LogRedact(MDNS_LOG_CATEGORY_XPC, MDNS_LOG_DEBUG, "munmap fails: " PUB_S, strerror(errno)));
+        mapped_pointer = mDNSNULL;
+
+        close(fd);
+        fd = -1; // set the file descriptor to -1 to avoid double free
+    }
+    archive_entry_free(entry);
+    entry = mDNSNULL;
+
+    archive_write_close(a);
+    archive_write_free(a);
+    a = mDNSNULL;
+
+    // remove the original one, return the newly created compressed file name
+    remove(input_file);
+    strncpy(input_file, output_file, buffer_len);
+    input_file[buffer_len - 1] = '\0';
+
+    return 0;
+
+error:
+    if (a != mDNSNULL) {
+        archive_write_close(a);
+        archive_write_free(a);
+    }
+    if (entry != mDNSNULL) {
+        archive_entry_free(entry);
+    }
+    if (fd != -1) {
+        close(fd);
+    }
+    if (mapped_pointer != mDNSNULL) {
+        munmap(mapped_pointer, st.st_size);
+    }
+    remove(input_file);
+    return -1;
+}
+
+/*
+ * Return the time difference(ms) between two struct timeval.
+ */
+#define US_PER_S 1000000
+#define MS_PER_S 1000
+mDNSlocal mDNSs32 timediff_ms(struct timeval* t1, struct timeval* t2)
+{
+    int usec, ms, sec;
+
+    if (t1->tv_sec < t2->tv_sec || (t1->tv_sec == t2->tv_sec && t1->tv_usec < t2->tv_usec))
+        return -timediff_ms(t2, t1);
+
+    sec = (int)(t1->tv_sec - t2->tv_sec);
+    if (t1->tv_usec >= t2->tv_usec)
+        usec = t1->tv_usec - t2->tv_usec;
+    else {
+        usec = t1->tv_usec + US_PER_S - t2->tv_usec;
+        sec -= 1;
+    }
+    ms = sec * MS_PER_S;
+    ms += usec / MS_PER_S;
+    return ms;
+}
diff --git a/mDNSMacOSX/xpc_services/xpc_service_log_utility.h b/mDNSMacOSX/xpc_services/xpc_service_log_utility.h
new file mode 100644 (file)
index 0000000..5dd9201
--- /dev/null
@@ -0,0 +1,18 @@
+//
+//  xpc_service_log_utility.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef XPC_SERVICE_LOG_UTILITY_H
+#define XPC_SERVICE_LOG_UTILITY_H
+
+#include "mDNSEmbeddedAPI.h"
+
+#define MDSNRESPONDER_STATE_DUMP_DIR "/private/var/log/mDNSResponder"
+#define MDSNRESPONDER_STATE_DUMP_FILE_NAME "mDNSResponder_state_dump"
+
+mDNSexport void init_log_utility_service(void);
+
+#endif /* XPC_SERVICE_LOG_UTILITY_H */
diff --git a/mDNSMacOSX/xpc_services/xpc_services.c b/mDNSMacOSX/xpc_services/xpc_services.c
new file mode 100644 (file)
index 0000000..32649f2
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#include "xpc_services.h"
+#include <xpc/private.h>                // xpc_connection_copy_entitlement_value
+
+#include "mDNSMacOSX.h"                 // KQueueLock/KQueueUnlock
+#include "dnsproxy.h"                   // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback
+#include "xpc_service_dns_proxy.h"      // init_dnsproxy_service
+#include "xpc_service_log_utility.h"    // init_dnsctl_service
+
+extern mDNS mDNSStorage;
+
+mDNSexport void xpc_server_init()
+{
+    // add XPC Services here
+    init_dnsproxy_service();
+    init_log_utility_service();
+}
+
+// Utilities
+
+mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *entitlement_name)
+{
+    mDNSBool        entitled = mDNSfalse;
+    xpc_object_t    entitled_obj = xpc_connection_copy_entitlement_value(conn, entitlement_name);
+
+    if (entitled_obj) {
+        if (xpc_get_type(entitled_obj) == XPC_TYPE_BOOL && xpc_bool_get_value(entitled_obj)) {
+            entitled = mDNStrue;
+        }
+        xpc_release(entitled_obj);
+    } else {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "IsEntitled: Client Entitlement is NULL");
+    }
+
+    if (!entitled) {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "IsEntitled: Client is missing Entitlement!");
+    }
+
+    return entitled;
+}
diff --git a/mDNSMacOSX/xpc_services/xpc_services.h b/mDNSMacOSX/xpc_services/xpc_services.h
new file mode 100644 (file)
index 0000000..33b3ba9
--- /dev/null
@@ -0,0 +1,18 @@
+//
+//  xpc_services.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+
+#ifndef XPC_SERVICES_H
+#define XPC_SERVICES_H
+
+#include "mDNSEmbeddedAPI.h"
+#include <xpc/xpc.h>
+
+mDNSexport void xpc_server_init(void);
+mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *password);
+
+#endif // XPC_SERVICES_H
index c0badf43af0632d7b3bb699ca555784bc0feb76c..e756c80e427a996ab68553caf7a9d9203b7bb259 100755 (executable)
 #include <string.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <sys/socket.h>
 
 #include "mDNSEmbeddedAPI.h" // Defines the interface to the mDNS core code
 #include "mDNSPosix.h"    // Defines the specific types needed to run mDNS on this platform
 #include "ExampleClientApp.h"
 
 // Globals
-static mDNS mDNSStorage;       // mDNS core uses this to store its globals
+mDNSexport 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];
@@ -196,7 +197,7 @@ int main(int argc, char **argv)
         MakeDomainNameFromDNSNameString(&type, gServiceType);
         MakeDomainNameFromDNSNameString(&domain, gServiceDomain);
 
-        status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSNULL, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, BrowseCallback, NULL);
+        status = mDNS_StartBrowse(&mDNSStorage, &question, &type, &domain, mDNSInterface_Any, 0, mDNSfalse, mDNSfalse, BrowseCallback, NULL);
 
         // Run the platform main event loop until the user types ^C.
         // The BrowseCallback routine is responsible for printing
index be340912b3d83119fa243891dacb7db4fda9d02a..503751dfbf8bda43f52ec383fcfa3156227def50 100644 (file)
@@ -50,6 +50,7 @@ mDNSexport void ExampleClientEventLoop(mDNS *const m)
     {
         int nfds = 0;
         fd_set readfds;
+        fd_set writefds;
         struct timeval timeout;
         int result;
 
@@ -57,6 +58,7 @@ mDNSexport void ExampleClientEventLoop(mDNS *const m)
         // This example client has no file descriptors of its own,
         // but a real application would call FD_SET to add them to the set here
         FD_ZERO(&readfds);
+        FD_ZERO(&writefds);
 
         // 2. Set up the timeout.
         // This example client has no other work it needs to be doing,
@@ -65,11 +67,11 @@ mDNSexport void ExampleClientEventLoop(mDNS *const m)
         timeout.tv_usec = 0;
 
         // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
-        mDNSPosixGetFDSet(m, &nfds, &readfds, &timeout);
+        mDNSPosixGetFDSet(m, &nfds, &readfds, &writefds, &timeout);
 
         // 4. Call select as normal
         verbosedebugf("select(%d, %d.%06d)", nfds, timeout.tv_sec, timeout.tv_usec);
-        result = select(nfds, &readfds, NULL, NULL, &timeout);
+        result = select(nfds, &readfds, &writefds, NULL, &timeout);
 
         if (result < 0)
         {
@@ -79,7 +81,7 @@ mDNSexport void ExampleClientEventLoop(mDNS *const m)
         else
         {
             // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
-            mDNSPosixProcessFDSet(m, &readfds);
+            mDNSPosixProcessFDSet(m, &readfds, &writefds);
 
             // 6. This example client has no other work it needs to be doing,
             // but a real client would do its work here
index 6a5d362b936880d91ddc4e47b6d55cb1868e83bd..24c08bc49c3920a4da945fbc92628b8b4dd64d86 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2002-2018 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.
@@ -46,7 +46,7 @@
 //*************************************************************************************************************
 // Globals
 
-static mDNS mDNSStorage;       // mDNS core uses this to store its globals
+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];
@@ -173,11 +173,12 @@ mDNSlocal void WaitForAnswer(mDNS *const m, int seconds)
     while (!StopNow)
     {
         int nfds = 0;
-        fd_set readfds;
+        fd_set readfds, writefds;
         struct timeval now, remain = end;
         int result;
 
         FD_ZERO(&readfds);
+        FD_ZERO(&writefds);
         gettimeofday(&now, NULL);
         if (remain.tv_usec < now.tv_usec) { remain.tv_usec += 1000000; remain.tv_sec--; }
         if (remain.tv_sec < now.tv_sec)
@@ -187,9 +188,9 @@ mDNSlocal void WaitForAnswer(mDNS *const m, int seconds)
         }
         remain.tv_usec -= now.tv_usec;
         remain.tv_sec  -= now.tv_sec;
-        mDNSPosixGetFDSet(m, &nfds, &readfds, &remain);
-        result = select(nfds, &readfds, NULL, NULL, &remain);
-        if (result >= 0) mDNSPosixProcessFDSet(m, &readfds);
+        mDNSPosixGetFDSet(m, &nfds, &readfds, &writefds, &remain);
+        result = select(nfds, &readfds, &writefds, NULL, &remain);
+        if (result >= 0) mDNSPosixProcessFDSet(m, &readfds, &writefds);
         else if (errno != EINTR) StopNow = 2;
     }
 }
@@ -210,17 +211,13 @@ mDNSlocal mStatus StartQuery(DNSQuestion *q, char *qname, mDNSu16 qtype, const m
     q->ForceMCast       = mDNStrue;     // Query via multicast, even for apparently uDNS names like 1.1.1.17.in-addr.arpa.
     q->ReturnIntermed   = mDNStrue;
     q->SuppressUnusable = mDNSfalse;
-    q->SearchListIndex  = 0;
     q->AppendSearchDomains = 0;
-    q->RetryWithSearchDomains = mDNSfalse;
     q->TimeoutQuestion  = 0;
     q->ValidationRequired = 0;
     q->ValidatingResponse = 0;
     q->WakeOnResolve    = 0;
-    q->UseBackgroundTrafficClass = mDNSfalse;
+    q->UseBackgroundTraffic = mDNSfalse;
     q->ProxyQuestion    = 0;
-    q->qnameOrig        = mDNSNULL;
-    q->AnonInfo         = mDNSNULL;
     q->pid              = mDNSPlatformGetPID();
     q->QuestionCallback = callback;
     q->QuestionContext  = NULL;
index 4f98e90f4258beef5278e9a8c78493e35cfe8e18..78222e08572dd0662a16f1089d2e0abe1adf5aa8 100755 (executable)
@@ -1,6 +1,6 @@
 # -*- tab-width: 4 -*-
 #
-# Copyright (c) 2002-2004, 2015, Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2002-2019 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:
@@ -52,47 +52,69 @@ LIBVERS = 1
 
 COREDIR = ../mDNSCore
 SHAREDDIR ?= ../mDNSShared
+DSODIR ?= ../DSO
 JDK = /usr/jdk
 
-CC = @cc
-BISON = @bison
-FLEX = @flex
-ST = @strip
-LD = ld -shared
+SYSTEM := $(shell uname -s)
+ifeq ($(SYSTEM), Darwin)
+  os=x
+else ifeq ($(SYSTEM), Linux)
+  os=linux
+endif
+
+CC = cc
+BISON = bison
+FLEX = flex
+ST = strip
+LD = ld
+SOOPTS = -shared
 CP = cp
 RM = rm
 LN = ln -s -f
-CFLAGS_COMMON = -I$(COREDIR) -I$(SHAREDDIR) -I$(OBJDIR) -fwrapv -W -Wall -DPID_FILE=\"/var/run/mdnsd.pid\" -DMDNS_UDS_SERVERPATH=\"/var/run/mdnsd\"
+CFLAGS_COMMON = -I$(COREDIR) -I$(SHAREDDIR) -I$(DSODIR) -I$(PROXYDIR) -I$(OBJDIR) -fwrapv -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
 
+ifeq "$(OPEN_SOURCE)" "1"
+CFLAGS_OPEN_SOURCE=-D__OPEN_SOURCE__
+else
+CFLAGS_OPEN_SOURCE=
+endif
+
 # Set up diverging paths for debug vs. prod builds
-DEBUG=0
-ifeq ($(DEBUG),1)
-CFLAGS_DEBUG = -g -DMDNS_DEBUGMSGS=2
+ifeq "$(DEBUG)" "1"
+CFLAGS_DEBUGGING = -g -DMDNS_DEBUGMSGS=2
 OBJDIR = objects/debug
 BUILDDIR = build/debug
 STRIP = echo
 else
+ifeq "$(DEBUGSYMS)" "1"
+CFLAGS_DEBUGGING = -g -DMDNS_DEBUGMSGS=0
+OBJDIR = objects/prod
+BUILDDIR = build/prod
+STRIP = echo
+else
 # We use -Os for two reasons:
 # 1. We want to make small binaries, suitable for putting into hardware devices
 # 2. Some of the code analysis warnings only work when some form of optimization is enabled
-CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0
+CFLAGS_DEBUGGING = -g -DMDNS_DEBUGMSGS=0
 OBJDIR ?= objects/prod
 BUILDDIR ?= build/prod
 STRIP = $(ST) -S
 endif
+endif
 
 # Configure per-OS peculiarities
 ifeq ($(os),solaris)
-CFLAGS_DEBUG = -O0 -DMDNS_DEBUGMSGS=0
+CFLAGS_DEBUGGING = -O0 -DMDNS_DEBUGMSGS=0
 CFLAGS_OS = -DNOT_HAVE_DAEMON -DNOT_HAVE_SA_LEN -DNOT_HAVE_SOCKLEN_T -DNOT_HAVE_IF_NAMETOINDEX \
         -DLOG_PERROR=0 -D_XPG4_2 -D__EXTENSIONS__ -DHAVE_BROKEN_RECVIF_NAME -DTARGET_OS_SOLARIS
 CC = gcc
-LD = gcc -shared
+LD = gcc
+SOOPTS = -shared
 LINKOPTS = -lsocket -lnsl -lresolv
 JAVACFLAGS_OS += -I$(JDK)/include/solaris
 ifneq ($(DEBUG),1)
@@ -102,8 +124,9 @@ else
 
 # any target that contains the string "linux"
 ifeq ($(findstring linux,$(os)),linux)
-CFLAGS_OS = -D_GNU_SOURCE -DHAVE_IPV6 -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX -fno-strict-aliasing
-LD = $(CC) -shared
+CFLAGS_OS = -D_GNU_SOURCE -DHAVE_IPV6 -DNOT_HAVE_SA_LEN -DUSES_NETLINK -DHAVE_LINUX -DTARGET_OS_LINUX -ftabstop=4
+LD = $(CC)
+SOOPTS = -shared
 FLEXFLAGS_OS = -l
 JAVACFLAGS_OS += -I$(JDK)/include/linux
 
@@ -146,10 +169,11 @@ ifeq ($(os),x)
 # we get build failures: ‘daemon’ is deprecated (declared at /usr/include/stdlib.h:283)
 CFLAGS_OS = -DHAVE_IPV6 -no-cpp-precomp -Werror -Wdeclaration-after-statement \
        -D__MAC_OS_X_VERSION_MIN_REQUIRED=__MAC_OS_X_VERSION_10_4 \
-       -DHAVE_STRLCPY=1 \
+       -DHAVE_STRLCPY=1 -DTARGET_OS_MAC \
        -D__APPLE_USE_RFC_2292 #-Wunreachable-code
 CC = gcc
-LD = $(CC) -dynamiclib
+LD = $(CC)
+SOOPTS = -dynamiclib
 LINKOPTS = -lSystem
 LDSUFFIX = dylib
 JDK = /System/Library/Frameworks/JavaVM.framework/Home
@@ -174,6 +198,7 @@ NSSINSTPATH := /lib
 
 # If not otherwise defined, we install into /usr/lib and /usr/include
 # and our startup script is called mdns (e.g. /etc/init.d/mdns)
+ETCBASE?=/etc
 INSTBASE?=/usr
 STARTUPSCRIPTNAME?=mdns
 
@@ -213,11 +238,11 @@ endif
 endif
 endif
 
-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUG)
+MDNSCFLAGS = $(CFLAGS) $(CFLAGS_COMMON) $(CFLAGS_OS) $(CFLAGS_DEBUGGING) $(CFLAGS_OPEN_SOURCE)
 
 #############################################################################
 
-all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder Identify NetMonitor $(OPTIONALTARG)
+all: setup Daemon libdns_sd Clients SAClient SAResponder SAProxyResponder NetMonitor $(OPTIONALTARG)
 
 install: setup InstalledStartup InstalledDaemon InstalledLib InstalledManPages InstalledClients $(OPTINSTALL)
 
@@ -237,8 +262,10 @@ clean:
 # daemon target builds the daemon
 DAEMONOBJS = $(OBJDIR)/PosixDaemon.c.o $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNS.c.o \
              $(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 \
-                        $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/anonymous.c.o
+             $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/dnssd_ipc.c.o $(OBJDIR)/GenLinkedList.c.o \
+             $(OBJDIR)/PlatformCommon.c.o $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/ClientRequests.c.o \
+             $(OBJDIR)/dso.c.o $(OBJDIR)/dso-transport.c.o $(OBJDIR)/dnssd_clientshim.c.o \
+             $(OBJDIR)/posix_utilities.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 \
@@ -250,7 +277,7 @@ Daemon: setup $(BUILDDIR)/mdnsd
 
 $(BUILDDIR)/mdnsd: $(DAEMONOBJS)
        $(CC) -o $@ $+ $(LINKOPTS)
-       @$(STRIP) $@
+       $(STRIP) $@
 
 # libdns_sd target builds the client library
 libdns_sd: setup $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
@@ -259,22 +286,22 @@ 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) $(LINKOPTS) -o $@ $+
-       @$(STRIP) $@
+       $(LD) $(SOOPTS) $(LINKOPTS) -o $@ $+
+       $(STRIP) $@
 
 Clients: setup libdns_sd ../Clients/build/dns-sd
        @echo "Clients done"
 
-../Clients/build/dns-sd:
-       @$(MAKE) -C ../Clients
+../Clients/build/dns-sd: ../Clients/dns-sd.c
+       $(MAKE) -C ../Clients DEBUG=$(DEBUG) SUPMAKE_CFLAGS="$(MDNSCFLAGS)"
 
 # 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) $(LINKOPTS) -o $@ $+
-       @$(STRIP) $@
+       $(LD) $(SOOPTS) $(LINKOPTS) -o $@ $+
+       $(STRIP) $@
 
 #############################################################################
 
@@ -299,15 +326,15 @@ InstalledNSS: $(NSSINSTPATH)/$(NSSLINKNAME) /etc/nss_mdns.conf $(MANPATH)/man5/n
 
 # Note: If daemon already installed, we make sure it's stopped before overwriting it
 $(INSTBASE)/sbin/mdnsd: $(BUILDDIR)/mdnsd $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME)
-       @if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi
+       if test -x $@; then $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) stop; fi
        $(CP) $< $@
-       @$(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) start
+       $(STARTUPSCRIPTDIR)/$(STARTUPSCRIPTNAME) start
 
 $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX).$(LIBVERS): $(BUILDDIR)/libdns_sd.$(LDSUFFIX)
        $(CP) $< $@
        $(LN) $@ $(INSTBASE)/lib/libdns_sd.$(LDSUFFIX)
 ifdef LDCONFIG
-    # -m means 'merge into existing database', -R means 'rescan directories'
+       # -m means 'merge into existing database', -R means 'rescan directories'
        $(LDCONFIG) -mR
 endif
 
@@ -356,8 +383,8 @@ $(NSSINSTPATH)/$(NSSLIBFILE): $(BUILDDIR)/$(NSSLIBFILE)
 /etc/nss_mdns.conf: nss_mdns.conf
        $(CP) $< $@
        chmod 444 $@
-       # Check the nsswitch.conf file.
-       # If 'mdns' does not already appear on the "hosts:" line, then add it right before 'dns'
+# Check the nsswitch.conf file.
+# If 'mdns' does not already appear on the "hosts:" line, then add it right before 'dns'
        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
 
@@ -370,11 +397,11 @@ JAVAC = $(JDK)/bin/javac
 JAVAH = $(JDK)/bin/javah
 JAVADOC = $(JDK)/bin/javadoc
 JAR = $(JDK)/bin/jar
-JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS) -I$(JDK)/include
+JAVACFLAGS = $(MDNSCFLAGS) $(JAVACFLAGS_OS) -I$(JDK)/include
 
 JavaForXcode_: setup $(BUILDDIR)/dns_sd.jar $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h
        @echo $@ done
-       
+
 $(PROJECT_DERIVED_FILE_DIR)/DNSSD.java.h: $(OBJDIR)/DNSSD.java.h
        @if test ! -d $(PROJECT_DERIVED_FILE_DIR) ; then mkdir -p $(PROJECT_DERIVED_FILE_DIR) ; fi
        $(CP) $< $@
@@ -447,7 +474,7 @@ JavaDoc: Java setup
 # The following targets build embedded example programs
 SPECIALOBJ = $(OBJDIR)/mDNSPosix.c.o $(OBJDIR)/mDNSUNP.c.o $(OBJDIR)/mDNSDebug.c.o $(OBJDIR)/GenLinkedList.c.o \
        $(OBJDIR)/DNSDigest.c.o $(OBJDIR)/uDNS.c.o $(OBJDIR)/DNSCommon.c.o $(OBJDIR)/PlatformCommon.c.o \
-       $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/anonymous.c.o
+       $(OBJDIR)/CryptoAlg.c.o $(OBJDIR)/dso.c.o $(OBJDIR)/dso-transport.c.o $(OBJDIR)/dnssd_clientshim.c.o
 COMMONOBJ  = $(SPECIALOBJ) $(OBJDIR)/mDNS.c.o
 APPOBJ     = $(COMMONOBJ) $(OBJDIR)/ExampleClientApp.c.o
 
@@ -460,9 +487,6 @@ SAResponder: setup $(BUILDDIR)/mDNSResponderPosix
 SAProxyResponder: setup $(BUILDDIR)/mDNSProxyResponderPosix
        @echo "Embedded Standalone ProxyResponder done"
 
-Identify: setup $(BUILDDIR)/mDNSIdentify
-       @echo "Identify done"
-
 NetMonitor: setup $(BUILDDIR)/mDNSNetMonitor
        @echo "NetMonitor done"
 
@@ -478,11 +502,6 @@ $(BUILDDIR)/mDNSResponderPosix:      $(COMMONOBJ)  $(OBJDIR)/Responder.c.o
 $(BUILDDIR)/mDNSProxyResponderPosix: $(COMMONOBJ)  $(OBJDIR)/ProxyResponder.c.o
        $(CC) $+ -o $@ $(LINKOPTS)
 
-$(BUILDDIR)/mDNSIdentify:            $(SPECIALOBJ) $(OBJDIR)/Identify.c.o
-       $(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 $@ $(LINKOPTS)
 
@@ -495,30 +514,33 @@ $(BUILDDIR)/dnsextd:                 $(DNSEXTDOBJ) $(OBJDIR)/dnsextd.c.threadsaf
 
 # Implicit rules
 $(OBJDIR)/%.c.o:       %.c
-       $(CC) $(CFLAGS) -c -o $@ $<
+       $(CC) $(MDNSCFLAGS) -c -o $@ $<
 
 $(OBJDIR)/%.c.o:       $(COREDIR)/%.c
-       $(CC) $(CFLAGS) -c -o $@ $<
+       $(CC) $(MDNSCFLAGS) -c -o $@ $<
 
 $(OBJDIR)/%.c.o:       $(SHAREDDIR)/%.c
-       $(CC) $(CFLAGS) -c -o $@ $<
+       $(CC) $(MDNSCFLAGS) -c -o $@ $<
+
+$(OBJDIR)/%.c.o:       $(DSODIR)/%.c
+       $(CC) $(MDNSCFLAGS) -c -o $@ $<
 
 $(OBJDIR)/%.c.threadsafe.o:    %.c
-       $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+       $(CC) $(MDNSCFLAGS) $(MDNSCFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
 
 $(OBJDIR)/%.c.threadsafe.o:    $(SHAREDDIR)/%.c
-       $(CC) $(CFLAGS) $(CFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
+       $(CC) $(MDNSCFLAGS) $(MDNSCFLAGS_PTHREAD) -D_REENTRANT -c -o $@ $<
 
 $(OBJDIR)/%.c.so.o:    %.c
-       $(CC) $(CFLAGS) -c -fPIC -o $@ $<
+       $(CC) $(MDNSCFLAGS) -c -fPIC -o $@ $<
 
 $(OBJDIR)/%.c.so.o:    $(SHAREDDIR)/%.c
-       $(CC) $(CFLAGS) -c -fPIC -o $@ $<
+       $(CC) $(MDNSCFLAGS) -c -fPIC -o $@ $<
 
 $(OBJDIR)/%.y.o: $(SHAREDDIR)/%.y
        $(BISON)              -o $(OBJDIR)/$*.c -d $<
-       $(CC) $(CFLAGS) -c -o $@ $(OBJDIR)/$*.c
+       $(CC) $(MDNSCFLAGS) -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
+       $(CC) $(MDNSCFLAGS) -Wno-error -c -o $@ $(OBJDIR)/$*.l.c
index 418aaddae75e85cb9e646f547414a8d89da00d96..5a93de6c778b76b9f56581a42f21fe3e765fb603 100644 (file)
@@ -314,7 +314,7 @@ mDNSlocal void SendUnicastQuery(mDNS *const m, HostEntry *entry, domainname *nam
         InterfaceID = mDNSInterface_Any;    // Send query from our unicast reply socket
     }
 
-    mDNSSendDNSMessage(m, &query, qptr, InterfaceID, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSNULL, mDNSfalse);
+    mDNSSendDNSMessage(m, &query, qptr, InterfaceID, mDNSNULL, mDNSNULL, target, MulticastDNSPort, mDNSNULL, mDNSfalse);
 }
 
 mDNSlocal void AnalyseHost(mDNS *const m, HostEntry *entry, const mDNSInterfaceID InterfaceID)
@@ -531,8 +531,8 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
     // Perhaps more (or all?) of the cases should do that?
     switch(pktrr->rrtype)
     {
-    case kDNSType_A:    n += mprintf("%.4a", &rd->ipv4); break;
-    case kDNSType_PTR:  n += mprintf("%##.*s", MaxWidth - n, rd->name.c); break;
+    case kDNSType_A:    mprintf("%.4a", &rd->ipv4); break;
+    case kDNSType_PTR:  mprintf("%##.*s", MaxWidth - n, rd->name.c); break;
     case kDNSType_HINFO:    // same as kDNSType_TXT below
     case kDNSType_TXT:  {
         mDNSu8 *t = rd->txt.c;
@@ -556,10 +556,10 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
             if (t < rdend && t[0]) { *p++ = '\\'; *p++ = ' '; }
         }
         *p++ = 0;
-        n += mprintf("%.*s", MaxWidth - n, buffer);
+        mprintf("%.*s", MaxWidth - n, buffer);
     } break;
-    case kDNSType_AAAA: n += mprintf("%.16a", &rd->ipv6); break;
-    case kDNSType_SRV:  n += mprintf("%##s:%d", rd->srv.target.c, mDNSVal16(rd->srv.port)); break;
+    case kDNSType_AAAA: mprintf("%.16a", &rd->ipv6); break;
+    case kDNSType_SRV:  mprintf("%##s:%d", rd->srv.target.c, mDNSVal16(rd->srv.port)); break;
     case kDNSType_OPT:  {
         char b[MaxMsg];
         // Quick hack: we don't want the prefix that GetRRDisplayString_rdb puts at the start of its
@@ -567,14 +567,14 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
         // length of that prefix and strip that many bytes off the beginning of the string we display.
         mDNSu32 striplen = mDNS_snprintf(b, MaxMsg-1, "%4d %##s %s ", pktrr->rdlength, pktrr->name->c, DNSTypeName(pktrr->rrtype));
         GetRRDisplayString_rdb(pktrr, &pktrr->rdata->u, b);
-        n += mprintf("%.*s", MaxWidth - n, b + striplen);
+        mprintf("%.*s", MaxWidth - n, b + striplen);
     } break;
     case kDNSType_NSEC: {
         char b[MaxMsg];
         // See the quick hack above
         mDNSu32 striplen = mDNS_snprintf(b, MaxMsg-1, "%4d %##s %s ", pktrr->rdlength, pktrr->name->c, DNSTypeName(pktrr->rrtype));
         GetRRDisplayString_rdb(pktrr, &pktrr->rdata->u, b);
-        n += mprintf("%s", b+striplen);
+        mprintf("%s", b+striplen);
     } break;
     default:            {
         mDNSu8 *s = rd->data;
@@ -593,7 +593,7 @@ mDNSlocal void DisplayResourceRecord(const mDNSAddr *const srcaddr, const char *
             s++;
         }
         *p++ = 0;
-        n += mprintf("%.*s", MaxWidth - n, buffer);
+        mprintf("%.*s", MaxWidth - n, buffer);
     } break;
     }
 
index 295e842121439699e44e0426ebd815e55eb55311..de76034c3f8bd6b01fce7817bc1837d83fa94b8e 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
@@ -37,6 +36,7 @@
 #include <fcntl.h>
 #include <pwd.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #if __APPLE__
 #undef daemon
@@ -48,6 +48,7 @@ extern int daemon(int, int);
 #include "mDNSUNP.h"        // For daemon()
 #include "uds_daemon.h"
 #include "PlatformCommon.h"
+#include "posix_utilities.h"    // For getLocalTimestamp()
 
 #define CONFIG_FILE "/etc/mdnsd.conf"
 static domainname DynDNSZone;                // Default wide-area zone for service registration
@@ -121,9 +122,19 @@ mDNSlocal void ParseCmdLinArgs(int argc, char **argv)
 mDNSlocal void DumpStateLog()
 // Dump a little log of what we've been up to.
 {
-       LogMsg("---- BEGIN STATE LOG ----");
-    udsserver_info();
-    LogMsg("----  END STATE LOG  ----");
+    char timestamp[64]; // 64 is enough to store the UTC timestmp
+    
+    mDNSu32 major_version = _DNS_SD_H / 10000;
+    mDNSu32 minor_version1 = (_DNS_SD_H - major_version * 10000) / 100;
+    mDNSu32 minor_version2 = _DNS_SD_H % 100;
+
+    getLocalTimestamp(timestamp, sizeof(timestamp));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- BEGIN STATE LOG ---- (%s mDNSResponder Build %d.%02d.%02d)", timestamp, major_version, minor_version1, minor_version2);
+
+    udsserver_info_dump_to_fd(STDERR_FILENO);
+
+    getLocalTimestamp(timestamp, sizeof(timestamp));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "---- END STATE LOG ---- (%s mDNSResponder Build %d.%02d.%02d)", timestamp, major_version, minor_version1, minor_version2);
 }
 
 mDNSlocal mStatus MainLoop(mDNS *m) // Loop until we quit.
@@ -189,9 +200,21 @@ int main(int argc, char **argv)
     {
         const struct passwd *pw = getpwnam("nobody");
         if (pw != NULL)
-            setuid(pw->pw_uid);
+        {
+            if (setgid(pw->pw_gid) < 0)
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                          "WARNING: mdnsd continuing as group root because setgid to \"nobody\" failed with " PUB_S, strerror(errno));
+            }
+            if (setuid(pw->pw_uid) < 0)
+            {
+                LogMsg("WARNING: mdnsd continuing as root because setuid to \"nobody\" failed with %s", strerror(errno));
+            }
+        }
         else
+        {
             LogMsg("WARNING: mdnsd continuing as root because user \"nobody\" does not exist");
+        }
     }
 
     if (mStatus_NoError == err)
@@ -205,7 +228,7 @@ int main(int argc, char **argv)
         LogMsg("ExitCallback: udsserver_exit failed");
 
  #if MDNS_DEBUGMSGS > 0
-    printf("mDNSResponder exiting normally with %ld\n", err);
+    printf("mDNSResponder exiting normally with %d\n", err);
  #endif
 
     return err;
index 94fde85593eda58329834d5e5aedea33a21bb682..7b2305fa69642d555229ee6d8bf6facc6db03706 100644 (file)
@@ -36,7 +36,7 @@
 
 //*************************************************************************************************************
 // Globals
-static mDNS mDNSStorage;       // mDNS core uses this to store its globals
+mDNS mDNSStorage;       // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
 mDNSexport const char ProgramName[] = "mDNSProxyResponderPosix";
 
index d4e20104c71f476b33201ffd644122bb4ecadf67..119c4987a8d97086b5089bd4bb6bb7ed5dde41e7 100755 (executable)
@@ -31,6 +31,7 @@
 #include <errno.h>          // For errno, EINTR
 #include <signal.h>
 #include <fcntl.h>
+#include <sys/socket.h>
 
 #if __APPLE__
 #undef daemon
@@ -45,7 +46,7 @@ extern int daemon(int, int);
 #pragma mark ***** Globals
 #endif
 
-static mDNS mDNSStorage;       // mDNS core uses this to store its globals
+mDNS mDNSStorage;       // mDNS core uses this to store its globals
 static mDNS_PlatformSupport PlatformStorage;  // Stores this platform's globals
 
 mDNSexport const char ProgramName[] = "mDNSResponderPosix";
@@ -428,7 +429,7 @@ static mStatus RegisterOneService(const char *  richTextName,
     domainname domain;
 
     status = mStatus_NoError;
-    thisServ = (PosixService *) malloc(sizeof(*thisServ));
+    thisServ = (PosixService *) calloc(sizeof(*thisServ), 1);
     if (thisServ == NULL) {
         status = mStatus_NoMemoryErr;
     }
@@ -631,14 +632,11 @@ static mStatus RegisterOurServices(void)
 static void DeregisterOurServices(void)
 {
     PosixService *thisServ;
-    int thisServID;
 
     while (gServiceList != NULL) {
         thisServ = gServiceList;
         gServiceList = thisServ->next;
 
-        thisServID = thisServ->serviceID;
-
         mDNS_DeregisterService(&mDNSStorage, &thisServ->coreServ);
 
         if (gMDNSPlatformPosixVerboseLevel > 0) {
@@ -711,7 +709,7 @@ int main(int argc, char **argv)
     while (!gStopNow)
     {
         int nfds = 0;
-        fd_set readfds;
+        fd_set readfds, writefds;
         struct timeval timeout;
         int result;
 
@@ -719,6 +717,7 @@ int main(int argc, char **argv)
         // This example client has no file descriptors of its own,
         // but a real application would call FD_SET to add them to the set here
         FD_ZERO(&readfds);
+        FD_ZERO(&writefds);
 
         // 2. Set up the timeout.
         // This example client has no other work it needs to be doing,
@@ -727,7 +726,7 @@ int main(int argc, char **argv)
         timeout.tv_usec = 0;
 
         // 3. Give the mDNSPosix layer a chance to add its information to the fd_set and timeout
-        mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &timeout);
+        mDNSPosixGetFDSet(&mDNSStorage, &nfds, &readfds, &writefds, &timeout);
 
         // 4. Call select as normal
         verbosedebugf("select(%d, %d.%06d)", nfds, timeout.tv_sec, timeout.tv_usec);
@@ -764,7 +763,7 @@ int main(int argc, char **argv)
         else
         {
             // 5. Call mDNSPosixProcessFDSet to let the mDNSPosix layer do its work
-            mDNSPosixProcessFDSet(&mDNSStorage, &readfds);
+            mDNSPosixProcessFDSet(&mDNSStorage, &readfds, &writefds);
 
             // 6. This example client has no other work it needs to be doing,
             // but a real client would do its work here
index 308252fb8341feebd679a0e248b58763dfbe9300..9793195e84ab32da12c870a097ad2314383dad37 100755 (executable)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2019 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.
@@ -19,6 +19,7 @@
 #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 "PlatformCommon.h"
 #include "dns_sd.h"
 #include "dnssec.h"
 #include "nsec.h"
@@ -40,6 +41,7 @@
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <time.h>                   // platform support for UTC time
+#include <ifaddrs.h>
 
 #if USES_NETLINK
 #include <asm/types.h>
 // ***************************************************************************
 // Structures
 
-// We keep a list of client-supplied event sources in PosixEventSource records
-struct PosixEventSource
-{
-    mDNSPosixEventCallback Callback;
-    void                        *Context;
-    int fd;
-    struct  PosixEventSource    *Next;
-};
-typedef struct PosixEventSource PosixEventSource;
-
 // Context record for interface change callback
 struct IfChangeRec
 {
@@ -76,9 +68,7 @@ struct IfChangeRec
 typedef struct IfChangeRec IfChangeRec;
 
 // Note that static data is initialized to zero in (modern) C.
-static fd_set gEventFDs;
-static int gMaxFD;                              // largest fd in gEventFDs
-static GenLinkedList gEventSources;             // linked list of PosixEventSource's
+static PosixEventSource *gEventSources;             // linked list of PosixEventSource's
 static sigset_t gEventSignalSet;                // Signals which event loop listens for
 static sigset_t gEventSignals;                  // Signals which were received while inside loop
 
@@ -91,9 +81,23 @@ static int num_registered_interfaces = 0;
 static int num_pkts_accepted = 0;
 static int num_pkts_rejected = 0;
 
+// ***************************************************************************
+// Locals
+mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
+                                    const char *taskName, mDNSPosixEventCallback callback, void *context);
+mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeSource, mDNSBool removeSource, int flags);
+mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
+                                     const char *taskName, mDNSPosixEventCallback callback, void *context);
 // ***************************************************************************
 // Functions
 
+#if MDNS_MALLOC_DEBUGGING
+mDNSexport void mDNSPlatformValidateLists(void)
+{
+    // This should validate gEventSources and any other Posix-specific stuff that gets allocated.
+}
+#endif
+
 int gMDNSPlatformPosixVerboseLevel = 0;
 
 #define PosixErrorToStatus(errNum) ((errNum) == 0 ? mStatus_NoError : mStatus_UnknownErr)
@@ -212,6 +216,70 @@ mDNSexport mStatus mDNSPlatformSendUDP(const mDNS *const m, const void *const ms
     return PosixErrorToStatus(err);
 }
 
+mDNSlocal void TCPReadCallback(int fd, void *context)
+{
+    TCPSocket *sock = context;
+    (void)fd;
+    
+    if (sock->flags & kTCPSocketFlags_UseTLS)
+    {
+        // implement
+    }
+    else
+    {
+        sock->callback(sock, sock->context, mDNSfalse, sock->err);
+    }
+}
+
+mDNSlocal void tcpConnectCallback(int fd, void *context)
+{
+    TCPSocket *sock = context;
+    mDNSBool c = !sock->connected;
+    int result;
+    socklen_t len = sizeof result;
+
+    sock->connected = mDNStrue;
+
+    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &result, &len) < 0)
+    {
+        LogInfo("ERROR: TCPConnectCallback - unable to get connect error: socket %d: Error %d (%s)",
+               sock->events.fd, result, strerror(result));
+        sock->err = mStatus_ConnFailed;
+    }
+    else
+    {
+        if (result != 0)
+        {
+            sock->err = mStatus_ConnFailed;
+            if (result == EHOSTUNREACH || result == EADDRNOTAVAIL || result == ENETDOWN)
+            {
+                LogInfo("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+                        sock->events.fd, result, strerror(result));
+            }
+            else
+            { 
+                LogMsg("ERROR: TCPConnectCallback - connect failed: socket %d: Error %d (%s)",
+                       sock->events.fd, result, strerror(result));
+            }
+        }
+        else
+        {
+            // The connection succeeded.
+            sock->connected = mDNStrue;
+            // Select for read events.
+            sock->events.fd = fd;
+            requestReadEvents(&sock->events, "mDNSPosix::tcpConnectCallback", TCPReadCallback, sock);
+        }
+    }
+
+    if (sock->callback)
+    {
+        sock->callback(sock, sock->context, c, sock->err);
+        // Here sock must be assumed to be invalid, in case the callback freed it.
+        return;
+    }
+}
+
 // This routine is called when the main loop detects that data is available on a socket.
 mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int skt)
 {
@@ -312,60 +380,314 @@ mDNSlocal void SocketDataReady(mDNS *const m, PosixNetworkInterface *intf, int s
                         &senderAddr, senderPort, &destAddr, MulticastDNSPort, InterfaceID);
 }
 
-mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSIPPort * port, mDNSBool useBackgroundTrafficClass)
+mDNSexport TCPSocket *mDNSPlatformTCPSocket(TCPSocketFlags flags, mDNSAddr_Type addrType, mDNSIPPort * port,
+                                            domainname *hostname, mDNSBool useBackgroundTrafficClass)
 {
-    (void)flags;        // Unused
-    (void)port;         // Unused
-    (void)useBackgroundTrafficClass; // Unused
-    return NULL;
+    TCPSocket *sock;
+    int len = sizeof (TCPSocket);
+    
+    (void)useBackgroundTrafficClass;
+
+    if (hostname)
+    {
+        len += sizeof (domainname);
+    }
+    sock = malloc(len); 
+
+    if (sock == NULL)
+    {
+        LogMsg("mDNSPlatformTCPSocket: no memory for socket");
+        return NULL;
+    }
+    memset(sock, 0, sizeof *sock);
+    
+    if (hostname)
+    {
+        sock->hostname = (domainname *)(sock + 1);
+        LogMsg("mDNSPlatformTCPSocket: hostname %##s", hostname->c);
+        AssignDomainName(sock->hostname, hostname);
+    }
+    
+    sock->events.fd = -1;
+    if (!mDNSPosixTCPSocketSetup(&sock->events.fd, addrType, port, &sock->port))
+    {
+      if (sock->events.fd != -1) close(sock->events.fd);
+      free(sock);
+      return mDNSNULL;
+    }
+
+    // Set up the other fields in the structure.
+    sock->flags = flags;
+    sock->err = mStatus_NoError;
+    sock->setup = mDNSfalse;
+    sock->connected = mDNSfalse;
+    return sock;
 }
 
-mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int sd)
+mDNSexport mStatus mDNSPlatformTCPSocketSetCallback(TCPSocket *sock, TCPConnectionCallback callback, void *context)
 {
-    (void)flags;        // Unused
-    (void)sd;           // Unused
-    return NULL;
+    sock->callback = callback;
+    sock->context = context;
+    return mStatus_NoError;
+}
+
+mDNSexport TCPSocket *mDNSPlatformTCPAccept(TCPSocketFlags flags, int fd)
+{
+    TCPSocket *sock;
+
+    // XXX Add!
+    if (flags & kTCPSocketFlags_UseTLS)
+    {
+    return mDNSNULL; // not supported yet.
+    }
+
+    sock = (TCPSocket *) mDNSPlatformMemAllocateClear(sizeof *sock);
+    if (!sock)
+    {
+        return mDNSNULL;
+    }
+
+    sock->events.fd = fd;
+    sock->flags = flags;
+    sock->connected = mDNStrue;
+    return sock;
+}
+
+
+mDNSlocal void tcpListenCallback(int fd, void *context)
+{
+    TCPListener *listener = context;
+    TCPSocket *sock;
+    
+    sock = mDNSPosixDoTCPListenCallback(fd, listener->addressType, listener->socketFlags,
+                                 listener->callback, listener->context);
+    if (sock != NULL)
+    {
+        requestReadEvents(&sock->events, "mDNSPosix::tcpListenCallback", TCPReadCallback, sock);
+    }
+}
+
+mDNSexport TCPListener *mDNSPlatformTCPListen(mDNSAddr_Type addrType, mDNSIPPort *port, mDNSAddr *addr,
+                                              TCPSocketFlags socketFlags, mDNSBool reuseAddr, int queueLength,
+                                              TCPAcceptedCallback callback, void *context)
+{
+    TCPListener *ret;
+    int fd = -1;
+
+    if (!mDNSPosixTCPListen(&fd, addrType, port, addr, reuseAddr, queueLength))
+    {
+        if (fd != -1)
+        {
+            close(fd);
+        }
+        return mDNSNULL;
+    }
+    
+    // Allocate a listener structure
+    ret = (TCPListener *) mDNSPlatformMemAllocateClear(sizeof *ret);
+    if (ret == NULL)
+    {
+        LogMsg("mDNSPlatformTCPListen: no memory for TCPListener struct.");
+        close(fd);
+        return mDNSNULL;
+    }
+    ret->events.fd = fd;
+    ret->callback = callback;
+    ret->context = context;
+    ret->addressType = addrType;
+    ret->socketFlags = socketFlags;
+
+    // When we get a connection, mDNSPosixListenCallback will be called, and it will invoke the
+    // callback we were passed.
+    requestReadEvents(&ret->events, "tcpListenCallback", tcpListenCallback, ret);
+    return ret;
 }
 
 mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock)
 {
-    (void)sock;         // Unused
-    return -1;
+    return sock->events.fd;
 }
 
-mDNSexport mStatus mDNSPlatformTCPConnect(TCPSocket *sock, const mDNSAddr *dst, mDNSOpaque16 dstport, domainname *hostname, mDNSInterfaceID InterfaceID,
-                                          TCPConnectionCallback callback, void *context)
+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)hostname;     // Unused
-    (void)InterfaceID;  // Unused
-    (void)callback;     // Unused
-    (void)context;      // Unused
-    return(mStatus_UnsupportedErr);
+    int result;
+    union {
+        struct sockaddr sa;
+        struct sockaddr_in sin;
+        struct sockaddr_in6 sin6;
+    } addr;
+    socklen_t len;
+
+    sock->callback = callback;
+    sock->context = context;
+    sock->setup = mDNSfalse;
+    sock->connected = mDNSfalse;
+    sock->err = mStatus_NoError;
+
+    result = fcntl(sock->events.fd, F_GETFL, 0);
+    if (result < 0)
+    {
+        LogMsg("mDNSPlatformTCPConnect: F_GETFL failed: %s", strerror(errno));
+        return mStatus_UnknownErr;
+    }
+
+    result = fcntl(sock->events.fd, F_SETFL, result | O_NONBLOCK);
+    if (result < 0)
+    {
+        LogMsg("mDNSPlatformTCPConnect: F_SETFL failed: %s", strerror(errno));
+        return mStatus_UnknownErr;
+    }
+
+    // If we've been asked to bind to a single interface, do it.  See comment in mDNSMacOSX.c for more info.
+    if (InterfaceID)
+    {
+        PosixNetworkInterface *iface = (PosixNetworkInterface *)InterfaceID;
+#if defined(SO_BINDTODEVICE)
+        result = setsockopt(sock->events.fd,
+                            SOL_SOCKET, SO_BINDTODEVICE, iface->intfName, strlen(iface->intfName));
+        if (result < 0)
+        {
+            LogMsg("mDNSPlatformTCPConnect: SO_BINDTODEVICE failed on %s: %s", iface->intfName, strerror(errno));
+            return mStatus_BadParamErr;
+        }
+#else
+        if (dst->type == mDNSAddrType_IPv4)
+        {
+#if defined(IP_BOUND_IF)
+            result = setsockopt(sock->events.fd, IPPROTO_IP, IP_BOUND_IF, &iface->index, sizeof iface->index);
+            if (result < 0)
+            {
+                LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
+                       iface->intfName, iface->index, strerror(errno));
+                return mStatus_BadParamErr;
+            }
+#else
+            (void)iface;
+#endif // IP_BOUND_IF
+        }
+        else
+        { // IPv6
+#if defined(IPV6_BOUND_IF)
+            result = setsockopt(sock->events.fd, IPPROTO_IPV6, IPV6_BOUND_IF, &iface->index, sizeof iface->index);
+            if (result < 0)
+            {
+                LogMsg("mDNSPlatformTCPConnect: IP_BOUND_IF failed on %s (%d): %s",
+                       iface->intfName, iface->index, strerror(errno));
+                return mStatus_BadParamErr;
+            }
+#else
+            (void)iface;
+#endif // IPV6_BOUND_IF
+        }           
+#endif // SO_BINDTODEVICE
+    }
+
+    memset(&addr, 0, sizeof addr);
+    if (dst->type == mDNSAddrType_IPv4)
+    {
+        addr.sa.sa_family = AF_INET;
+        addr.sin.sin_port = dstport.NotAnInteger;
+        len = sizeof (struct sockaddr_in);
+        addr.sin.sin_addr.s_addr = dst->ip.v4.NotAnInteger;
+    }
+    else
+    {
+        addr.sa.sa_family = AF_INET6;
+        len = sizeof (struct sockaddr_in6);
+        addr.sin6.sin6_port = dstport.NotAnInteger;
+        memcpy(&addr.sin6.sin6_addr.s6_addr, &dst->ip.v6, sizeof addr.sin6.sin6_addr.s6_addr);
+    }
+#ifndef NOT_HAVE_SA_LEN
+    addr.sa.sa_len = len;
+#endif
+
+    result = connect(sock->events.fd, (struct sockaddr *)&addr, len);
+    if (result < 0)
+    {
+        if (errno == EINPROGRESS)
+        {
+            requestWriteEvents(&sock->events, "mDNSPlatformConnect", tcpConnectCallback, sock);
+            return mStatus_ConnPending;
+        }
+        if (errno == EHOSTUNREACH || errno == EADDRNOTAVAIL || errno == ENETDOWN)
+        {
+            LogInfo("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s)",
+                    sock->events.fd, errno, strerror(errno));
+        }
+        else
+        { 
+            LogMsg("ERROR: mDNSPlatformTCPConnect - connect failed: socket %d: Error %d (%s) length %d",
+                   sock->events.fd, errno, strerror(errno), len);
+        }
+        return mStatus_ConnFailed;
+    }       
+
+    LogMsg("NOTE: mDNSPlatformTCPConnect completed synchronously");
+    return mStatus_NoError;
 }
 
 mDNSexport void mDNSPlatformTCPCloseConnection(TCPSocket *sock)
 {
-    (void)sock;         // Unused
+    if (sock)
+    { // can sock really be NULL when this is called?
+        shutdown(sock->events.fd, SHUT_RDWR);
+        stopReadOrWriteEvents(sock->events.fd, mDNSfalse, mDNStrue,
+                              PosixEventFlag_Read | PosixEventFlag_Write);
+        close(sock->events.fd);
+        free(sock);
+    }
 }
 
 mDNSexport long mDNSPlatformReadTCP(TCPSocket *sock, void *buf, unsigned long buflen, mDNSBool * closed)
 {
-    (void)sock;         // Unused
-    (void)buf;          // Unused
-    (void)buflen;       // Unused
-    (void)closed;       // Unused
-    return 0;
+    ssize_t nread;
+    
+    *closed = mDNSfalse;
+    if (sock->flags & kTCPSocketFlags_UseTLS)
+    {
+        // Implement...
+        nread = -1;
+        *closed = mDNStrue;
+    } else {
+        nread = mDNSPosixReadTCP(sock->events.fd, buf, buflen, closed);
+    }
+    return nread;
+}
+
+mDNSexport mDNSBool mDNSPlatformTCPWritable(TCPSocket *sock)
+{
+    fd_set w;
+    int nfds = sock->events.fd + 1;
+    int count;
+    struct timeval tv;
+
+    if (nfds > FD_SETSIZE)
+    {
+        LogMsg("ERROR: mDNSPlatformTCPWritable called on an fd that won't fit in an fd_set.");
+        return mDNStrue; // hope for the best?
+    }
+    FD_SET(sock->events.fd, &w);
+    tv.tv_sec = tv.tv_usec = 0;
+    count = select(nfds, NULL, &w, NULL, &tv);
+    if (count > 0)
+    {
+        return mDNStrue;
+    }
+    return mDNSfalse;
 }
 
 mDNSexport long mDNSPlatformWriteTCP(TCPSocket *sock, const char *msg, unsigned long len)
 {
-    (void)sock;         // Unused
-    (void)msg;          // Unused
-    (void)len;          // Unused
-    return 0;
+    if (sock->flags & kTCPSocketFlags_UseTLS)
+    {
+        // implement
+        return -1;
+    }
+    else
+    {
+        return mDNSPosixWriteTCP(sock->events.fd, msg, len);
+    }
 }
 
 mDNSexport UDPSocket *mDNSPlatformUDPSocket(mDNSIPPort port)
@@ -434,12 +756,13 @@ mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNSBool setservers, mDNSBool setse
     DNameListElem **BrowseDomains, mDNSBool ackConfig)
 {
     (void) setservers;
-    (void) fqdn;
     (void) setsearch;
-    (void) RegDomains;
-    (void) BrowseDomains;
     (void) ackConfig;
 
+    if (fqdn         ) fqdn->c[0]      = 0;
+    if (RegDomains   ) *RegDomains     = NULL;
+    if (BrowseDomains) *BrowseDomains  = NULL;
+
     return mDNStrue;
 }
 
@@ -499,11 +822,11 @@ mDNSexport int ParseDNSServers(mDNS *m, const char *filePath)
             mDNSAddr DNSAddr;
             DNSAddr.type = mDNSAddrType_IPv4;
             DNSAddr.ip.v4.NotAnInteger = ina.s_addr;
-            mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
+            mDNS_AddDNSServer(m, NULL, mDNSInterface_Any, 0, &DNSAddr, UnicastDNSPort, kScopeNone, 0, mDNSfalse, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
             numOfServers++;
         }
     }
-       fclose(fp);
+    fclose(fp);
     return (numOfServers > 0) ? 0 : -1;
 }
 
@@ -636,7 +959,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
     // ... with a shared UDP port, if it's for multicast receiving
     if (err == 0 && port.NotAnInteger)
     {
-        // <rdar://problem/20946253>
+        // <rdar://problem/20946253> Suggestions from Jonny Törnbom at Axis Communications
         // We test for SO_REUSEADDR first, as suggested by Jonny Törnbom from Axis Communications
         // Linux kernel versions 3.9 introduces support for socket option
         // SO_REUSEPORT, however this is not implemented the same as on *BSD
@@ -657,6 +980,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
         #endif
         if (err < 0) { err = errno; perror("setsockopt - SO_REUSExxxx"); }
 
+#if TARGET_OS_MAC
         // Enable inbound packets on IFEF_AWDL interface.
         // Only done for multicast sockets, since we don't expect unicast socket operations
         // on the IFEF_AWDL interface. Operation is a no-op for other interface types.
@@ -664,6 +988,7 @@ mDNSlocal int SetupSocket(struct sockaddr *intfAddr, mDNSIPPort port, int interf
         #define SO_RECV_ANYIF   0x1104      /* unrestricted inbound processing */
         #endif
         if (setsockopt(*sktPtr, SOL_SOCKET, SO_RECV_ANYIF, &kOn, sizeof(kOn)) < 0) perror("setsockopt - SO_RECV_ANYIF");
+#endif
     }
 
     // We want to receive destination addresses and interface identifiers.
@@ -876,8 +1201,26 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
     // And make a copy of the intfName.
     if (err == 0)
     {
+#ifdef LINUX
+        char *s;
+        int len;
+        s = strchr(intfName, ':');
+        if (s != NULL)
+        {
+            len = (s - intfName) + 1;
+        }
+        else
+        {
+            len = strlen(intfName) + 1;
+        }
+        intf->intfName = malloc(len);
+        if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
+        memcpy(intf->intfName, intfName, len - 1);
+        intfName[len - 1] = 0;
+#else
         intf->intfName = strdup(intfName);
         if (intf->intfName == NULL) { assert(0); err = ENOMEM; }
+#endif
     }
 
     if (err == 0)
@@ -889,6 +1232,7 @@ mDNSlocal int SetupOneInterface(mDNS *const m, struct sockaddr *intfAddr, struct
         //LogMsg("SetupOneInterface: %#a %#a",  &intf->coreIntf.ip,  &intf->coreIntf.mask);
         strncpy(intf->coreIntf.ifname, intfName, sizeof(intf->coreIntf.ifname));
         intf->coreIntf.ifname[sizeof(intf->coreIntf.ifname)-1] = 0;
+
         intf->coreIntf.Advertise = m->AdvertiseLocalAddresses;
         intf->coreIntf.McastTxRx = mDNStrue;
 
@@ -956,47 +1300,55 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
 {
     mDNSBool foundav4       = mDNSfalse;
     int err            = 0;
-    struct ifi_info *intfList      = get_ifi_info(AF_INET, mDNStrue);
-    struct ifi_info *firstLoopback = NULL;
+    struct ifaddrs *intfList;
+    struct ifaddrs *firstLoopback = NULL;
+    int firstLoopbackIndex = 0;
 
     assert(m != NULL);
     debugf("SetupInterfaceList");
 
-    if (intfList == NULL) err = ENOENT;
-
-#if HAVE_IPV6
-    if (err == 0)       /* Link the IPv6 list to the end of the IPv4 list */
+    if (getifaddrs(&intfList) < 0)
     {
-        struct ifi_info **p = &intfList;
-        while (*p) p = &(*p)->ifi_next;
-        *p = get_ifi_info(AF_INET6, mDNStrue);
+        err = errno;
     }
-#endif
+    if (intfList == NULL) err = ENOENT;
 
     if (err == 0)
     {
-        struct ifi_info *i = intfList;
+        struct ifaddrs *i = intfList;
         while (i)
         {
-            if (     ((i->ifi_addr->sa_family == AF_INET)
+            if (     ((i->ifa_addr->sa_family == AF_INET)
 #if HAVE_IPV6
-                      || (i->ifi_addr->sa_family == AF_INET6)
+                      || (i->ifa_addr->sa_family == AF_INET6)
 #endif
-                      ) &&  (i->ifi_flags & IFF_UP) && !(i->ifi_flags & IFF_POINTOPOINT))
+                      ) &&  (i->ifa_flags & IFF_UP) && !(i->ifa_flags & IFF_POINTOPOINT))
             {
-                if (i->ifi_flags & IFF_LOOPBACK)
+                int ifIndex = if_nametoindex(i->ifa_name);
+                if (ifIndex == 0)
+                {
+                    continue;
+                }
+                if (i->ifa_flags & IFF_LOOPBACK)
                 {
                     if (firstLoopback == NULL)
+                    {
                         firstLoopback = i;
+                        firstLoopbackIndex = ifIndex;
+                    }
                 }
                 else
                 {
-                    if (SetupOneInterface(m, i->ifi_addr, i->ifi_netmask, i->ifi_name, i->ifi_index) == 0)
-                        if (i->ifi_addr->sa_family == AF_INET)
+                    if (SetupOneInterface(m, i->ifa_addr, i->ifa_netmask, i->ifa_name, ifIndex) == 0)
+                    {
+                        if (i->ifa_addr->sa_family == AF_INET)
+                        {
                             foundav4 = mDNStrue;
+                        }
+                    }
                 }
             }
-            i = i->ifi_next;
+            i = i->ifa_next;
         }
 
         // If we found no normal interfaces but we did find a loopback interface, register the
@@ -1005,11 +1357,14 @@ mDNSlocal int SetupInterfaceList(mDNS *const m)
         // 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)
-            (void) SetupOneInterface(m, firstLoopback->ifi_addr, firstLoopback->ifi_netmask, firstLoopback->ifi_name, firstLoopback->ifi_index);
+        {
+            (void)SetupOneInterface(m, firstLoopback->ifa_addr, firstLoopback->ifa_netmask, firstLoopback->ifa_name,
+                                    firstLoopbackIndex);
+        }
     }
 
     // Clean up.
-    if (intfList != NULL) free_ifi_info(intfList);
+    if (intfList != NULL) freeifaddrs(intfList);
 
     // Clean up any interfaces that have been hanging around on the RecentInterfaces list for more than a minute
     PosixNetworkInterface **ri = &gRecentInterfaces;
@@ -1205,7 +1560,7 @@ mDNSlocal mDNSu32       ProcessRoutingNotification(int sd)
 #endif // USES_NETLINK
 
 // Called when data appears on interface change notification socket
-mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
+mDNSlocal void InterfaceChangeCallback(int fd, void *context)
 {
     IfChangeRec     *pChgRec = (IfChangeRec*) context;
     fd_set readFDs;
@@ -1213,7 +1568,6 @@ mDNSlocal void InterfaceChangeCallback(int fd, short filter, void *context)
     struct timeval zeroTimeout = { 0, 0 };
 
     (void)fd; // Unused
-    (void)filter; // Unused
 
     FD_ZERO(&readFDs);
     FD_SET(pChgRec->NotifySD, &readFDs);
@@ -1237,7 +1591,7 @@ mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
     mStatus err;
     IfChangeRec *pChgRec;
 
-    pChgRec = (IfChangeRec*) mDNSPlatformMemAllocate(sizeof *pChgRec);
+    pChgRec = (IfChangeRec*) mDNSPlatformMemAllocateClear(sizeof *pChgRec);
     if (pChgRec == NULL)
         return mStatus_NoMemoryErr;
 
@@ -1245,6 +1599,8 @@ mDNSlocal mStatus WatchForInterfaceChange(mDNS *const m)
     err = OpenIfNotifySocket(&pChgRec->NotifySD);
     if (err == 0)
         err = mDNSPosixAddFDToEventLoop(pChgRec->NotifySD, InterfaceChangeCallback, pChgRec);
+    if (err)
+        mDNSPlatformMemFree(pChgRec);
 
     return err;
 }
@@ -1387,13 +1743,6 @@ mDNSexport void    mDNSPlatformUnlock (const mDNS *const m)
 #pragma mark ***** Strings
 #endif
 
-// mDNS core calls this routine to copy C strings.
-// On the Posix platform this maps directly to the ANSI C strcpy.
-mDNSexport void    mDNSPlatformStrCopy(void *dst, const void *src)
-{
-    strcpy((char *)dst, (const char *)src);
-}
-
 mDNSexport mDNSu32  mDNSPlatformStrLCopy(void *dst, const void *src, mDNSu32 len)
 {
 #if HAVE_STRLCPY
@@ -1498,19 +1847,21 @@ mDNSexport void DNSProxyTerminate(void)
 
 // 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);
 }
 
-mDNSexport void *  mDNSPlatformMemAllocate(mDNSu32 len) { return(malloc(len)); }
-mDNSexport void *  mDNSPlatformMemAllocateClear(mDNSu32 len) { return(calloc(1, len)); }
-mDNSexport void    mDNSPlatformMemFree    (void *mem)   { free(mem); }
+#if !MDNS_MALLOC_DEBUGGING
+mDNSexport void *mDNSPlatformMemAllocate(mDNSu32 len)      { return(mallocL("mDNSPlatformMemAllocate", len)); }
+mDNSexport void *mDNSPlatformMemAllocateClear(mDNSu32 len) { return(callocL(name, len)); }
+mDNSexport void  mDNSPlatformMemFree    (void *mem)        {          freeL("mDNSPlatformMemFree", mem); }
+#endif
 
 #if _PLATFORM_HAS_STRONG_PRNG_
 mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
 {
-       return(arc4random());
+    return(arc4random());
 }
 #else
 mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
@@ -1533,15 +1884,18 @@ mDNSexport mStatus mDNSPlatformTimeInit(void)
 
 mDNSexport mDNSs32  mDNSPlatformRawTime()
 {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    // tv.tv_sec is seconds since 1st January 1970 (GMT, with no adjustment for daylight savings time)
-    // tv.tv_usec is microseconds since the start of this second (i.e. values 0 to 999999)
-    // We use the lower 22 bits of tv.tv_sec for the top 22 bits of our result
-    // 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.
+    struct timespec tm;
+    int ret = clock_gettime(CLOCK_MONOTONIC, &tm);
+    assert(ret == 0); // This call will only fail if the number of seconds does not fit in an object of type time_t.
+
+    // tm.tv_sec is seconds since some unspecified starting point (it is usually the system start up time)
+    // tm.tv_nsec is nanoseconds since the start of this second (i.e. values 0 to 999999999)
+    // We use the lower 22 bits of tm.tv_sec for the top 22 bits of our result
+    // and we multiply tm.tv_nsec by 2 / 1953125 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 ((tm.tv_sec << 10) | (tm.tv_nsec * 2 / 1953125));
 }
 
 mDNSexport mDNSs32 mDNSPlatformUTC(void)
@@ -1663,29 +2017,48 @@ mDNSlocal void mDNSPosixAddToFDSet(int *nfds, fd_set *readfds, int s)
     FD_SET(s, readfds);
 }
 
-mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout)
+mDNSexport void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds)
 {
-    mDNSs32 ticks;
-    struct timeval interval;
-
-    // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
-    mDNSs32 nextevent = mDNS_Execute(m);
+    int numFDs = *nfds;
+    PosixEventSource *iSource;
 
     // 2. Build our list of active file descriptors
     PosixNetworkInterface *info = (PosixNetworkInterface *)(m->HostInterfaces);
-    if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket4);
+    if (m->p->unicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket4);
 #if HAVE_IPV6
-    if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, m->p->unicastSocket6);
+    if (m->p->unicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, m->p->unicastSocket6);
 #endif
     while (info)
     {
-        if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket4);
+        if (info->multicastSocket4 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket4);
 #if HAVE_IPV6
-        if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(nfds, readfds, info->multicastSocket6);
+        if (info->multicastSocket6 != -1) mDNSPosixAddToFDSet(&numFDs, readfds, info->multicastSocket6);
 #endif
         info = (PosixNetworkInterface *)(info->coreIntf.next);
     }
 
+    // Copy over the event fds.   We have to do it this way because client-provided event loops expect
+    // to initialize their FD sets first and then call mDNSPosixGetFDSet()
+    for (iSource = gEventSources; iSource; iSource = iSource->next)
+    {
+        if (iSource->readCallback != NULL)
+            FD_SET(iSource->fd, readfds);
+        if (iSource->writeCallback != NULL)
+            FD_SET(iSource->fd, writefds);
+        if (numFDs <= iSource->fd)
+            numFDs = iSource->fd + 1;
+    }
+    *nfds = numFDs;
+}
+
+mDNSexport void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout)
+{
+    mDNSs32 ticks;
+    struct timeval interval;
+
+    // 1. Call mDNS_Execute() to let mDNSCore do what it needs to do
+    mDNSs32 nextevent = mDNS_Execute(m);
+
     // 3. Calculate the time remaining to the next scheduled event (in struct timeval format)
     ticks = nextevent - mDNS_TimeNow(m);
     if (ticks < 1) ticks = 1;
@@ -1698,9 +2071,16 @@ mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct ti
         *timeout = interval;
 }
 
-mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
+mDNSexport void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout)
+{
+    mDNSPosixGetNextDNSEventTime(m, timeout);
+    mDNSPosixGetFDSetForSelect(m, nfds, readfds, writefds);
+}
+
+mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds)
 {
     PosixNetworkInterface *info;
+    PosixEventSource    *iSource;
     assert(m       != NULL);
     assert(readfds != NULL);
     info = (PosixNetworkInterface *)(m->HostInterfaces);
@@ -1734,67 +2114,151 @@ mDNSexport void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds)
 #endif
         info = (PosixNetworkInterface *)(info->coreIntf.next);
     }
-}
-
-// update gMaxFD
-mDNSlocal void  DetermineMaxEventFD(void)
-{
-    PosixEventSource    *iSource;
 
-    gMaxFD = 0;
-    for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
-        if (gMaxFD < iSource->fd)
-            gMaxFD = iSource->fd;
+    // Now process routing socket events, discovery relay events and anything else of that ilk.
+    for (iSource = gEventSources; iSource; iSource = iSource->next)
+    {
+        if (iSource->readCallback != NULL && FD_ISSET(iSource->fd, readfds))
+        {
+            iSource->readCallback(iSource->fd, iSource->readContext);
+            break;  // in case callback removed elements from gEventSources
+        }
+        else if (iSource->writeCallback != NULL && FD_ISSET(iSource->fd, writefds))
+        {
+            mDNSPosixEventCallback writeCallback = iSource->writeCallback;
+            // Write events are one-shot: to get another event, the consumer has to put in a new request.
+            // We reset this before calling the callback just in case the callback requests another write
+            // callback, or deletes the event context from the list.
+            iSource->writeCallback = NULL;
+            writeCallback(iSource->fd, iSource->writeContext);
+            break;  // in case callback removed elements from gEventSources
+        }
+    }
 }
 
-// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
-{
-    PosixEventSource    *newSource;
+mDNSu32 mDNSPlatformEventContextSize = sizeof (PosixEventSource);
 
-    if (gEventSources.LinkOffset == 0)
-        InitLinkedList(&gEventSources, offsetof(PosixEventSource, Next));
+mDNSlocal void requestIOEvents(PosixEventSource *newSource, const char *taskName,
+                                  mDNSPosixEventCallback callback, void *context, int flag)
+{
+    PosixEventSource **epp = &gEventSources;
 
-    if (fd >= (int) FD_SETSIZE || fd < 0)
-        return mStatus_UnsupportedErr;
+    if (newSource->fd >= (int) FD_SETSIZE || newSource->fd < 0)
+    {
+        LogMsg("requestIOEvents called with fd %d > FD_SETSIZE %d.", newSource->fd, FD_SETSIZE);
+        assert(0);
+    }
     if (callback == NULL)
-        return mStatus_BadParamErr;
-
-    newSource = (PosixEventSource*) malloc(sizeof *newSource);
-    if (NULL == newSource)
-        return mStatus_NoMemoryErr;
+    {
+        LogMsg("requestIOEvents called no callback.", newSource->fd, FD_SETSIZE);
+        assert(0);
+    }
 
-    newSource->Callback = callback;
-    newSource->Context = context;
-    newSource->fd = fd;
+    // See if this event context is already on the list; if it is, no need to scan the list.
+    if (!(newSource->flags & PosixEventFlag_OnList))
+    {
+        while (*epp)
+        {
+            // This should never happen.
+            if (newSource == *epp)
+            {
+                LogMsg("Event context marked not on list but is on list.");
+                assert(0);
+            }
+            epp = &(*epp)->next;
+        }
+        if (*epp == NULL)
+        {
+            *epp = newSource;
+            newSource->next = NULL;
+            newSource->flags = PosixEventFlag_OnList;
+        }
+    }
 
-    AddToTail(&gEventSources, newSource);
-    FD_SET(fd, &gEventFDs);
+    if (flag & PosixEventFlag_Read)
+    {
+        newSource->readCallback = callback;
+        newSource->readContext = context;
+        newSource->flags |= PosixEventFlag_Read;
+        newSource->readTaskName = taskName;
+    }
+    if (flag & PosixEventFlag_Write)
+    {
+        newSource->writeCallback = callback;
+        newSource->writeContext = context;
+        newSource->flags |= PosixEventFlag_Write;
+        newSource->writeTaskName = taskName;
+    }
+}
 
-    DetermineMaxEventFD();
+mDNSlocal void requestReadEvents(PosixEventSource *eventSource,
+                                    const char *taskName, mDNSPosixEventCallback callback, void *context)
+{
+    requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Read);
+}
 
-    return mStatus_NoError;
+mDNSlocal void requestWriteEvents(PosixEventSource *eventSource,
+                                     const char *taskName, mDNSPosixEventCallback callback, void *context)
+{
+    requestIOEvents(eventSource, taskName, callback, context, PosixEventFlag_Write);
 }
 
 // Remove a file descriptor from the set that mDNSPosixRunEventLoopOnce() listens to.
-mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
+mDNSlocal mStatus stopReadOrWriteEvents(int fd, mDNSBool freeContext, mDNSBool removeContext, int flags)
 {
-    PosixEventSource    *iSource;
+    PosixEventSource *iSource, **epp = &gEventSources;
 
-    for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
+    while (*epp)
     {
+        iSource = *epp;
         if (fd == iSource->fd)
         {
-            FD_CLR(fd, &gEventFDs);
-            RemoveFromList(&gEventSources, iSource);
-            free(iSource);
-            DetermineMaxEventFD();
+            if (flags & PosixEventFlag_Read)
+            {
+                iSource->readCallback = NULL;
+                iSource->readContext = NULL;
+            }
+            if (flags & PosixEventFlag_Write)
+            {
+                iSource->writeCallback = NULL;
+                iSource->writeContext = NULL;
+            }
+            if (iSource->writeCallback == NULL && iSource->readCallback == NULL)
+            {
+                if (removeContext || freeContext)
+                    *epp = iSource->next;
+                if (freeContext)
+                    free(iSource);
+            }
             return mStatus_NoError;
         }
+        epp = &(*epp)->next;
     }
     return mStatus_NoSuchNameErr;
 }
 
+// Some of the mDNSPosix client code relies on being able to add FDs to the event loop without
+// providing storage for the event-related info.   mDNSPosixAddFDToEventLoop and
+// mDNSPosixRemoveFDFromEventLoop handle the event structure storage automatically.
+mStatus mDNSPosixAddFDToEventLoop(int fd, mDNSPosixEventCallback callback, void *context)
+{
+    PosixEventSource *newSource;
+
+    newSource = (PosixEventSource*) malloc(sizeof *newSource);
+    if (NULL == newSource)
+        return mStatus_NoMemoryErr;
+    memset(newSource, 0, sizeof *newSource);
+    newSource->fd = fd;
+
+    requestReadEvents(newSource, "mDNSPosixAddFDToEventLoop", callback, context);
+    return mStatus_NoError;
+}
+
+mStatus mDNSPosixRemoveFDFromEventLoop(int fd)
+{
+    return stopReadOrWriteEvents(fd, mDNStrue, mDNStrue, PosixEventFlag_Read | PosixEventFlag_Write);
+}
+
 // Simply note the received signal in gEventSignals.
 mDNSlocal void  NoteSignal(int signum)
 {
@@ -1836,34 +2300,39 @@ mStatus mDNSPosixIgnoreSignalInEventLoop(int signum)
 mStatus mDNSPosixRunEventLoopOnce(mDNS *m, const struct timeval *pTimeout,
                                   sigset_t *pSignalsReceived, mDNSBool *pDataDispatched)
 {
-    fd_set listenFDs = gEventFDs;
-    int fdMax = 0, numReady;
+    fd_set listenFDs;
+    fd_set writeFDs;
+    int numFDs = 0, numReady;
     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)
-        fdMax = gMaxFD;
+    // 1. Set up the fd_set as usual here.
+    // This example client has no file descriptors of its own,
+    // but a real application would call FD_SET to add them to the set here
+    FD_ZERO(&listenFDs);
+    FD_ZERO(&writeFDs);
+
+    // 2. Set up the timeout.
+    mDNSPosixGetNextDNSEventTime(m, &timeout);
 
-    numReady = select(fdMax + 1, &listenFDs, (fd_set*) NULL, (fd_set*) NULL, &timeout);
+    // Include the sockets that are listening to the wire in our select() set
+    mDNSPosixGetFDSetForSelect(m, &numFDs, &listenFDs, &writeFDs);
+    numReady = select(numFDs, &listenFDs, &writeFDs, (fd_set*) NULL, &timeout);
 
-    // If any data appeared, invoke its callback
     if (numReady > 0)
     {
-        PosixEventSource    *iSource;
-
-        (void) mDNSPosixProcessFDSet(m, &listenFDs);    // call this first to process wire data for clients
-
-        for (iSource=(PosixEventSource*)gEventSources.Head; iSource; iSource = iSource->Next)
-        {
-            if (FD_ISSET(iSource->fd, &listenFDs))
-            {
-                iSource->Callback(iSource->fd, 0, iSource->Context);
-                break;  // in case callback removed elements from gEventSources
-            }
-        }
+        mDNSPosixProcessFDSet(m, &listenFDs, &writeFDs);
         *pDataDispatched = mDNStrue;
     }
+    else if (numReady < 0)
+    {
+       if (errno != EINTR) {
+            // This should never happen, represents a coding error, and is not recoverable, since
+            // we'll just sit here spinning and never receive another event.   The usual reason for
+            // it to happen is that an FD was closed but not removed from the event list.
+            LogMsg("select failed: %s", strerror(errno));
+            abort();
+        }
+    }
     else
         *pDataDispatched = mDNSfalse;
 
index ca60d806ab04c958269eafbf867e832fc0057e6b..01d7e96805a715c9a91a97930112f41f2f21ef4b 100755 (executable)
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
  * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
  *
@@ -35,7 +35,7 @@ typedef struct PosixNetworkInterface PosixNetworkInterface;
 
 struct PosixNetworkInterface
 {
-    NetworkInterfaceInfo coreIntf;             // MUST be the first element in this structure
+    NetworkInterfaceInfo coreIntf;      // MUST be the first element in this structure
     mDNSs32 LastSeen;
     const char *            intfName;
     PosixNetworkInterface * aliasIntf;
@@ -57,21 +57,76 @@ struct mDNS_PlatformSupport_struct
 #endif
 };
 
+// We keep a list of client-supplied event sources in PosixEventSource records
+// Add a file descriptor to the set that mDNSPosixRunEventLoopOnce() listens to.
+#define PosixEventFlag_OnList   1
+#define PosixEventFlag_Read     2
+#define PosixEventFlag_Write    4
+    
+typedef void (*mDNSPosixEventCallback)(int fd, void *context);
+struct PosixEventSource
+{
+    struct PosixEventSource *next;
+    mDNSPosixEventCallback readCallback;
+    mDNSPosixEventCallback writeCallback;
+    const char *readTaskName;
+    const char *writeTaskName;
+    void *readContext;
+    void *writeContext;
+    int fd;
+    unsigned flags;
+};
+typedef struct PosixEventSource PosixEventSource;
+    
+struct TCPSocket_struct
+{
+    mDNSIPPort port;            // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with mDNSIPPort
+    TCPSocketFlags flags;       // MUST BE SECOND FIELD -- mDNSCore expects every TCPSocket_struct have TCPSocketFlags flags after mDNSIPPort
+    TCPConnectionCallback callback;
+    PosixEventSource events;
+    // SSL context goes here.
+    domainname *hostname;
+    mDNSAddr remoteAddress;
+    mDNSIPPort remotePort;
+    void *context;
+    mDNSBool setup;
+    mDNSBool connected;
+    mStatus err;
+};
+
+struct TCPListener_struct
+{
+    TCPAcceptedCallback callback;
+    PosixEventSource events;
+    void *context;
+    mDNSAddr_Type addressType;
+    TCPSocketFlags socketFlags;
+};
+    
 #define uDNS_SERVERS_FILE "/etc/resolv.conf"
 extern int ParseDNSServers(mDNS *m, const char *filePath);
 extern mStatus mDNSPlatformPosixRefreshInterfaceList(mDNS *const m);
 // See comment in implementation.
 
+// Get the next upcoming mDNS (or DNS) event time as a posix timeval that can be passed to select.
+// This will only update timeout if the next mDNS event is sooner than the value that was passed.
+// Therefore, use { FutureTime, 0 } as an initializer if no other timer events are being managed.
+extern void mDNSPosixGetNextDNSEventTime(mDNS *m, struct timeval *timeout);
+
+// Returns all the FDs that the posix I/O event system expects to be passed to select.
+extern void mDNSPosixGetFDSetForSelect(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds);
+
 // Call mDNSPosixGetFDSet before calling select(), to update the parameters
 // as may be necessary to meet the needs of the mDNSCore code.
 // The timeout pointer MUST NOT be NULL.
 // Set timeout->tv_sec to FutureTime if you want to have effectively no timeout
 // After calling mDNSPosixGetFDSet(), call select(nfds, &readfds, NULL, NULL, &timeout); as usual
 // After select() returns, call mDNSPosixProcessFDSet() to let mDNSCore do its work
-extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, struct timeval *timeout);
-extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds);
+// mDNSPosixGetFDSet simply calls mDNSPosixGetNextDNSEventTime and then mDNSPosixGetFDSetForSelect.
+extern void mDNSPosixGetFDSet(mDNS *m, int *nfds, fd_set *readfds, fd_set *writefds, struct timeval *timeout);
 
-typedef void (*mDNSPosixEventCallback)(int fd, short filter, void *context);
+
+extern void mDNSPosixProcessFDSet(mDNS *const m, fd_set *readfds, fd_set *writefds);
 
 extern mStatus mDNSPosixAddFDToEventLoop( int fd, mDNSPosixEventCallback callback, void *context);
 extern mStatus mDNSPosixRemoveFDFromEventLoop( int fd);
@@ -79,6 +134,10 @@ extern mStatus mDNSPosixListenForSignalInEventLoop( int signum);
 extern mStatus mDNSPosixIgnoreSignalInEventLoop( int signum);
 extern mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, sigset_t *pSignalsReceived, mDNSBool *pDataDispatched);
 
+extern mStatus mDNSPosixListenForSignalInEventLoop( int signum);
+extern mStatus mDNSPosixIgnoreSignalInEventLoop( int signum);
+extern mStatus mDNSPosixRunEventLoopOnce( mDNS *m, const struct timeval *pTimeout, sigset_t *pSignalsReceived, mDNSBool *pDataDispatched);
+
 #ifdef  __cplusplus
 }
 #endif
index e00ddd62b881a54eab294d9ad5e6d8b1a64cbea1..7ad0f301b5e05d946ebd74af9a37548d77b9f125 100755 (executable)
 #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
-   <sys/sockio.h>.
- */
-
-#ifndef SIOCGIFCONF
-    #include <sys/sockio.h>
-#endif
-
 /* sockaddr_dl is only referenced if we're using IP_RECVIF,
    so only include the header in that case.
  */
     #include <net/if_dl.h>
 #endif
 
-#if defined(AF_INET6) && HAVE_IPV6 && !HAVE_LINUX
-#include <net/if_var.h>
-#include <netinet/in_var.h>
-// Note: netinet/in_var.h implicitly includes netinet6/in6_var.h for us
-#endif
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-#include <netdb.h>
-#include <arpa/inet.h>
-
-/* Converts a prefix length to IPv6 network mask */
-void plen_to_mask(int plen, char *addr) {
-    int i;
-    int colons=7; /* Number of colons in IPv6 address */
-    int bits_in_block=16; /* Bits per IPv6 block */
-    for(i=0; i<=colons; i++) {
-        int block, ones=0xffff, ones_in_block;
-        if (plen>bits_in_block) ones_in_block=bits_in_block;
-        else ones_in_block=plen;
-        block = ones & (ones << (bits_in_block-ones_in_block));
-        i==0 ? sprintf(addr, "%x", block) : sprintf(addr, "%s:%x", addr, block);
-        plen -= ones_in_block;
-    }
-}
-
-/* Gets IPv6 interface information from the /proc filesystem in linux*/
-struct ifi_info *get_ifi_info_linuxv6(int doaliases)
-{
-    struct ifi_info *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
-    FILE *fp = NULL;
-    int i, nitems, flags, index, plen, scope;
-    struct addrinfo hints, *res0;
-    int err;
-    int sockfd = -1;
-    struct ifreq ifr;
-    char ifnameFmt[16], addrStr[32 + 7 + 1], ifname[IFNAMSIZ], lastname[IFNAMSIZ];
-
-    res0=NULL;
-    ifihead = NULL;
-    ifipnext = &ifihead;
-
-    if ((fp = fopen(PROC_IFINET6_PATH, "r")) != NULL) {
-        sockfd = socket(AF_INET6, SOCK_DGRAM, 0);
-        if (sockfd < 0) {
-            goto gotError;
-        }
-
-        // Parse /proc/net/if_inet6 according to <https://www.tldp.org/HOWTO/Linux+IPv6-HOWTO/ch11s04.html>.
-
-        // Create a string specifier with a width of IFNAMSIZ - 1 ("%<IFNAMSIZ - 1>s") to scan the interface name. The
-        // reason why we don't just use the string-ified macro expansion of IFNAMSIZ for the width is because the width
-        // needs to be a decimal string and there's no guarantee that IFNAMSIZ will be defined as a decimal integer. For
-        // example, it could be defined in hexadecimal or as an arithmetic expression.
-
-        snprintf(ifnameFmt, sizeof(ifnameFmt), "%%%ds", IFNAMSIZ - 1);
-
-        // Write the seven IPv6 address string colons and NUL terminator, i.e., "xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx".
-        // The remaining 32 IPv6 address characters come from /proc/net/if_inet6.
-
-        for (i = 4; i < 39; i += 5) addrStr[i] = ':';
-        addrStr[39] = '\0';
-
-        lastname[0] = '\0';
-        for (;;) {
-            nitems = fscanf(fp, " %4c%4c%4c%4c%4c%4c%4c%4c %x %x %x %x",
-                &addrStr[0],  &addrStr[5],  &addrStr[10], &addrStr[15],
-                &addrStr[20], &addrStr[25], &addrStr[30], &addrStr[35],
-                &index, &plen, &scope, &flags);
-            if (nitems != 12) break;
-
-            nitems = fscanf(fp, ifnameFmt, ifname);
-            if (nitems != 1) break;
-
-            if (strcmp(lastname, ifname) == 0) {
-                if (doaliases == 0)
-                    continue;   /* already processed this interface */
-            }
-            memcpy(lastname, ifname, IFNAMSIZ);
-            ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
-            if (ifi == NULL) {
-                goto gotError;
-            }
-
-            ifipold   = *ifipnext;       /* need this later */
-            ifiptr    = ifipnext;
-            *ifipnext = ifi;            /* prev points to this new one */
-            ifipnext = &ifi->ifi_next;  /* pointer to next one goes here */
-
-            /* Add address of the interface */
-            memset(&hints, 0, sizeof(hints));
-            hints.ai_family = AF_INET6;
-            hints.ai_flags = AI_NUMERICHOST;
-            err = getaddrinfo(addrStr, NULL, &hints, &res0);
-            if (err) {
-                goto gotError;
-            }
-            ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
-            if (ifi->ifi_addr == NULL) {
-                goto gotError;
-            }
-            memcpy(ifi->ifi_addr, res0->ai_addr, sizeof(struct sockaddr_in6));
-
-            /* Add netmask of the interface */
-            char ipv6addr[INET6_ADDRSTRLEN];
-            plen_to_mask(plen, ipv6addr);
-            ifi->ifi_netmask = calloc(1, sizeof(struct sockaddr_in6));
-            if (ifi->ifi_netmask == NULL) {
-                goto gotError;
-            }
-
-            ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_family=AF_INET6;
-            ((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_scope_id=scope;
-            inet_pton(AF_INET6, ipv6addr, &((struct sockaddr_in6 *)ifi->ifi_netmask)->sin6_addr);
-
-            /* Add interface name */
-            memcpy(ifi->ifi_name, ifname, IFI_NAME);
-
-            /* Add interface index */
-            ifi->ifi_index = index;
-
-            /* Add interface flags*/
-            memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-            if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
-                if (errno == EADDRNOTAVAIL) {
-                    /*
-                     * If the main interface is configured with no IP address but
-                     * an alias interface exists with an IP address, you get
-                     * EADDRNOTAVAIL for the main interface
-                     */
-                    free(ifi->ifi_addr);
-                    free(ifi->ifi_netmask);
-                    free(ifi);
-                    ifipnext  = ifiptr;
-                    *ifipnext = ifipold;
-                    continue;
-                } else {
-                    goto gotError;
-                }
-            }
-            ifi->ifi_flags = ifr.ifr_flags;
-            freeaddrinfo(res0);
-            res0=NULL;
-        }
-    }
-    goto done;
-
-gotError:
-    if (ifihead != NULL) {
-        free_ifi_info(ifihead);
-        ifihead = NULL;
-    }
-    if (res0 != NULL) {
-        freeaddrinfo(res0);
-        res0=NULL;
-    }
-done:
-    if (sockfd != -1) {
-        int rv;
-        rv = close(sockfd);
-        assert(rv == 0);
-    }
-    if (fp != NULL) {
-        fclose(fp);
-    }
-    return(ifihead);    /* pointer to first structure in linked list */
-}
-#endif // defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-
-struct ifi_info *get_ifi_info(int family, int doaliases)
-{
-    int junk;
-    struct ifi_info     *ifi, *ifihead, **ifipnext, *ifipold, **ifiptr;
-    int sockfd, sockf6, len, lastlen, flags, myflags;
-#ifdef NOT_HAVE_IF_NAMETOINDEX
-    int index = 200;
-#endif
-    char                *ptr, *buf, lastname[IFNAMSIZ], *cptr;
-    struct ifconf ifc;
-    struct ifreq        *ifr, ifrcopy;
-    struct sockaddr_in  *sinptr;
-
-#if defined(AF_INET6) && HAVE_IPV6
-    struct sockaddr_in6 *sinptr6;
-#endif
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-    if (family == AF_INET6) return get_ifi_info_linuxv6(doaliases);
-#endif
-
-    sockfd = -1;
-    sockf6 = -1;
-    buf = NULL;
-    ifihead = NULL;
-
-    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
-    if (sockfd < 0) {
-        goto gotError;
-    }
-
-    lastlen = 0;
-    len = 100 * sizeof(struct ifreq);   /* initial buffer size guess */
-    for ( ; ; ) {
-        buf = (char*)malloc(len);
-        if (buf == NULL) {
-            goto gotError;
-        }
-        ifc.ifc_len = len;
-        ifc.ifc_buf = buf;
-        if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) {
-            if (errno != EINVAL || lastlen != 0) {
-                goto gotError;
-            }
-        } 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_ifi_info1 */
-
-/* include get_ifi_info2 */
-    for (ptr = buf; ptr < buf + ifc.ifc_len; ) {
-        ifr = (struct ifreq *) ptr;
-
-        /* Advance to next one in buffer */
-        if (sizeof(struct ifreq) > sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr))
-            ptr += sizeof(struct ifreq);
-        else
-            ptr += sizeof(ifr->ifr_name) + GET_SA_LEN(ifr->ifr_addr);
-
-//      fprintf(stderr, "intf %p name=%s AF=%d\n", index, ifr->ifr_name, ifr->ifr_addr.sa_family);
-
-        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;
-        if (ioctl(sockfd, SIOCGIFFLAGS, &ifrcopy) < 0) {
-            goto gotError;
-        }
-
-        flags = ifrcopy.ifr_flags;
-        if ((flags & IFF_UP) == 0)
-            continue;   /* ignore if interface not up */
-
-        ifi = (struct ifi_info*)calloc(1, sizeof(struct ifi_info));
-        if (ifi == NULL) {
-            goto gotError;
-        }
-        ifipold   = *ifipnext;       /* need this later */
-        ifiptr    = ifipnext;
-        *ifipnext = ifi;             /* prev points to this new one */
-        ifipnext  = &ifi->ifi_next;  /* pointer to next one goes here */
-
-        ifi->ifi_flags = flags;     /* IFF_xxx values */
-        ifi->ifi_myflags = myflags; /* IFI_xxx values */
-#ifndef NOT_HAVE_IF_NAMETOINDEX
-        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);
-        ifi->ifi_name[IFI_NAME-1] = '\0';
-/* end get_ifi_info2 */
-/* include get_ifi_info3 */
-        switch (ifr->ifr_addr.sa_family) {
-        case AF_INET:
-            sinptr = (struct sockaddr_in *) &ifr->ifr_addr;
-            if (ifi->ifi_addr == NULL) {
-                ifi->ifi_addr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
-                if (ifi->ifi_addr == NULL) {
-                    goto gotError;
-                }
-                memcpy(ifi->ifi_addr, sinptr, sizeof(struct sockaddr_in));
-
-#ifdef  SIOCGIFNETMASK
-                if (ioctl(sockfd, SIOCGIFNETMASK, &ifrcopy) < 0) {
-                    if (errno == EADDRNOTAVAIL) {
-                        /*
-                         * If the main interface is configured with no IP address but
-                         * an alias interface exists with an IP address, you get
-                         * EADDRNOTAVAIL for the main interface
-                         */
-                        free(ifi->ifi_addr);
-                        free(ifi);
-                        ifipnext  = ifiptr;
-                        *ifipnext = ifipold;
-                        continue;
-                    } else {
-                        goto gotError;
-                    }
-                }
-
-                ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
-                if (ifi->ifi_netmask == NULL) goto gotError;
-                sinptr = (struct sockaddr_in *) &ifrcopy.ifr_addr;
-                /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
-                sinptr->sin_len    = sizeof(struct sockaddr_in);
-#endif
-                sinptr->sin_family = AF_INET;
-                memcpy(ifi->ifi_netmask, sinptr, sizeof(struct sockaddr_in));
-#endif
-
-#ifdef  SIOCGIFBRDADDR
-                if (flags & IFF_BROADCAST) {
-                    if (ioctl(sockfd, SIOCGIFBRDADDR, &ifrcopy) < 0) {
-                        goto gotError;
-                    }
-                    sinptr = (struct sockaddr_in *) &ifrcopy.ifr_broadaddr;
-                    /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
-                    sinptr->sin_len    = sizeof( struct sockaddr_in );
-#endif
-                    sinptr->sin_family = AF_INET;
-                    ifi->ifi_brdaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
-                    if (ifi->ifi_brdaddr == NULL) {
-                        goto gotError;
-                    }
-                    memcpy(ifi->ifi_brdaddr, sinptr, sizeof(struct sockaddr_in));
-                }
-#endif
-
-#ifdef  SIOCGIFDSTADDR
-                if (flags & IFF_POINTOPOINT) {
-                    if (ioctl(sockfd, SIOCGIFDSTADDR, &ifrcopy) < 0) {
-                        goto gotError;
-                    }
-                    sinptr = (struct sockaddr_in *) &ifrcopy.ifr_dstaddr;
-                    /* The BSD ioctls (including Mac OS X) stick some weird values in for sin_len and sin_family */
-#ifndef NOT_HAVE_SA_LEN
-                    sinptr->sin_len    = sizeof( struct sockaddr_in );
-#endif
-                    sinptr->sin_family = AF_INET;
-                    ifi->ifi_dstaddr = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in));
-                    if (ifi->ifi_dstaddr == NULL) {
-                        goto gotError;
-                    }
-                    memcpy(ifi->ifi_dstaddr, sinptr, sizeof(struct sockaddr_in));
-                }
-#endif
-            }
-            break;
-
-#if defined(AF_INET6) && HAVE_IPV6
-        case AF_INET6:
-            sinptr6 = (struct sockaddr_in6 *) &ifr->ifr_addr;
-            if (ifi->ifi_addr == NULL) {
-                ifi->ifi_addr = calloc(1, sizeof(struct sockaddr_in6));
-                if (ifi->ifi_addr == NULL) {
-                    goto gotError;
-                }
-
-                /* Some platforms (*BSD) inject the prefix in IPv6LL addresses */
-                /* We need to strip that out */
-                if (IN6_IS_ADDR_LINKLOCAL(&sinptr6->sin6_addr))
-                    sinptr6->sin6_addr.s6_addr[2] = sinptr6->sin6_addr.s6_addr[3] = 0;
-                memcpy(ifi->ifi_addr, sinptr6, sizeof(struct sockaddr_in6));
-
-#ifdef  SIOCGIFNETMASK_IN6
-                {
-                    struct in6_ifreq ifr6;
-                    if (sockf6 == -1)
-                        sockf6 = socket(AF_INET6, SOCK_DGRAM, 0);
-                    memset(&ifr6, 0, sizeof(ifr6));
-                    memcpy(&ifr6.ifr_name,           &ifr->ifr_name, sizeof(ifr6.ifr_name          ));
-                    memcpy(&ifr6.ifr_ifru.ifru_addr, &ifr->ifr_addr, sizeof(ifr6.ifr_ifru.ifru_addr));
-                    if (ioctl(sockf6, SIOCGIFNETMASK_IN6, &ifr6) < 0) {
-                        if (errno == EADDRNOTAVAIL) {
-                            /*
-                             * If the main interface is configured with no IP address but
-                             * an alias interface exists with an IP address, you get
-                             * EADDRNOTAVAIL for the main interface
-                             */
-                            free(ifi->ifi_addr);
-                            free(ifi);
-                            ifipnext  = ifiptr;
-                            *ifipnext = ifipold;
-                            continue;
-                        } else {
-                            goto gotError;
-                        }
-                    }
-                    ifi->ifi_netmask = (struct sockaddr*)calloc(1, sizeof(struct sockaddr_in6));
-                    if (ifi->ifi_netmask == NULL) goto gotError;
-                    sinptr6 = (struct sockaddr_in6 *) &ifr6.ifr_ifru.ifru_addr;
-                    memcpy(ifi->ifi_netmask, sinptr6, sizeof(struct sockaddr_in6));
-                }
-#endif
-            }
-            break;
-#endif
-
-        default:
-            break;
-        }
-    }
-    goto done;
-
-gotError:
-    if (ifihead != NULL) {
-        free_ifi_info(ifihead);
-        ifihead = NULL;
-    }
-
-done:
-    if (buf != NULL) {
-        free(buf);
-    }
-    if (sockfd != -1) {
-        junk = close(sockfd);
-        assert(junk == 0);
-    }
-    if (sockf6 != -1) {
-        junk = close(sockf6);
-        assert(junk == 0);
-    }
-    return(ifihead);    /* pointer to first structure in linked list */
-}
-/* end get_ifi_info3 */
-
-/* include free_ifi_info */
-void
-free_ifi_info(struct ifi_info *ifihead)
-{
-    struct ifi_info *ifi, *ifinext;
-
-    for (ifi = ifihead; ifi != NULL; ifi = ifinext) {
-        if (ifi->ifi_addr != NULL)
-            free(ifi->ifi_addr);
-        if (ifi->ifi_netmask != NULL)
-            free(ifi->ifi_netmask);
-        if (ifi->ifi_brdaddr != NULL)
-            free(ifi->ifi_brdaddr);
-        if (ifi->ifi_dstaddr != NULL)
-            free(ifi->ifi_dstaddr);
-        ifinext = ifi->ifi_next;    /* can't fetch ifi_next after free() */
-        free(ifi);                  /* the ifi_info{} itself */
-    }
-}
-/* end free_ifi_info */
-
 ssize_t
 recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
                struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl)
index 2b36ceb04252a581e4b54a0c74c700a915ce52c5..420b038d9b47f2d12fc863ca97044e968f07084b 100755 (executable)
@@ -44,14 +44,6 @@ extern "C" {
 typedef unsigned int socklen_t;
 #endif
 
-#if !defined(_SS_MAXSIZE)
-#if HAVE_IPV6
-#define sockaddr_storage sockaddr_in6
-#else
-#define sockaddr_storage sockaddr
-#endif // HAVE_IPV6
-#endif // !defined(_SS_MAXSIZE)
-
 #ifndef NOT_HAVE_SA_LEN
 #define GET_SA_LEN(X) (sizeof(struct sockaddr) > ((struct sockaddr*)&(X))->sa_len ? \
                        sizeof(struct sockaddr) : ((struct sockaddr*)&(X))->sa_len   )
@@ -82,43 +74,10 @@ struct my_in_pktinfo {
 extern ssize_t recvfrom_flags(int fd, void *ptr, size_t nbytes, int *flagsp,
                               struct sockaddr *sa, socklen_t *salenptr, struct my_in_pktinfo *pktp, u_char *ttl);
 
-struct ifi_info {
-    char ifi_name[IFI_NAME];    /* interface name, null terminated */
-    u_char ifi_haddr[IFI_HADDR]; /* hardware address */
-    u_short ifi_hlen;           /* #bytes in hardware address: 0, 6, 8 */
-    short ifi_flags;            /* IFF_xxx constants from <net/if.h> */
-    short ifi_myflags;          /* our own IFI_xxx flags */
-    int ifi_index;              /* interface index */
-    struct sockaddr  *ifi_addr; /* primary address */
-    struct sockaddr  *ifi_netmask;
-    struct sockaddr  *ifi_brdaddr; /* broadcast address */
-    struct sockaddr  *ifi_dstaddr; /* destination address */
-    struct ifi_info  *ifi_next; /* next of these structures */
-};
-
-#if defined(AF_INET6) && HAVE_IPV6 && HAVE_LINUX
-#define PROC_IFINET6_PATH "/proc/net/if_inet6"
-extern struct ifi_info  *get_ifi_info_linuxv6(int doaliases);
-#endif
-
 #if defined(AF_INET6) && HAVE_IPV6
 #define INET6_ADDRSTRLEN 46 /*Maximum length of IPv6 address */
 #endif
 
-
-
-#define IFI_ALIAS   1           /* ifi_addr is an alias */
-
-/* From the text (Stevens, section 16.6): */
-/* 'Since many programs need to know all the interfaces on a system, we will develop a */
-/* function of our own named get_ifi_info that returns a linked list of structures, one */
-/* for each interface that is currently "up."' */
-extern struct ifi_info  *get_ifi_info(int family, int doaliases);
-
-/* 'The free_ifi_info function, which takes a pointer that was */
-/* returned by get_ifi_info and frees all the dynamic memory.' */
-extern void             free_ifi_info(struct ifi_info *);
-
 #ifdef NOT_HAVE_DAEMON
 extern int daemon(int nochdir, int noclose);
 #endif
diff --git a/mDNSPosix/posix_utilities.c b/mDNSPosix/posix_utilities.c
new file mode 100644 (file)
index 0000000..89eca5b
--- /dev/null
@@ -0,0 +1,28 @@
+//
+//  posix_utilities.c
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#include "posix_utilities.h"
+#include "mDNSEmbeddedAPI.h"
+#include <stdlib.h>                 // for NULL
+#include <stdio.h>                  // for snprintf
+#include <time.h>
+#include <sys/time.h>               // for gettimeofday
+
+mDNSexport void getLocalTimestamp(char * const buffer, mDNSu32 buffer_len)
+{
+    struct timeval      now;
+    struct tm           local_time;
+    char                date_time_str[32];
+    char                time_zone_str[32];
+
+    gettimeofday(&now, NULL);
+    localtime_r(&now.tv_sec, &local_time);
+
+    strftime(date_time_str, sizeof(date_time_str), "%F %T", &local_time);
+    strftime(time_zone_str, sizeof(time_zone_str), "%z", &local_time);
+    snprintf(buffer, buffer_len, "%s.%06lu%s", date_time_str, (unsigned long)now.tv_usec, time_zone_str);
+}
diff --git a/mDNSPosix/posix_utilities.h b/mDNSPosix/posix_utilities.h
new file mode 100644 (file)
index 0000000..2eff6f3
--- /dev/null
@@ -0,0 +1,16 @@
+//
+//  posix_utilities.h
+//  mDNSResponder
+//
+//  Copyright (c) 2019 Apple Inc. All rights reserved.
+//
+
+#ifndef posix_utilities_h
+#define posix_utilities_h
+
+#include "mDNSEmbeddedAPI.h"
+
+// timestamp format: "2008-08-08 20:00:00.000000+0800", a 64-byte buffer is enough to store the result
+extern void getLocalTimestamp(char * const buffer, mDNSu32 buffer_len);
+
+#endif /* posix_utilities_h */
diff --git a/mDNSShared/ClientRequests.c b/mDNSShared/ClientRequests.c
new file mode 100644 (file)
index 0000000..6c139f4
--- /dev/null
@@ -0,0 +1,886 @@
+/*
+ * Copyright (c) 2018-2019 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.
+ */
+
+#include "ClientRequests.h"
+
+#include "DNSCommon.h"
+#include "uDNS.h"
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+#include "mDNSMacOSX.h"
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+#include <dispatch/dispatch.h>
+#include <net/if.h>
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+#include <WebFilterDNS/WebFilterDNS.h>
+
+int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
+int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
+int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
+#endif
+
+#define RecordTypeIsAddress(TYPE)   (((TYPE) == kDNSType_A) || ((TYPE) == kDNSType_AAAA))
+
+extern mDNS mDNSStorage;
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+extern domainname ActiveDirectoryPrimaryDomain;
+#endif
+
+// Normally we append search domains only for queries with a single label that are not fully qualified. This can be
+// overridden to apply search domains for queries (that are not fully qualified) with any number of labels e.g., moon,
+// moon.cs, moon.cs.be, etc. - Mohan
+mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
+
+// Control enabling optimistic DNS - Phil
+mDNSBool EnableAllowExpired = mDNStrue;
+
+mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp);
+mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation);
+mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, mDNSu32 inReqID, const domainname *inQName, mDNSu16 inQType,
+    mDNSu16 inQClass, mDNSInterfaceID inInterfaceID, mDNSs32 inServiceID, mDNSu32 inFlags, mDNSBool inAppendSearchDomains,
+    mDNSs32 inPID, const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler,
+    void *inResultContext);
+mDNSlocal void QueryRecordOpStop(QueryRecordOp *op);
+mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op);
+mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer,
+    QC_result inAddRecord);
+mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion);
+mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
+    const domainname *inSearchDomain);
+mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID);
+mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName);
+mDNSlocal mDNSBool StringEndsWithDot(const char *inString);
+mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp);
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *domain, mDNSBool inExcludeLocal);
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID);
+#endif
+
+mDNSexport mStatus GetAddrInfoClientRequestStart(GetAddrInfoClientRequest *inRequest, mDNSu32 inReqID,
+    const char *inHostnameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu32 inProtocols, mDNSs32 inPID,
+       const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler,
+    void *inResultContext)
+{
+    mStatus             err;
+    domainname          hostname;
+    mDNSBool            appendSearchDomains;
+    mDNSInterfaceID     interfaceID;
+    DNSServiceFlags     flags;
+       mDNSs32                         serviceID;
+
+    if (!MakeDomainNameFromDNSNameString(&hostname, inHostnameStr))
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%u] ERROR: bad hostname '" PRI_S "'", inReqID, inHostnameStr);
+        err = mStatus_BadParamErr;
+        goto exit;
+    }
+
+    if (inProtocols & ~(kDNSServiceProtocol_IPv4|kDNSServiceProtocol_IPv6))
+    {
+        err = mStatus_BadParamErr;
+        goto exit;
+    }
+
+    flags = inFlags;
+    if (!inProtocols)
+    {
+        flags |= kDNSServiceFlagsSuppressUnusable;
+        inRequest->protocols = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
+    }
+    else
+    {
+        inRequest->protocols = inProtocols;
+    }
+
+    if (flags & kDNSServiceFlagsServiceIndex)
+    {
+        // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
+        LogInfo("GetAddrInfoClientRequestStart: kDNSServiceFlagsServiceIndex is SET by the client");
+
+        // If kDNSServiceFlagsServiceIndex is SET, interpret the interfaceID as the serviceId and set the interfaceID to 0.
+        serviceID      = (mDNSs32)inInterfaceIndex;
+        interfaceID    = mDNSNULL;
+    }
+       else
+       {
+               serviceID = -1;
+        err = InterfaceIndexToInterfaceID(inInterfaceIndex, &interfaceID);
+        if (err) goto exit;
+       }
+    inRequest->interfaceID = interfaceID;
+
+    if (!StringEndsWithDot(inHostnameStr) && (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&hostname)))
+    {
+        appendSearchDomains = mDNStrue;
+    }
+    else
+    {
+        appendSearchDomains = mDNSfalse;
+    }
+
+    if (inRequest->protocols & kDNSServiceProtocol_IPv6)
+    {
+        err = QueryRecordOpCreate(&inRequest->op6);
+        if (err) goto exit;
+
+        err = QueryRecordOpStart(inRequest->op6, inReqID, &hostname, kDNSType_AAAA, kDNSServiceClass_IN,
+            inRequest->interfaceID, serviceID, flags, appendSearchDomains, inPID, inUUID, inUID, inResultHandler,
+            inResultContext);
+        if (err) goto exit;
+    }
+
+    if (inRequest->protocols & kDNSServiceProtocol_IPv4)
+    {
+        err = QueryRecordOpCreate(&inRequest->op4);
+        if (err) goto exit;
+
+        err = QueryRecordOpStart(inRequest->op4, inReqID, &hostname, kDNSType_A, kDNSServiceClass_IN,
+            inRequest->interfaceID, serviceID, flags, appendSearchDomains, inPID, inUUID, inUID, inResultHandler,
+            inResultContext);
+        if (err) goto exit;
+    }
+    err = mStatus_NoError;
+
+exit:
+    if (err) GetAddrInfoClientRequestStop(inRequest);
+    return err;
+}
+
+mDNSexport void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest *inRequest)
+{
+    if (inRequest->op4) QueryRecordOpStop(inRequest->op4);
+    if (inRequest->op6) QueryRecordOpStop(inRequest->op6);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+    {
+        const QueryRecordOp * const     op4 = inRequest->op4;
+        const QueryRecordOp * const     op6 = inRequest->op6;
+        const DNSQuestion *             q4  = mDNSNULL;
+        const DNSQuestion *             q6  = mDNSNULL;
+
+        if (op4)
+        {
+            if (op4->answered)
+            {
+                // If we have a v4 answer and if we timed out prematurely before, provide a trigger to the upper layer so
+                // that it can retry questions if needed. - Mohan
+                q4 = &op4->q;
+            }
+            else if (op4->q.TimeoutQuestion)
+            {
+                // If we are not delivering answers, we may be timing out prematurely. Note down the current state so that
+                // we know to retry when we see a valid response again. - Mohan
+                mDNSPlatformUpdateDNSStatus(&op4->q);
+            }
+        }
+        if (op6)
+        {
+            if (op6->answered)
+            {
+                q6 = &op6->q;
+            }
+            else if (op6->q.TimeoutQuestion)
+            {
+                mDNSPlatformUpdateDNSStatus(&op6->q);
+            }
+        }
+        mDNSPlatformTriggerDNSRetry(q4, q6);
+    }
+#endif
+
+    if (inRequest->op4)
+    {
+        QueryRecordOpFree(inRequest->op4);
+        inRequest->op4 = mDNSNULL;
+    }
+    if (inRequest->op6)
+    {
+        QueryRecordOpFree(inRequest->op6);
+        inRequest->op6 = mDNSNULL;
+    }
+}
+
+mDNSexport const domainname * GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest *inRequest)
+{
+    if (inRequest->op4) return &inRequest->op4->q.qname;
+    if (inRequest->op6) return &inRequest->op6->q.qname;
+    return (const domainname *)"";
+}
+
+mDNSexport mDNSBool GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest *inRequest)
+{
+    if ((inRequest->op4 && QueryRecordOpIsMulticast(inRequest->op4)) ||
+        (inRequest->op6 && QueryRecordOpIsMulticast(inRequest->op6)))
+    {
+        return mDNStrue;
+    }
+    return mDNSfalse;
+}
+
+mDNSexport mStatus QueryRecordClientRequestStart(QueryRecordClientRequest *inRequest, mDNSu32 inReqID,
+    const char *inQNameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu16 inQType, mDNSu16 inQClass,
+    mDNSs32 inPID, mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler, void *inResultContext)
+{
+    mStatus             err;
+    domainname          qname;
+    mDNSInterfaceID     interfaceID;
+    mDNSBool            appendSearchDomains;
+
+    err = InterfaceIndexToInterfaceID(inInterfaceIndex, &interfaceID);
+    if (err) goto exit;
+
+    if (!MakeDomainNameFromDNSNameString(&qname, inQNameStr))
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%u] ERROR: bad domain name '" PRI_S "'", inReqID, inQNameStr);
+        err = mStatus_BadParamErr;
+        goto exit;
+    }
+
+    if (RecordTypeIsAddress(inQType) && !StringEndsWithDot(inQNameStr) &&
+        (AlwaysAppendSearchDomains || DomainNameIsSingleLabel(&qname)))
+    {
+        appendSearchDomains = mDNStrue;
+    }
+    else
+    {
+        appendSearchDomains = mDNSfalse;
+    }
+
+    err = QueryRecordOpStart(&inRequest->op, inReqID, &qname, inQType, inQClass, interfaceID, -1, inFlags,
+        appendSearchDomains, inPID, inUUID, inUID, inResultHandler, inResultContext);
+
+exit:
+    if (err) QueryRecordClientRequestStop(inRequest);
+    return err;
+}
+
+mDNSexport void QueryRecordClientRequestStop(QueryRecordClientRequest *inRequest)
+{
+    QueryRecordOpStop(&inRequest->op);
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+    if (inRequest->op.answered)
+    {
+        DNSQuestion *v4q, *v6q;
+        // If we are receiving positive answers, provide the hint to the upper layer. - Mohan
+        v4q = (inRequest->op.q.qtype == kDNSType_A)    ? &inRequest->op.q : mDNSNULL;
+        v6q = (inRequest->op.q.qtype == kDNSType_AAAA) ? &inRequest->op.q : mDNSNULL;
+        mDNSPlatformTriggerDNSRetry(v4q, v6q);
+    }
+#endif
+}
+
+mDNSexport const domainname * QueryRecordClientRequestGetQName(const QueryRecordClientRequest *inRequest)
+{
+    return &inRequest->op.q.qname;
+}
+
+mDNSexport mDNSu16 QueryRecordClientRequestGetType(const QueryRecordClientRequest *inRequest)
+{
+    return inRequest->op.q.qtype;
+}
+
+mDNSexport mDNSBool QueryRecordClientRequestIsMulticast(QueryRecordClientRequest *inRequest)
+{
+    return (QueryRecordOpIsMulticast(&inRequest->op) ? mDNStrue : mDNSfalse);
+}
+
+mDNSlocal mStatus QueryRecordOpCreate(QueryRecordOp **outOp)
+{
+    mStatus err;
+    QueryRecordOp *op;
+
+    op = (QueryRecordOp *) mDNSPlatformMemAllocateClear(sizeof(*op));
+    if (!op)
+    {
+        err = mStatus_NoMemoryErr;
+        goto exit;
+    }
+    *outOp = op;
+    err = mStatus_NoError;
+
+exit:
+    return err;
+}
+
+mDNSlocal void QueryRecordOpFree(QueryRecordOp *operation)
+{
+    mDNSPlatformMemFree(operation);
+}
+
+#define VALID_MSAD_SRV_TRANSPORT(T) \
+    (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
+#define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
+
+mDNSlocal mStatus QueryRecordOpStart(QueryRecordOp *inOp, mDNSu32 inReqID, const domainname *inQName, mDNSu16 inQType,
+    mDNSu16 inQClass, mDNSInterfaceID inInterfaceID, mDNSs32 inServiceID, mDNSu32 inFlags, mDNSBool inAppendSearchDomains,
+    mDNSs32 inPID, const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler,
+    void *inResultContext)
+{
+    mStatus                 err;
+    DNSQuestion * const     q = &inOp->q;
+    mDNSu32                 len;
+
+    // Save the original qname.
+
+    len = DomainNameLength(inQName);
+    inOp->qname = (domainname *) mDNSPlatformMemAllocate(len);
+    if (!inOp->qname)
+    {
+        err = mStatus_NoMemoryErr;
+        goto exit;
+    }
+    mDNSPlatformMemCopy(inOp->qname, inQName, len);
+
+    inOp->interfaceID   = inInterfaceID;
+    inOp->reqID         = inReqID;
+    inOp->resultHandler = inResultHandler;
+    inOp->resultContext = inResultContext;
+
+    // Set up DNSQuestion.
+
+    if (EnableAllowExpired && (inFlags & kDNSServiceFlagsAllowExpiredAnswers))
+    {
+        q->allowExpired = AllowExpired_AllowExpiredAnswers;
+    }
+    else
+    {
+        q->allowExpired = AllowExpired_None;
+    }
+    q->ServiceID            = inServiceID;
+    q->InterfaceID          = inInterfaceID;
+    q->flags                = inFlags;
+    AssignDomainName(&q->qname, inQName);
+    q->qtype                = inQType;
+    q->qclass               = inQClass;
+    q->LongLived            = (inFlags & kDNSServiceFlagsLongLivedQuery)            ? mDNStrue : mDNSfalse;
+    q->ForceMCast           = (inFlags & kDNSServiceFlagsForceMulticast)            ? mDNStrue : mDNSfalse;
+    q->ReturnIntermed       = (inFlags & kDNSServiceFlagsReturnIntermediates)       ? mDNStrue : mDNSfalse;
+    q->SuppressUnusable     = (inFlags & kDNSServiceFlagsSuppressUnusable)          ? mDNStrue : mDNSfalse;
+    q->TimeoutQuestion      = (inFlags & kDNSServiceFlagsTimeout)                   ? mDNStrue : mDNSfalse;
+    q->UseBackgroundTraffic = (inFlags & kDNSServiceFlagsBackgroundTrafficClass)    ? mDNStrue : mDNSfalse;
+    q->AppendSearchDomains  = inAppendSearchDomains;
+    q->InitialCacheMiss     = mDNSfalse;
+
+    // Turn off dnssec validation for local domains and Question Types: RRSIG/ANY(ANY Type is not supported yet) - Mohan
+
+    q->ValidationRequired = DNSSEC_VALIDATION_NONE;
+    if (!IsLocalDomain(&q->qname) && (inQType != kDNSServiceType_RRSIG) && (inQType != kDNSServiceType_ANY))
+    {
+        if (inFlags & kDNSServiceFlagsValidate)
+        {
+            q->ValidationRequired   = DNSSEC_VALIDATION_SECURE;
+            q->AppendSearchDomains  = mDNSfalse;
+        }
+        else if (inFlags & kDNSServiceFlagsValidateOptional)
+        {
+            q->ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
+        }
+    }
+
+    q->pid              = inPID;
+    if (inUUID) mDNSPlatformMemCopy(q->uuid, inUUID, UUID_SIZE);
+    q->euid             = inUID;
+    q->request_id       = inReqID;
+    q->QuestionCallback = QueryRecordOpCallback;
+    q->ResetHandler     = QueryRecordOpResetHandler;
+
+    // For single label queries that are not fully qualified, look at /etc/hosts, cache and try search domains before trying
+    // them on the wire as a single label query. - Mohan
+
+    if (q->AppendSearchDomains && DomainNameIsSingleLabel(inOp->qname)) q->InterfaceID = mDNSInterface_LocalOnly;
+    err = QueryRecordOpStartQuestion(inOp, q);
+    if (err) goto exit;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+    if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
+    {
+        external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags);
+    }
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+    if ((RecordTypeIsAddress(q->qtype) || VALID_MSAD_SRV(&inOp->q)) && !q->ForceMCast &&
+        SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
+    {
+        DNSQuestion *       q2;
+
+        q2 = (DNSQuestion *) mDNSPlatformMemAllocate((mDNSu32)sizeof(*inOp->q2));
+        if (!q2)
+        {
+            err = mStatus_NoMemoryErr;
+            goto exit;
+        }
+        inOp->q2 = q2;
+
+        *q2 = *q;
+        q2->IsUnicastDotLocal = mDNStrue;
+
+        if ((CountLabels(&q2->qname) == 2) && !SameDomainName(&q2->qname, &ActiveDirectoryPrimaryDomain)
+            && !DomainNameIsInSearchList(&q2->qname, mDNSfalse))
+        {
+            inOp->q2Type                = q2->qtype;
+            inOp->q2LongLived           = q2->LongLived;
+            inOp->q2ReturnIntermed      = q2->ReturnIntermed;
+            inOp->q2TimeoutQuestion     = q2->TimeoutQuestion;
+            inOp->q2AppendSearchDomains = q2->AppendSearchDomains;
+
+            AssignDomainName(&q2->qname, &localdomain);
+            q2->qtype                   = kDNSType_SOA;
+            q2->LongLived               = mDNSfalse;
+            q2->ReturnIntermed          = mDNStrue;
+            q2->TimeoutQuestion         = mDNSfalse;
+            q2->AppendSearchDomains     = mDNSfalse;
+        }
+
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%u] QueryRecordOpStart: starting parallel unicast query for " PRI_DM_NAME " " PUB_S,
+               inOp->reqID, DM_NAME_PARAM(q2->qname.c), DNSTypeName(q2->qtype));
+
+        err = QueryRecordOpStartQuestion(inOp, q2);
+        if (err) goto exit;
+    }
+#endif
+    err = mStatus_NoError;
+
+exit:
+    if (err) QueryRecordOpStop(inOp);
+    return err;
+}
+
+mDNSlocal void QueryRecordOpStop(QueryRecordOp *op)
+{
+    if (op->q.QuestionContext)
+    {
+        QueryRecordOpStopQuestion(&op->q);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+        if (callExternalHelpers(op->q.InterfaceID, op->qname, op->q.flags))
+        {
+            external_stop_browsing_for_service(op->q.InterfaceID, &op->q.qname, op->q.qtype, op->q.flags);
+        }
+#endif
+    }
+    if (op->qname)
+    {
+        mDNSPlatformMemFree(op->qname);
+        op->qname = mDNSNULL;
+    }
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+    if (op->q2)
+    {
+        if (op->q2->QuestionContext) QueryRecordOpStopQuestion(op->q2);
+        mDNSPlatformMemFree(op->q2);
+        op->q2 = mDNSNULL;
+    }
+#endif
+}
+
+mDNSlocal mDNSBool QueryRecordOpIsMulticast(const QueryRecordOp *op)
+{
+    return ((mDNSOpaque16IsZero(op->q.TargetQID) && (op->q.ThisQInterval > 0)) ? mDNStrue : mDNSfalse);
+}
+
+// GetTimeNow is a callback-safe alternative to mDNS_TimeNow(), which expects to be called with m->mDNS_busy == 0.
+mDNSlocal mDNSs32 GetTimeNow(mDNS *m)
+{
+    mDNSs32 time;
+    mDNS_Lock(m);
+    time = m->timenow;
+    mDNS_Unlock(m);
+    return time;
+}
+
+mDNSlocal void QueryRecordOpCallback(mDNS *m, DNSQuestion *inQuestion, const ResourceRecord *inAnswer, QC_result inAddRecord)
+{
+    mStatus                     resultErr;
+    QueryRecordOp *const        op = (QueryRecordOp *)inQuestion->QuestionContext;
+    const domainname *          domain;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+    if ((inQuestion == op->q2) && (inQuestion->qtype == kDNSType_SOA))
+    {
+        DNSQuestion * const     q2 = op->q2;
+
+        if (inAnswer->rrtype != kDNSType_SOA) goto exit;
+        QueryRecordOpStopQuestion(q2);
+
+        // Restore DNSQuestion variables that were modified for the SOA query.
+
+        q2->qtype               = op->q2Type;
+        q2->LongLived           = op->q2LongLived;
+        q2->ReturnIntermed      = op->q2ReturnIntermed;
+        q2->TimeoutQuestion     = op->q2TimeoutQuestion;
+        q2->AppendSearchDomains = op->q2AppendSearchDomains;
+
+        if (inAnswer->RecordType != kDNSRecordTypePacketNegative)
+        {
+            QueryRecordOpRestartUnicastQuestion(op, q2, mDNSNULL);
+        }
+        else if (q2->AppendSearchDomains)
+        {
+            domain = NextSearchDomain(op);
+            if (domain) QueryRecordOpRestartUnicastQuestion(op, q2, domain);
+        }
+        goto exit;
+    }
+#endif
+
+    if (inAddRecord == QC_suppressed)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+               "[R%u] QueryRecordOpCallback: Suppressed question " PRI_DM_NAME " (" PUB_S ")",
+               op->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype));
+
+        resultErr = kDNSServiceErr_NoSuchRecord;
+    }
+    else if (inAnswer->RecordType == kDNSRecordTypePacketNegative)
+    {
+        if (inQuestion->TimeoutQuestion && ((GetTimeNow(m) - inQuestion->StopTime) >= 0))
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                   "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") timing out, InterfaceID %p",
+                   op->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype),
+                   inQuestion->InterfaceID);
+            resultErr = kDNSServiceErr_Timeout;
+        }
+        else
+        {
+            if (inQuestion->AppendSearchDomains && (op->searchListIndex >= 0) && inAddRecord && (inAddRecord != QC_dnssec))
+            {
+                domain = NextSearchDomain(op);
+                if (domain || DomainNameIsSingleLabel(op->qname))
+                {
+                    QueryRecordOpStopQuestion(inQuestion);
+                    QueryRecordOpRestartUnicastQuestion(op, inQuestion, domain);
+                    goto exit;
+                }
+            }
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+            if (!inAnswer->InterfaceID && IsLocalDomain(inAnswer->name))
+            {
+                if ((RecordTypeIsAddress(inQuestion->qtype) &&
+                    (inAnswer->negativeRecordType == kNegativeRecordType_NoData)) ||
+                    DomainNameIsInSearchList(&inQuestion->qname, mDNStrue))
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                           "[R%u] QueryRecordOpCallback: Question " PRI_DM_NAME " (" PUB_S ") answering local with negative unicast response",
+                           op->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype));
+                }
+                else
+                {
+                    goto exit;
+                }
+            }
+#endif
+            resultErr = kDNSServiceErr_NoSuchRecord;
+        }
+    }
+    else
+    {
+        resultErr = kDNSServiceErr_NoError;
+    }
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+    if ((resultErr != kDNSServiceErr_Timeout) && (inAddRecord == QC_add))
+    {
+        op->answered = mDNStrue;
+    }
+#endif
+
+    if (op->resultHandler) op->resultHandler(m, inQuestion, inAnswer, inAddRecord, resultErr, op->resultContext);
+    if (resultErr == kDNSServiceErr_Timeout) QueryRecordOpStopQuestion(inQuestion);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+       NotifyWebContentFilter(inAnswer, inQuestion->euid);
+#endif
+
+exit:
+    return;
+}
+
+mDNSlocal void QueryRecordOpResetHandler(DNSQuestion *inQuestion)
+{
+    QueryRecordOp *const        op = (QueryRecordOp *)inQuestion->QuestionContext;
+
+    AssignDomainName(&inQuestion->qname, op->qname);
+    if (inQuestion->AppendSearchDomains && DomainNameIsSingleLabel(op->qname))
+    {
+        inQuestion->InterfaceID = mDNSInterface_LocalOnly;
+    }
+    else
+    {
+        inQuestion->InterfaceID = op->interfaceID;
+    }
+    op->searchListIndex = 0;
+}
+
+mDNSlocal mStatus QueryRecordOpStartQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion)
+{
+    mStatus     err;
+
+    inQuestion->QuestionContext = inOp;
+    err = mDNS_StartQuery(&mDNSStorage, inQuestion);
+    if (err)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%u] ERROR: QueryRecordOpStartQuestion mDNS_StartQuery for " PRI_DM_NAME " " PUB_S " failed with error %d",
+               inOp->reqID, DM_NAME_PARAM(inQuestion->qname.c), DNSTypeName(inQuestion->qtype), err);
+        inQuestion->QuestionContext = mDNSNULL;
+    }
+    return err;
+}
+
+mDNSlocal mStatus QueryRecordOpStopQuestion(DNSQuestion *inQuestion)
+{
+    mStatus     err;
+
+    err = mDNS_StopQuery(&mDNSStorage, inQuestion);
+    inQuestion->QuestionContext = mDNSNULL;
+    return err;
+}
+
+mDNSlocal mStatus QueryRecordOpRestartUnicastQuestion(QueryRecordOp *inOp, DNSQuestion *inQuestion,
+    const domainname *inSearchDomain)
+{
+    mStatus     err;
+
+    inQuestion->InterfaceID = inOp->interfaceID;
+    AssignDomainName(&inQuestion->qname, inOp->qname);
+    if (inSearchDomain) AppendDomainName(&inQuestion->qname, inSearchDomain);
+    if (SameDomainLabel(LastLabel(&inQuestion->qname), (const mDNSu8 *)&localdomain))
+    {
+        inQuestion->IsUnicastDotLocal = mDNStrue;
+    }
+    else
+    {
+        inQuestion->IsUnicastDotLocal = mDNSfalse;
+    }
+    err = QueryRecordOpStartQuestion(inOp, inQuestion);
+    return err;
+}
+
+mDNSlocal mStatus InterfaceIndexToInterfaceID(mDNSu32 inInterfaceIndex, mDNSInterfaceID *outInterfaceID)
+{
+    mStatus             err;
+    mDNSInterfaceID     interfaceID;
+
+    interfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, inInterfaceIndex);
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+    // The request is scoped to a specific interface index, but the interface is not currently in our list.
+    if ((inInterfaceIndex != kDNSServiceInterfaceIndexAny) && (interfaceID == mDNSInterface_Any))
+    {
+        static dispatch_once_t      getLoopbackIndexOnce = 0;
+        static mDNSu32              loopbackIndex = 0;
+
+        dispatch_once(&getLoopbackIndexOnce,
+        ^{
+            loopbackIndex = if_nametoindex("lo0");
+        });
+
+        // If it's one of the specially defined inteface index values, just return an error. Also, caller should return an
+        // error immediately if lo0 is not configured into the current active interfaces. See <rdar://problem/21967160>.
+        if ((inInterfaceIndex == kDNSServiceInterfaceIndexLocalOnly) ||
+            (inInterfaceIndex == kDNSServiceInterfaceIndexUnicast)   ||
+            (inInterfaceIndex == kDNSServiceInterfaceIndexP2P)       ||
+            (inInterfaceIndex == kDNSServiceInterfaceIndexBLE)       ||
+            (inInterfaceIndex == loopbackIndex))
+        {
+            LogInfo("ERROR: bad interfaceIndex %d", inInterfaceIndex);
+            err = mStatus_BadParamErr;
+            goto exit;
+        }
+
+        // Otherwise, use the specified interface index value and the request will be applied to that interface when it
+        // comes up.
+        interfaceID = (mDNSInterfaceID)(uintptr_t)inInterfaceIndex;
+        LogInfo("Query pending for interface index %d", inInterfaceIndex);
+    }
+#endif
+
+    *outInterfaceID = interfaceID;
+    err = mStatus_NoError;
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNREADY_INTERFACES)
+exit:
+#endif
+    return err;
+}
+
+mDNSlocal mDNSBool DomainNameIsSingleLabel(const domainname *inName)
+{
+    const mDNSu8 *const     label = inName->c;
+    return (((label[0] != 0) && (label[1 + label[0]] == 0)) ? mDNStrue : mDNSfalse);
+}
+
+mDNSlocal mDNSBool StringEndsWithDot(const char *inString)
+{
+    const char *        ptr;
+    mDNSu32             escapeCount;
+    mDNSBool            result;
+
+    // Loop invariant: escapeCount is the number of consecutive escape characters that immediately precede *ptr.
+    // - If escapeCount is even, then *ptr is immediately preceded by escapeCount / 2 consecutive literal backslash
+    //   characters, so *ptr is not escaped.
+    // - If escapeCount is odd, then *ptr is immediately preceded by (escapeCount - 1) / 2 consecutive literal backslash
+    //   characters followed by an escape character, so *ptr is escaped.
+    escapeCount = 0;
+    result = mDNSfalse;
+    for (ptr = inString; *ptr != '\0'; ptr++)
+    {
+        if (*ptr == '\\')
+        {
+            escapeCount++;
+        }
+        else
+        {
+            if ((*ptr == '.') && (ptr[1] == '\0'))
+            {
+                if ((escapeCount % 2) == 0) result = mDNStrue;
+                break;
+            }
+            escapeCount = 0;
+        }
+    }
+    return result;
+}
+
+mDNSlocal const domainname * NextSearchDomain(QueryRecordOp *inOp)
+{
+    const domainname *      domain;
+
+    while ((domain = uDNS_GetNextSearchDomain(inOp->interfaceID, &inOp->searchListIndex, mDNSfalse)) != mDNSNULL)
+    {
+        if ((DomainNameLength(inOp->qname) - 1 + DomainNameLength(domain)) <= MAX_DOMAIN_NAME) break;
+    }
+    if (!domain) inOp->searchListIndex = -1;
+    return domain;
+}
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+mDNSlocal mDNSBool DomainNameIsInSearchList(const domainname *inName, mDNSBool inExcludeLocal)
+{
+    const SearchListElem *      item;
+    int                         labelCount, domainLabelCount;
+
+    labelCount = CountLabels(inName);
+    for (item = SearchList; item; item = item->next)
+    {
+        if (inExcludeLocal && SameDomainName(&item->domain, &localdomain)) continue;
+        domainLabelCount = CountLabels(&item->domain);
+        if (labelCount >= domainLabelCount)
+        {
+            if (SameDomainName(&item->domain, SkipLeadingLabels(inName, (labelCount - domainLabelCount))))
+            {
+                return mDNStrue;
+            }
+        }
+    }
+    return mDNSfalse;
+}
+#endif
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, WEB_CONTENT_FILTER)
+mDNSlocal void NotifyWebContentFilter(const ResourceRecord *inAnswer, uid_t inUID)
+{
+    if (WCFIsServerRunning)
+    {
+               const mDNS *const m = &mDNSStorage;
+
+        if (WCFIsServerRunning(m->WCF) && inAnswer->rdlength != 0)
+        {
+                       struct sockaddr_storage addr;
+                       addr.ss_len = 0;
+                       if (inAnswer->rrtype == kDNSType_A || inAnswer->rrtype == kDNSType_AAAA)
+                       {
+                               if (inAnswer->rrtype == kDNSType_A)
+                               {
+                                       struct sockaddr_in *const sin = (struct sockaddr_in *)&addr;
+                                       sin->sin_port = 0;
+                                       // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
+                                       // sin->sin_addr.s_addr = inAnswer->rdata->u.ipv4.NotAnInteger;
+                                       if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(mDNSv4Addr)), inAnswer))
+                                               LogMsg("NotifyWebContentFilter: WCF AF_INET putRData failed");
+                                       else
+                                       {
+                                               addr.ss_len = sizeof (struct sockaddr_in);
+                                               addr.ss_family = AF_INET;
+                                       }
+                               }
+                               else if (inAnswer->rrtype == kDNSType_AAAA)
+                               {
+                                       struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&addr;
+                                       sin6->sin6_port = 0;
+                                       // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
+                                       // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = inAnswer->rdata->u.ipv6.l[0];
+                                       // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = inAnswer->rdata->u.ipv6.l[1];
+                                       // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = inAnswer->rdata->u.ipv6.l[2];
+                                       // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = inAnswer->rdata->u.ipv6.l[3];
+                                       if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(mDNSv6Addr)), inAnswer))
+                                               LogMsg("NotifyWebContentFilter: WCF AF_INET6 putRData failed");
+                                       else
+                                       {
+                                               addr.ss_len = sizeof (struct sockaddr_in6);
+                                               addr.ss_family = AF_INET6;
+                                       }
+                               }
+                               if (addr.ss_len)
+                               {
+                               char name[MAX_ESCAPED_DOMAIN_NAME];
+                               ConvertDomainNameToCString(inAnswer->name, name);
+
+                                       debugf("NotifyWebContentFilter: Name %s, uid %u, addr length %d", name, inUID, addr.ss_len);
+                                       if (WCFNameResolvesToAddr)
+                                       {
+                                               WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, inUID);
+                                       }
+                               }
+                       }
+                       else if (inAnswer->rrtype == kDNSType_CNAME)
+                       {
+                               domainname cname;
+                       char name[MAX_ESCAPED_DOMAIN_NAME];
+                               char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
+
+                               if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), inAnswer))
+                                       LogMsg("NotifyWebContentFilter: WCF CNAME putRData failed");
+                               else
+                               {
+                               ConvertDomainNameToCString(inAnswer->name, name);
+                                       ConvertDomainNameToCString(&cname, cname_cstr);
+                                       if (WCFNameResolvesToAddr)
+                                       {
+                                               WCFNameResolvesToName(m->WCF, name, cname_cstr, inUID);
+                                       }
+                               }
+                       }
+        }
+    }
+}
+#endif
diff --git a/mDNSShared/ClientRequests.h b/mDNSShared/ClientRequests.h
new file mode 100644 (file)
index 0000000..82f8d77
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018-2019 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.
+ */
+
+#ifndef __ClientRequests_h
+#define __ClientRequests_h
+
+#include "mDNSEmbeddedAPI.h"
+#include "dns_sd_internal.h"
+
+typedef void (*QueryRecordResultHandler)(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord,
+    DNSServiceErrorType error, void *context);
+
+typedef struct
+{
+    DNSQuestion                 q;                      // DNSQuestion for record query.
+    domainname *                qname;                  // Name of the original record.
+    mDNSInterfaceID             interfaceID;            // Interface over which to perform query.
+    QueryRecordResultHandler    resultHandler;          // Handler for query record operation results.
+    void *                      resultContext;          // Context to pass to result handler.
+    mDNSu32                     reqID;                  // 
+    int                         searchListIndex;        // Index that indicates the next search domain to try.
+#if MDNSRESPONDER_SUPPORTS(APPLE, UNICAST_DOTLOCAL)
+    DNSQuestion *               q2;                     // DNSQuestion for unicast version of a record with a dot-local name.
+    mDNSu16                     q2Type;                 // q2's original qtype value.
+    mDNSBool                    q2LongLived;            // q2's original LongLived value.
+    mDNSBool                    q2ReturnIntermed;       // q2's original ReturnIntermed value.
+    mDNSBool                    q2TimeoutQuestion;      // q2's original TimeoutQuestion value.
+    mDNSBool                    q2AppendSearchDomains;  // q2's original AppendSearchDomains value.
+#endif
+#if MDNSRESPONDER_SUPPORTS(APPLE, REACHABILITY_TRIGGER)
+    mDNSBool                    answered;               // True if the query was answered.
+#endif
+
+}   QueryRecordOp;
+
+typedef struct
+{
+    mDNSInterfaceID     interfaceID;    // InterfaceID being used for query record operations.
+    mDNSu32             protocols;      // Protocols (IPv4, IPv6) specified by client.
+    QueryRecordOp *     op4;            // Query record operation object for A record.
+    QueryRecordOp *     op6;            // Query record operation object for AAAA record.
+
+}   GetAddrInfoClientRequest;
+
+typedef struct
+{
+    QueryRecordOp       op; // Query record operation object.
+
+}   QueryRecordClientRequest;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+mDNSexport mStatus GetAddrInfoClientRequestStart(GetAddrInfoClientRequest *inRequest, mDNSu32 inReqID,
+    const char *inHostnameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu32 inProtocols, mDNSs32 inPID,
+    const mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler, void *inResultContext);
+mDNSexport void GetAddrInfoClientRequestStop(GetAddrInfoClientRequest *inRequest);
+mDNSexport const domainname * GetAddrInfoClientRequestGetQName(const GetAddrInfoClientRequest *inRequest);
+mDNSexport mDNSBool GetAddrInfoClientRequestIsMulticast(const GetAddrInfoClientRequest *inRequest);
+
+mDNSexport mStatus QueryRecordClientRequestStart(QueryRecordClientRequest *inRequest, mDNSu32 inReqID,
+    const char *inQNameStr, mDNSu32 inInterfaceIndex, DNSServiceFlags inFlags, mDNSu16 inQType, mDNSu16 inQClass,
+    mDNSs32 inPID, mDNSu8 inUUID[UUID_SIZE], mDNSu32 inUID, QueryRecordResultHandler inResultHandler, void *inResultContext);
+mDNSexport void QueryRecordClientRequestStop(QueryRecordClientRequest *inRequest);
+mDNSexport const domainname * QueryRecordClientRequestGetQName(const QueryRecordClientRequest *inRequest);
+mDNSexport mDNSu16 QueryRecordClientRequestGetType(const QueryRecordClientRequest *inRequest);
+mDNSexport mDNSBool QueryRecordClientRequestIsMulticast(QueryRecordClientRequest *inRequest);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // __ClientRequests_h
index fecfb0f38864388244c2466d7c8901f3e1e451b2..55353bc79452b10ef2059c098818bf11a6f2e2a5 100644 (file)
@@ -18,7 +18,7 @@
 //---------------------------------------------------------------------------------------------------------------------------
 /*!    @header         CommonServices
 
-    Common Services for Mac OS X, Linux, Palm, VxWorks, Windows, and Windows CE.
+    Common Services for Mac OS X, Linux, Palm, Windows, and Windows CE.
  */
 
 #ifndef __COMMON_SERVICES__
@@ -94,19 +94,6 @@ extern "C" {
     #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( __FreeBSD__ ) && !defined( __linux__ ) && !defined ( __SVR4 ) && !defined ( __sun ) && !defined( __PALMOS_TRAPS__ ) && !defined( __PALMOS_ARMLET__ ) && !defined( _WIN32 ) )
-        #define TARGET_OS_VXWORKS       1
-    #else
-        #define TARGET_OS_VXWORKS       0
-    #endif
-#endif
-
 // Windows
 
 #if ( !defined( TARGET_OS_WIN32 ) )
@@ -225,12 +212,6 @@ extern "C" {
 
 // Palm (no special includes yet).
 
-#elif ( TARGET_OS_VXWORKS )
-
-// VxWorks
-
-    #include    "vxWorks.h"
-
 #elif ( TARGET_OS_WIN32 )
 
 // Windows
@@ -275,15 +256,7 @@ extern "C" {
 #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
+    #define TARGET_BUILD_MAIN       1
 #endif
 
 #if 0
@@ -439,9 +412,7 @@ extern "C" {
     #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
@@ -451,21 +422,16 @@ typedef SOCKET SocketRef;
     #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 )
+#if ( ( TARGET_OS_MAC && !defined( SO_NOADDRERR ) ) || ( TARGET_OS_WIN32 && !defined( EAI_AGAIN ) ) )
 typedef int socklen_t;
-    #endif
 #endif
 
 // ssize_t is not defined on the following platforms so emulate it if not defined:
@@ -473,19 +439,15 @@ typedef int socklen_t;
 // - 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_FREEBSD && !TARGET_OS_LINUX && !TARGET_OS_VXWORKS && !TARGET_OS_MAC)
+#if ( !defined(_SSIZE_T) && ( TARGET_OS_WIN32 || !defined( _BSD_SSIZE_T_DEFINED_ ) ) && !TARGET_OS_FREEBSD && !TARGET_OS_LINUX && !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 ) )
+#if ( !defined( AF_INET6 ) )
         #define sockaddr_storage        sockaddr_in
         #define ss_family               sin_family
-    #endif
 #endif
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -738,7 +700,6 @@ typedef int ssize_t;
 #pragma mark == Types ==
 #endif
 
-#if ( TARGET_LANGUAGE_C_LIKE )
 //===========================================================================================================================
 //      Standard Types
 //===========================================================================================================================
@@ -759,10 +720,6 @@ 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;
@@ -912,11 +869,7 @@ typedef int bool;
     @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
@@ -925,11 +878,7 @@ typedef char CStr255[ 256 ];
  */
 
 #if ( !defined( TYPE_LONGLONG_NATIVE ) )
-    #if ( !TARGET_OS_VXWORKS )
-        #define TYPE_LONGLONG_NATIVE            1
-    #else
-        #define TYPE_LONGLONG_NATIVE            0
-    #endif
+    #define TYPE_LONGLONG_NATIVE            1
 #endif
 
 //---------------------------------------------------------------------------------------------------------------------------
@@ -943,14 +892,12 @@ typedef char CStr255[ 256 ];
     "__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 )
+#if ( TARGET_OS_WIN32 )
 typedef __int64 long_long_compat;
 typedef unsigned __int64 unsigned_long_long_compat;
-    #else
+#else
 typedef signed long long long_long_compat;
 typedef unsigned long long unsigned_long_long_compat;
-    #endif
 #endif
 
 #if 0
@@ -1030,10 +977,8 @@ typedef unsigned long long unsigned_long_long_compat;
     @constant  kNoSpaceErr                                     -6763 Not enough space to perform operation.
  */
 
-#if ( TARGET_LANGUAGE_C_LIKE )
-    #if ( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
+#if ( !TARGET_OS_MAC && !TARGET_API_MAC_OSX_KERNEL )
 typedef int32_t OSStatus;
-    #endif
 #endif
 
 #define kNoErr                      0
@@ -1138,10 +1083,8 @@ typedef int32_t OSStatus;
     to wait for 5 seconds you would use "5 * kDurationSecond".
  */
 
-#if ( TARGET_LANGUAGE_C_LIKE )
-    #if ( !TARGET_OS_MAC )
+#if ( !TARGET_OS_MAC )
 typedef int32_t Duration;
-    #endif
 #endif
 
 #define kDurationImmediate              0L
@@ -1213,9 +1156,7 @@ typedef int32_t Duration;
         left = right ->  0
  */
 
-#if ( TARGET_LANGUAGE_C_LIKE )
 int NumVersionCompare( uint32_t inLeft, uint32_t inRight );
-#endif
 
 #if 0
 #pragma mark == Binary Constants ==
@@ -1535,9 +1476,7 @@ int NumVersionCompare( uint32_t inLeft, uint32_t inRight );
  */
 
 #if ( DEBUG )
-    #if ( TARGET_LANGUAGE_C_LIKE )
 OSStatus    CommonServicesTest( void );
-    #endif
 #endif
 
 #ifdef  __cplusplus
index 44305a5c99701665fbf19ce7fa7a539fd791af1b..5b2e23a2b0b1393329440082ca80c1f2960d72a0 100644 (file)
 
 #if ( DEBUG )
 
-#if ( TARGET_OS_VXWORKS )
-    #include    "intLib.h"
-#endif
-
 #if ( TARGET_OS_WIN32 )
     #include    <time.h>
 
@@ -170,27 +166,6 @@ DebugWinCharToTCharString(
 //     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;
@@ -245,15 +220,6 @@ DEBUG_EXPORT OSStatus   DebugInitialize( DebugOutputType inType, ... )
 
     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 )
@@ -289,12 +255,6 @@ DEBUG_EXPORT OSStatus   DebugInitialize( DebugOutputType inType, ... )
             #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;
@@ -565,10 +525,6 @@ static OSStatus DebugPrint( DebugLevel inLevel, char *inData, size_t inSize )
 
     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;
     }
@@ -2450,13 +2406,6 @@ DEBUG_EXPORT uint32_t   DebugTaskLevel( void )
 
     level = 0;
 
-#if ( TARGET_OS_VXWORKS )
-    if( intContext() )
-    {
-        level |= ( ( 1 << kDebugInterruptLevelShift ) & kDebugInterruptLevelMask );
-    }
-#endif
-
     return( level );
 }
 
index 108f7f5f9a16960791ac7db09a83085131aed224..c0cd576a0918d2298acdf04d5df804b700b17d02 100644 (file)
 
 #include    "CommonServices.h"
 
-#if ( TARGET_OS_VXWORKS )
-    #include    "logLib.h"
-#endif
-
 #if 0
 #pragma mark == Settings ==
 #endif
@@ -1247,30 +1243,6 @@ typedef uint32_t DebugPropertyTag;
     #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
index 1c6cb5be7c9486dc612881afd7967ca80558f23e..2135c6ae8803bf44c08c1a19ba009119bf836e43 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
@@ -255,6 +254,9 @@ int     OffsetRemoveFromList( GenLinkedOffsetList *pList, void *elem)
 {
     void    *iElem, *lastElem;
 
+    if (elem == NULL) {
+        return 0;
+    }
     for ( iElem = GetHeadPtr( pList), lastElem = NULL; iElem;
           iElem = GetOffsetLink( pList, iElem))
     {
index 49c8fd19e2dab102438a4556dd134b12396f1681..f3b2aab8829b38f481755b455062656d7b35579a 100644 (file)
@@ -1,6 +1,6 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
- * Copyright (c) 2004-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2019 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.
  * WITHOUT 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 defines functions that are common to platforms with Posix APIs.
+ * Current examples are mDNSMacOSX and mDNSPosix.
  */
 
 #include <stdio.h>              // Needed for fopen() etc.
 #include <unistd.h>             // Needed for close()
+#include <stdlib.h>             // Needed for malloc()
 #include <string.h>             // Needed for strlen() etc.
 #include <errno.h>              // Needed for errno etc.
 #include <sys/socket.h>         // Needed for socket() etc.
 #include <netinet/in.h>         // Needed for sockaddr_in
 #include <syslog.h>
+#include <sys/fcntl.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <assert.h>
 
 #if APPLE_OSX_mDNSResponder
 #include <os/log.h>
 typedef unsigned int socklen_t;
 #endif
 
+#if MDNS_MALLOC_DEBUGGING
+// We ONLY want this for malloc debugging--on a running production system we want to deal with
+// malloc failures, not just die.   There is a small performance penalty for enabling these options
+// as well, so they are all only appropriate for debugging.   The flags mean:
+//
+// A = warnings are errors
+// X = abort on failure
+// Z = sets J & R
+// J = allocated memory is initialized to a pattern
+// R causes realloc to always reallocate even if not needed
+
+char _malloc_options[] = "AXZ";
+
+mDNSlocal mDNSListValidator *listValidators;
+
+mDNSexport void mDNSPlatformAddListValidator(mDNSListValidator *lv, mDNSListValidationFunction *lvf,
+                                             const char *lvfName, void *context)
+{
+    mDNSPlatformMemZero(lv, sizeof *lv);
+    lv->validator = lvf;
+    lv->validationFunctionName = lvfName;
+    lv->context = context;
+    lv->next = listValidators;
+    listValidators = lv;
+}
+
+mDNSlocal void validateLists(void)
+{
+    mDNSListValidator *vfp;
+    // Check Unix Domain Socket client lists (uds_daemon.c)
+    for (vfp = listValidators; vfp; vfp = vfp->next)
+    {
+        vfp->validator(vfp->context);
+    }
+
+    mDNSPlatformValidateLists();
+}
+
+#define kAllocMagic     0xDEAD1234
+#define kGuardMagic     0xDEAD1234
+#define kFreeMagic      0xDEADDEAD
+#define kAllocLargeSize 32768
+
+mDNSexport void *mallocL(const char *msg, mDNSu32 size)
+{
+    // Allocate space for two words of sanity checking data before the requested block and two words after.
+    // Adjust the length for alignment.
+    mDNSu32 *mem = malloc(sizeof(mDNSu32) * 4 + size);
+    mDNSu32 guard[2];
+    if (!mem)
+    { LogMsg("malloc( %s : %u ) failed", msg, size); return(NULL); }
+    else
+    {
+        mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
+        if      (size > kAllocLargeSize)      LogMsg("malloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
+        else if (MDNS_MALLOC_DEBUGGING >= 2)  LogMsg("malloc( %s : %lu ) @ %p",                    msg, size, &mem[2]);
+        mem[  0] = kAllocMagic;
+        guard[0] = kGuardMagic;
+        mem[  1] = size;
+        guard[1] = size;
+        memcpy(after, &guard, sizeof guard);
+        memset(&mem[2], 0xFF, size);
+        validateLists();
+        return(&mem[2]);
+    }
+}
+
+mDNSexport void *callocL(const char *msg, mDNSu32 size)
+{
+    mDNSu32 guard[2];
+    const mDNSu32 headerSize = 4 * sizeof(mDNSu32);
+    
+    // Allocate space for two words of sanity checking data before the requested block and two words after.
+    // Adjust the length for alignment.
+    mDNSu32 *mem = (mDNSu32 *)calloc(1, headerSize + size);
+    if (!mem)
+    { LogMsg("calloc( %s : %u ) failed", msg, size); return(NULL); }
+    else
+    {
+        mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)(mem + 2) + size);
+        if      (size > kAllocLargeSize)     LogMsg("calloc( %s : %lu ) @ %p suspiciously large", msg, size, &mem[2]);
+        else if (MDNS_MALLOC_DEBUGGING >= 2) LogMsg("calloc( %s : %lu ) @ %p",                    msg, size, &mem[2]);
+        mem[  0] = kAllocMagic;
+        guard[0] = kGuardMagic;
+        mem[  1] = size;
+        guard[1] = size;
+        memcpy(after, guard, sizeof guard);
+        validateLists();
+        return(&mem[2]);
+    }
+}
+
+mDNSexport void freeL(const char *msg, void *x)
+{
+    if (!x)
+        LogMsg("free( %s @ NULL )!", msg);
+    else
+    {
+        mDNSu32 *mem = ((mDNSu32 *)x) - 2;
+        if      (mem[0] == kFreeMagic)  { LogMemCorruption("free( %s : %lu @ %p ) !!!! ALREADY DISPOSED !!!!", msg, mem[1], &mem[2]); return; }
+        if      (mem[0] != kAllocMagic) { LogMemCorruption("free( %s : %lu @ %p ) !!!! NEVER ALLOCATED !!!!",  msg, mem[1], &mem[2]); return; }
+        if      (mem[1] > kAllocLargeSize)          LogMsg("free( %s : %lu @ %p) suspiciously large",          msg, mem[1], &mem[2]);
+        else if (MDNS_MALLOC_DEBUGGING >= 2)        LogMsg("free( %s : %ld @ %p)",                             msg, mem[1], &mem[2]);
+        mDNSu32 *after = (mDNSu32 *)((mDNSu8 *)x + mem[1]);
+        mDNSu32 guard[2];
+
+        memcpy(guard, after, sizeof guard);
+        if (guard[0] != kGuardMagic)    { LogMemCorruption("free( %s : %lu @ %p ) !!!! END GUARD OVERWRITE !!!!",
+                                                           msg, mem[1], &mem[2]); return; }
+        if (guard[1] != mem[1])         { LogMemCorruption("free( %s : %lu @ %p ) !!!! LENGTH MISMATCH !!!!",
+                                                           msg, mem[1], &mem[2]); return; }
+        mem[0] = kFreeMagic;
+        memset(mem + 2, 0xFF, mem[1] + 2 * sizeof(mDNSu32));
+        validateLists();
+        free(mem);
+    }
+}
+
+#endif
+
 // Bind a UDP socket to find the source address to a destination
 mDNSexport void mDNSPlatformSourceAddrForDest(mDNSAddr *const src, const mDNSAddr *const dst)
 {
@@ -131,9 +259,9 @@ mDNSexport void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const fi
 
     if (domain && domain->c[0] && buf[0])
     {
-        DomainAuthInfo *info = (DomainAuthInfo*)mDNSPlatformMemAllocate(sizeof(*info));
+        DomainAuthInfo *info = (DomainAuthInfo*) mDNSPlatformMemAllocateClear(sizeof(*info));
         // for now we assume keyname = service reg domain and we use same key for service and hostname registration
-        err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0, mDNSfalse);
+        err = mDNS_SetSecretForDomain(m, info, domain, domain, buf, NULL, 0);
         if (err) LogMsg("ERROR: mDNS_SetSecretForDomain returned %d for domain %##s", err, domain->c);
     }
 
@@ -152,6 +280,7 @@ mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
 }
 #endif
 
+#if !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
 mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, mDNSLogLevel_t loglevel)
 {
 #if APPLE_OSX_mDNSResponder && LogTimeStamps
@@ -175,26 +304,16 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, m
     {
         static int log_inited = 0;
 
-        int syslog_level = LOG_ERR;
+        int syslog_level;
         switch (loglevel)
         {
-#if APPLE_OSX_mDNSResponder
-        case MDNS_LOG_MSG:       syslog_level = OS_LOG_TYPE_DEFAULT;     break;
-        case MDNS_LOG_OPERATION: syslog_level = OS_LOG_TYPE_INFO;        break;
-        case MDNS_LOG_SPS:       syslog_level = OS_LOG_TYPE_INFO;        break;
-        case MDNS_LOG_INFO:      syslog_level = OS_LOG_TYPE_INFO;        break;
-        case MDNS_LOG_DEBUG:     syslog_level = OS_LOG_TYPE_DEBUG;       break;
-        default:                 syslog_level = OS_LOG_TYPE_DEFAULT;     break;
-#else
-        case MDNS_LOG_MSG:       syslog_level = LOG_ERR;     break;
-        case MDNS_LOG_OPERATION: syslog_level = LOG_WARNING; break;
-        case MDNS_LOG_SPS:       syslog_level = LOG_NOTICE;  break;
-        case MDNS_LOG_INFO:      syslog_level = LOG_INFO;    break;
-        case MDNS_LOG_DEBUG:     syslog_level = LOG_DEBUG;   break;
-        default:
-            fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
-            fflush(stderr);
-#endif
+            case MDNS_LOG_FAULT:     syslog_level = LOG_ERR;     break;
+            case MDNS_LOG_ERROR:     syslog_level = LOG_ERR;     break;
+            case MDNS_LOG_WARNING:   syslog_level = LOG_WARNING; break;
+            case MDNS_LOG_DEFAULT:   syslog_level = LOG_NOTICE;  break;
+            case MDNS_LOG_INFO:      syslog_level = LOG_INFO;    break;
+            case MDNS_LOG_DEBUG:     syslog_level = LOG_DEBUG;   break;
+            default:                 syslog_level = LOG_NOTICE;  break;
         }
 
         if (!log_inited) { openlog(ident, LOG_CONS, LOG_DAEMON); log_inited++; }
@@ -205,11 +324,408 @@ mDNSexport void mDNSPlatformWriteLogMsg(const char *ident, const char *buffer, m
         else
 #endif
         {
-#if APPLE_OSX_mDNSResponder
-            mDNSPlatformLogToFile(syslog_level, buffer);
-#else
             syslog(syslog_level, "%s", buffer);
+        }
+    }
+}
+#endif // !MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+
+mDNSexport mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort)
+{
+    int sa_family = (addrType == mDNSAddrType_IPv4) ? AF_INET : AF_INET6;
+    int err;
+    int sock;
+    mDNSu32 lowWater = 15384;
+
+    sock = socket(sa_family, SOCK_STREAM, IPPROTO_TCP);
+    if (sock < 3)
+    {
+        if (errno != EAFNOSUPPORT)
+        {
+            LogMsg("mDNSPosixTCPSocketSetup: socket error %d errno %d (%s)", sock, errno, strerror(errno));
+        }
+        return mDNStrue;
+    }
+    *fd = sock;
+
+    union
+    {
+        struct sockaddr sa;
+        struct sockaddr_in sin;
+        struct sockaddr_in6 sin6;
+    } addr;
+    // If port is not NULL, bind to it.
+    if (port != NULL)
+    {
+        socklen_t len = (sa_family == AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6);
+        mDNSPlatformMemZero(&addr, sizeof addr);
+
+        addr.sa.sa_family = sa_family;
+#ifndef NOT_HAVE_SA_LEN
+       addr.sa.sa_len = len;
 #endif
+        if (sa_family == AF_INET6)
+        {
+            addr.sin6.sin6_port = port->NotAnInteger;
+        }
+        else
+        {
+            addr.sin.sin_port = port->NotAnInteger;
+        }
+        err = bind(sock, &addr.sa, len);
+        if (err < 0)
+        {
+            LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
+            return mDNSfalse;
+        }
+    }
+
+    socklen_t addrlen = sizeof addr;
+    err = getsockname(sock, (struct sockaddr *)&addr, &addrlen);
+    if (err < 0)
+    {
+        LogMsg("mDNSPosixTCPSocketSetup getsockname: %s", strerror(errno));
+        return mDNSfalse;
+    }
+    if (sa_family == AF_INET6)
+    {
+        outTcpPort->NotAnInteger = addr.sin6.sin6_port;
+
+    } else
+    {
+        outTcpPort->NotAnInteger = addr.sin.sin_port;
+    }
+    if (port)
+        port->NotAnInteger = outTcpPort->NotAnInteger;
+
+    err = setsockopt(sock, IPPROTO_TCP, TCP_NOTSENT_LOWAT, &lowWater, sizeof lowWater);
+    if (err < 0)
+    {
+        LogMsg("mDNSPosixTCPSocketSetup: TCP_NOTSENT_LOWAT failed: %s", strerror(errno));
+        return mDNSfalse;
+    }
+
+    return mDNStrue;
+}
+
+mDNSexport TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags,
+                                             TCPAcceptedCallback callback, void *context)
+{
+    union
+    {
+        struct sockaddr_in6 sin6;
+        struct sockaddr_in sin;
+        struct sockaddr sa;
+    } address;
+
+    socklen_t slen = sizeof address;
+    int remoteSock;
+    mDNSAddr addr;
+    mDNSIPPort port;
+    TCPSocket *sock = mDNSNULL;
+    int failed;
+    char *nbp;
+    int i;
+    mDNSu32 lowWater = 16384;
+    // When we remember our connection, we remember a name that we can print for logging.   But
+    // since we are the listener in this case, we don't /have/ a name for it.   This buffer
+    // is used to print the IP address into a human readable string which will serve that purpose
+    // for this case.
+    char namebuf[INET6_ADDRSTRLEN + 1 + 5 + 1];
+
+    remoteSock = accept(fd, &address.sa, &slen);
+    if (remoteSock < 0)
+    {
+        LogMsg("mDNSPosixDoTCPListenCallback: accept returned %d", remoteSock);
+        goto out;
+    }
+
+    failed = fcntl(remoteSock, F_SETFL, O_NONBLOCK);
+    if (failed < 0)
+    {
+        close(remoteSock);
+        LogMsg("mDNSPosixDoTCPListenCallback: fcntl returned %d", errno);
+        goto out;
+    }
+
+    failed = setsockopt(remoteSock, IPPROTO_TCP, TCP_NOTSENT_LOWAT,
+                        &lowWater, sizeof lowWater);
+    if (failed < 0)
+    {
+        close(remoteSock);
+        LogMsg("mDNSPosixDoTCPListenCallback: TCP_NOTSENT_LOWAT returned %d", errno);
+        goto out;
+    }
+    
+    if (address.sa.sa_family == AF_INET6)
+    {
+        // If we are listening on an IPv4/IPv6 socket, the incoming address might be an IPv4-in-IPv6 address
+        for (i = 0; i < 10; i++)
+        {
+            if (address.sin6.sin6_addr.s6_addr[i] != 0)
+            {
+                addr.type = mDNSAddrType_IPv6;
+                goto nope;
+            }
         }
+
+        // a legit IPv4 address would be ::ffff:a.b.c.d; if there's no ::ffff bit, then it's an IPv6
+        // address with a really weird prefix.
+        if (address.sin6.sin6_addr.s6_addr[10] != 0xFF || address.sin6.sin6_addr.s6_addr[11] != 0xFF)
+        {
+            addr.type = mDNSAddrType_IPv6;
+        } else if (addressType != mDNSAddrType_None)
+        {
+            if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+            {
+                strcpy(namebuf, ":unknown:");
+            }
+            LogMsg("mDNSPosixDoTCPListenCallback received an IPv4 connection from %s on an IPv6-only socket.",
+                   namebuf);
+            close(remoteSock);
+            goto out;
+        }
+        else
+        {
+            addr.type = mDNSAddrType_IPv4;
+        }
+    nope:
+        if (addr.type == mDNSAddrType_IPv6)
+        {
+            if (inet_ntop(address.sin6.sin6_family, &address.sin6.sin6_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+            {
+                strcpy(namebuf, ":unknown:");
+            }
+            memcpy(&addr.ip.v6, &address.sin6.sin6_addr, sizeof addr.ip.v6);
+        }
+        else
+        {
+            if (inet_ntop(AF_INET, &address.sin6.sin6_addr.s6_addr[12], namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+            {
+                strcpy(namebuf, ":unknown:");
+            }
+            memcpy(&addr.ip.v4, &address.sin6.sin6_addr.s6_addr[12], sizeof addr.ip.v4);
+        }
+        port.NotAnInteger = address.sin6.sin6_port;
+    }
+    else if (address.sa.sa_family == AF_INET)
+    {
+        addr.type = mDNSAddrType_IPv4;
+        memcpy(&addr.ip.v4, &address.sin.sin_addr, sizeof addr.ip.v4);
+        port.NotAnInteger = address.sin.sin_port;
+        if (inet_ntop(AF_INET, &address.sin.sin_addr, namebuf, INET6_ADDRSTRLEN + 1) == NULL)
+        {
+            strcpy(namebuf, ":unknown:");
+        }
+    } else {
+        LogMsg("mDNSPosixDoTCPListenCallback: connection from unknown address family %d", address.sa.sa_family);
+        close(remoteSock);
+        goto out;
+    }
+    nbp = namebuf + strlen(namebuf);
+    *nbp++ = '%';
+    snprintf(nbp, 6, "%u", ntohs(port.NotAnInteger));
+             
+    sock = mDNSPlatformTCPAccept(socketFlags, remoteSock);
+    if (sock == NULL)
+    {
+        LogMsg("mDNSPosixDoTCPListenCallback: mDNSPlatformTCPAccept returned NULL; dropping connection from %s",
+               namebuf);
+        close(remoteSock);
+        goto out;
+    }
+    callback(sock, &addr, &port, namebuf, context);
+out:
+    return sock;
+}
+
+mDNSexport mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+                                       mDNSBool reuseAddr, int queueLength)
+
+{
+    union
+    {
+        struct sockaddr_in6 sin6;
+        struct sockaddr_in sin;
+        struct sockaddr sa;
+    } address;
+
+    int failed;
+    int sock;
+    int one = 1;
+    socklen_t sock_len;
+
+    // We require an addrtype parameter because addr is allowed to be null, but they have to agree.
+    if (addr != mDNSNULL && addr->type != addrtype)
+    {
+        LogMsg("mDNSPlatformTCPListen: address type conflict: %d:%d", addr->type, addrtype);
+        return mDNSfalse;
+    }
+    if (port == mDNSNULL)
+    {
+        LogMsg("mDNSPlatformTCPListen: port must not be NULL");
+        return mDNSfalse;
+    }
+
+    mDNSPlatformMemZero(&address, sizeof address);
+    if (addrtype == mDNSAddrType_None || addrtype == mDNSAddrType_IPv6)
+    {
+        // Set up DNS listener socket
+        if (addr != mDNSNULL)
+        {
+            memcpy(&address.sin6.sin6_addr.s6_addr, &addr->ip, sizeof address.sin6.sin6_addr.s6_addr);
+        }
+        address.sin6.sin6_port = port->NotAnInteger;
+
+        sock_len = sizeof address.sin6;
+        address.sin6.sin6_family = AF_INET6;
+    }
+    else if (addrtype == mDNSAddrType_IPv4)
+    {
+        if (addr != mDNSNULL)
+        {
+            memcpy(&address.sin.sin_addr.s_addr, &addr->ip, sizeof address.sin.sin_addr.s_addr);
+        }
+        address.sin.sin_port = port->NotAnInteger;
+        sock_len = sizeof address.sin;
+        address.sin.sin_family = AF_INET;
+    }
+    else
+    {
+        LogMsg("mDNSPlatformTCPListen: invalid address type: %d", addrtype);
+        return mDNSfalse;
+    }
+#ifndef NOT_HAVE_SA_LEN
+    address.sa.sa_len = sock_len;
+#endif
+    sock = socket(address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
+
+    if (sock < 0)
+    {
+        LogMsg("mDNSPlatformTCPListen: socket call failed: %s", strerror(errno));
+        return mDNSfalse;
+    }
+    *fd = sock;
+
+    // The reuseAddr flag is used to indicate that we want to listen on this port even if
+    // there are still lingering sockets.   We will still fail if there is another listener.
+    // Note that this requires SO_REUSEADDR, not SO_REUSEPORT, which does not have special
+    // handling for lingering sockets.
+    if (reuseAddr)
+    {
+        failed = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
+        if (failed < 0)
+        {
+            LogMsg("mDNSPlatformTCPListen: SO_REUSEADDR failed %s", strerror(errno));
+            return mDNSfalse;
+        }
+    }
+
+    // Bind to the port and (if provided) address
+    failed = bind(sock, &address.sa, sock_len);
+    if (failed < 0)
+    {
+        LogMsg("mDNSPlatformTCPListen: bind failed %s", strerror(errno));
+        return mDNSfalse;
+    }
+
+    // If there was no specified listen port, we need to know what port we got.
+    if (port->NotAnInteger == 0)
+    {
+        mDNSPlatformMemZero(&address, sizeof address);
+        failed = getsockname(sock, &address.sa, &sock_len);
+        if (failed < 0)
+        {
+            LogMsg("mDNSRelay: getsockname failed: %s", strerror(errno));
+            return mDNSfalse;
+        }
+        if (address.sa.sa_family == AF_INET)
+        {
+            port->NotAnInteger = address.sin.sin_port;
+        }
+        else
+        {
+            port->NotAnInteger = address.sin6.sin6_port;
+        }
+    }
+
+    failed = listen(sock, queueLength);
+    if (failed < 0)
+    {
+        LogMsg("mDNSPlatformTCPListen: listen failed: %s", strerror(errno));
+        return mDNSfalse;
+    }
+    return mDNStrue;
+}
+
+mDNSexport long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed)
+{
+    static int CLOSEDcount = 0;
+    static int EAGAINcount = 0;
+    ssize_t nread = recv(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 % 20) == 0)
+        {
+            LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got CLOSED %d times", fd, CLOSEDcount); 
+            assert(CLOSEDcount < 1000);
+            // Recovery Mechanism to bail mDNSResponder out of trouble: Instead of logging the same error
+            // msg multiple times, crash mDNSResponder using assert() and restart fresh. See advantages
+            // below:
+            // 1.Better User Experience 
+            // 2.CrashLogs frequency can be monitored 
+            // 3.StackTrace can be used for more info
+        }
+    }
+    // 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: mDNSPosixReadFromSocket - recv: %d (%s)", errno, strerror(errno));
+        nread = -1;
+    }
+    else
+    { // errno is EAGAIN (EWOULDBLOCK) -- no data available
+        nread = 0;
+        if ((++EAGAINcount % 1000) == 0)
+        {
+            LogMsg("ERROR: mDNSPosixReadFromSocket - recv %d got EAGAIN %d times", fd, EAGAINcount);
+            sleep(1);
+        }
+    }
+    return nread;
+}
+
+mDNSexport long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len)
+{
+    ssize_t result;
+    long nsent;
+
+    result = write(fd, msg, len);
+    if (result < 0)
+    {
+        if (errno == EAGAIN)
+        {
+            nsent = 0;
+        }
+        else
+        {
+            LogMsg("ERROR: mDNSPosixWriteTCP - send %s", strerror(errno)); nsent = -1;
+        }
+    }
+    else
+    {
+        nsent = (long)result;
     }
+    return nsent;
 }
index 2a068711e0d97ddf93f4716eafe71d0399f64691..fae414ae4c63daf977861a0cb50482edda63c82e 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- Mode: C; tab-width: 4 -*-
+/* -*- Mode: C; tab-width: 4; c-file-style: "bsd"; c-basic-offset: 4; fill-column: 108; indent-tabs-mode: nil; -*-
  *
  * Copyright (c) 2004 Apple Computer, Inc. All rights reserved.
  *
  * limitations under the License.
  */
 
-extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename, domainname *const hostname, domainname *const domain, mDNSBool *DomainDiscoveryDisabled);
+#ifndef __PLATFORM_COMMON_H
+#define __PLATFORM_COMMON_H
+extern void ReadDDNSSettingsFromConfFile(mDNS *const m, const char *const filename,
+                                                                                domainname *const hostname, domainname *const domain,
+                                                                                mDNSBool *DomainDiscoveryDisabled);
+extern mDNSBool mDNSPosixTCPSocketSetup(int *fd, mDNSAddr_Type addrType, mDNSIPPort *port, mDNSIPPort *outTcpPort);
+extern TCPSocket *mDNSPosixDoTCPListenCallback(int fd, mDNSAddr_Type addressType, TCPSocketFlags socketFlags,
+                     TCPAcceptedCallback callback, void *context);
+extern mDNSBool mDNSPosixTCPListen(int *fd, mDNSAddr_Type addrtype, mDNSIPPort *port, mDNSAddr *addr,
+                   mDNSBool reuseAddr, int queueLength);
+extern long mDNSPosixReadTCP(int fd, void *buf, unsigned long buflen, mDNSBool *closed);
+extern long mDNSPosixWriteTCP(int fd, const char *msg, unsigned long len);
+#endif
index 675eec51f0f0abbad3980b42201635ff563f6b6f..91323065d3981985b1a1c770ee76b824e2082e47 100644 (file)
@@ -66,7 +66,7 @@
  */
 
 #ifndef _DNS_SD_H
-#define _DNS_SD_H 8807002
+#define _DNS_SD_H 10960002
 
 #ifdef  __cplusplus
 extern "C" {
@@ -197,7 +197,7 @@ enum
 
     kDNSServiceFlagsAutoTrigger        = 0x1,
     /* Valid for browses using kDNSServiceInterfaceIndexAny.
-     * Will auto trigger the browse over AWDL as well once the service is discoveryed
+     * Will auto trigger the browse over AWDL as well once the service is discovered
      * over BLE.
      * This flag is an input value to DNSServiceBrowse(), which is why we can
      * use the same value as kDNSServiceFlagsMoreComing, which is an output flag
@@ -256,7 +256,6 @@ enum
     /* 
      * Client guarantees that record names are unique, so we can skip sending out initial
      * probe messages.  Standard name conflict resolution is still done if a conflict is discovered.
-     * Currently only valid for a DNSServiceRegister call.
      */
 
     kDNSServiceFlagsReturnIntermediates = 0x1000,
@@ -273,38 +272,28 @@ enum
      * (In earlier builds this flag was briefly calledkDNSServiceFlagsReturnCNAME)
      */
 
-    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.
+     * call DNSServiceCreateConnection(&SharedRef) 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
+     * the SharedRef, 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);
+     * DNSServiceRef SharedRef;
+     * error = DNSServiceCreateConnection(&SharedRef);
      * if (error) ...
-     * DNSServiceRef BrowseRef = MainRef;  // Important: COPY the primary DNSServiceRef first...
+     * DNSServiceRef BrowseRef = SharedRef;  // 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
-     * Also see Point 4.(Don't Double-Deallocate if the MainRef has been Deallocated) in Notes below:
+     * DNSServiceRefDeallocate(SharedRef); // Terminate the shared connection
      *
      * Notes:
      *
@@ -342,15 +331,18 @@ enum
      * DNSServiceRef's created by other calls like DNSServiceBrowse() or DNSServiceResolve()
      * cannot be shared by copying them and using kDNSServiceFlagsShareConnection.
      *
-     * 4. Don't Double-Deallocate if the MainRef has been Deallocated
-     * 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.
+     * 4. Don't Double-Deallocate
+     * Calling DNSServiceRefDeallocate(OpRef) for a particular operation's DNSServiceRef terminates
+     * just that operation. Calling DNSServiceRefDeallocate(SharedRef) for the main shared DNSServiceRef
+     * (the parent DNSServiceRef, originally created by DNSServiceCreateConnection(&SharedRef))
+     * 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.
+     * You can deallocate individual operations first and then deallocate the parent DNSServiceRef last,
+     * but if you deallocate the parent DNSServiceRef first, then all of the subordinate DNSServiceRef's
+     * are implicitly deallocated, and explicitly deallocating them a second time will lead to crashes.
      *
      * 5. Thread Safety
      * The dns_sd.h API does not presuppose any particular threading model, and consequently
@@ -358,15 +350,15 @@ enum
      * If the client concurrently, from multiple threads (or contexts), calls API routines using 
      * the same DNSServiceRef, it is the client's responsibility to provide mutual exclusion for 
      * that DNSServiceRef.
-
+     *
      * For example, use of DNSServiceRefDeallocate requires caution. A common mistake is as follows:
      * Thread B calls DNSServiceRefDeallocate to deallocate sdRef while Thread A is processing events
      * using sdRef. Doing this will lead to intermittent crashes on thread A if the sdRef is used after
      * it was deallocated.
-
+     *
      * A telltale sign of this crash type is to see DNSServiceProcessResult on the stack preceding the
      * actual crash location.
-
+     *
      * To state this more explicitly, mDNSResponder does not queue DNSServiceRefDeallocate so
      * that it occurs discretely before or after an event is handled.
      */
@@ -519,26 +511,38 @@ enum
      * is only set in the callbacks and kDNSServiceFlagsThresholdOne is only set on
      * input to a DNSServiceBrowse call.
      */
-     kDNSServiceFlagsPrivateOne          = 0x8000000,
+     kDNSServiceFlagsPrivateOne          = 0x2000,
     /*
      * This flag is private and should not be used.
      */
 
-     kDNSServiceFlagsPrivateTwo           = 0x10000000,
+     kDNSServiceFlagsPrivateTwo           = 0x8000000,
     /*
      * This flag is private and should not be used.
      */
 
-     kDNSServiceFlagsPrivateThree         = 0x20000000,
+     kDNSServiceFlagsPrivateThree         = 0x10000000,
     /*
      * This flag is private and should not be used.
      */
 
-     kDNSServiceFlagsPrivateFour          = 0x40000000,
+     kDNSServiceFlagsPrivateFour          = 0x20000000,
     /*
      * This flag is private and should not be used.
      */
 
+    kDNSServiceFlagsPrivateFive          = 0x40000000,
+    /*
+     * This flag is private and should not be used.
+     */
+
+
+    kDNSServiceFlagAnsweredFromCache     = 0x40000000,
+    /*
+     * When kDNSServiceFlagAnsweredFromCache is passed back in the flags parameter of DNSServiceQueryRecordReply or DNSServiceGetAddrInfoReply,
+     * an answer will have this flag set if it was answered from the cache.
+     */
+
     kDNSServiceFlagsAllowExpiredAnswers   = 0x80000000,
     /*
      * When kDNSServiceFlagsAllowExpiredAnswers is passed to DNSServiceQueryRecord or DNSServiceGetAddrInfo,
@@ -696,7 +700,8 @@ enum
     kDNSServiceErr_NATPortMappingDisabled    = -65565,  /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */
     kDNSServiceErr_NoRouter                  = -65566,  /* No router currently configured (probably no network connectivity) */
     kDNSServiceErr_PollingMode               = -65567,
-    kDNSServiceErr_Timeout                   = -65568
+    kDNSServiceErr_Timeout                   = -65568,
+    kDNSServiceErr_DefunctConnection         = -65569   /* Connection to daemon returned a SO_ISDEFUNCT error result */
 
                                                /* mDNS Error codes are in the range
                                                 * FFFE FF00 (-65792) to FFFE FFFF (-65537) */
@@ -722,8 +727,10 @@ enum
  * conventional DNS escaping rules, as used by the traditional DNS res_query() API, as described below:
  *
  * Generally all UTF-8 characters (which includes all US ASCII characters) represent themselves,
- * with two exceptions, the dot ('.') character, which is the label separator,
- * and the backslash ('\') character, which is the escape character.
+ * with three exceptions:
+ * the dot ('.') character, which is the DNS label separator,
+ * the backslash ('\') character, which is the DNS escape character, and
+ * the ASCII NUL (0) byte value, which is the C-string terminator character.
  * The escape character ('\') is interpreted as described below:
  * 
  *   '\ddd', where ddd is a three-digit decimal value from 000 to 255,
@@ -732,10 +739,10 @@ enum
  *        For example, the ASCII code for 'w' is 119, and therefore '\119' is equivalent to 'w'.
  *        Thus the command "ping '\119\119\119.apple.com'" is the equivalent to the command "ping 'www.apple.com'".
  *        Nonprinting ASCII characters in the range 0-31 are often represented this way.
- *        In particular, the ASCII NUL character (0) cannot appear in a C string because C uses it as the
- *        string terminator character, so ASCII NUL in a domain name has to be represented in a C string as '\000'.
+ *        In particular, the ASCII NUL character (0) cannot appear in a C-string because C uses it as the
+ *        string terminator character, so ASCII NUL in a domain name has to be represented in a C-string as '\000'.
  *        Other characters like space (ASCII code 32) are sometimes represented as '\032'
- *        in contexts where having an actual space character in a C string would be inconvenient.
+ *        in contexts where having an actual space character in a C-string would be inconvenient.
  *        
  *   Otherwise, for all cases where a '\' is followed by anything other than a three-digit decimal value
  *        from 000 to 255, the character sequence '\x' represents a single literal occurrence of character 'x'.
@@ -751,6 +758,21 @@ enum
  *        followed by neither a three-digit decimal value from 000 to 255 nor a single character.
  *        If a lone escape character ('\') does appear as the last character of a string, it is silently ignored.
  *
+ * The worse-case length for an escaped domain name is calculated as follows:
+ * The longest legal domain name is 256 bytes in wire format (see RFC 6762, Appendix C, DNS Name Length).
+ * For our calculation of the longest *escaped* domain name, we use
+ * the longest legal domain name, with the most characters escaped.
+ *
+ * We consider a domain name of the form: "label63.label63.label63.label62."
+ * where "label63" is a 63-byte label and "label62" is a 62-byte label.
+ * Counting four label-length bytes, 251 bytes of label data, and the terminating zero,
+ * this makes a total of 256 bytes in wire format, the longest legal domain name.
+ *
+ * If each one of the 251 bytes of label data is represented using '\ddd',
+ * then it takes 251 * 4 = 1004 bytes to represent these in a C-string.
+ * Adding four '.' characters as shown above, plus the C-string terminating
+ * zero at the end, results in a maximum storage requirement of 1009 bytes.
+ *
  * The exceptions, that do not use escaping, are the routines where the full
  * DNS name of a resource is broken, for convenience, into servicename/regtype/domain.
  * In these routines, the "servicename" is NOT escaped. It does not need to be, since
@@ -997,6 +1019,9 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef);
  * is invalidated when this function is called - the DNSRecordRef may not be used in subsequent
  * functions.
  *
+ * If the reference was passed to DNSServiceSetDispatchQueue(), DNSServiceRefDeallocate() must 
+ * be called on the same queue originally passed as an argument to DNSServiceSetDispatchQueue().
+ *
  * Note: This call is to be used only with the DNSServiceRef defined by this API.
  *
  * sdRef:           A DNSServiceRef initialized by any of the DNSService calls.
@@ -1061,12 +1086,17 @@ typedef void (DNSSD_API *DNSServiceDomainEnumReply)
 
 /* DNSServiceEnumerateDomains() Parameters:
  *
- * 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().
+ * sdRef:           A pointer to an uninitialized DNSServiceRef
+ *                  (or, if the kDNSServiceFlagsShareConnection flag is used,
+ *                  a copy of the shared connection reference that is to be used).
+ *                  If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ *                  returns kDNSServiceErr_NoError, and the enumeration operation
+ *                  will remain active indefinitely until the client terminates it
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ *                  (or by closing the underlying shared connection, if used).
  *
  * flags:           Possible values are:
+ *                  kDNSServiceFlagsShareConnection to use a shared connection.
  *                  kDNSServiceFlagsBrowseDomains to enumerate domains recommended for browsing.
  *                  kDNSServiceFlagsRegistrationDomains to enumerate domains recommended
  *                  for registration.
@@ -1154,13 +1184,20 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
 
 /* DNSServiceRegister() Parameters:
  *
- * 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().
+ * sdRef:           A pointer to an uninitialized DNSServiceRef
+ *                  (or, if the kDNSServiceFlagsShareConnection flag is used,
+ *                  a copy of the shared connection reference that is to be used).
+ *                  If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ *                  returns kDNSServiceErr_NoError, and the service registration
+ *                  will remain active indefinitely until the client terminates it
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ *                  (or by closing the underlying shared connection, if used).
  *
- * flags:           Indicates the renaming behavior on name conflict (most applications
- *                  will pass 0). See flag definitions above for details.
+ * flags:           Possible values are:
+ *                  kDNSServiceFlagsShareConnection to use a shared connection.
+ *                  Other flags indicate the renaming behavior on name conflict
+ *                  (not required for most applications).
+ *                  See flag definitions above for details.
  *
  * 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()
@@ -1210,31 +1247,6 @@ typedef void (DNSSD_API *DNSServiceRegisterReply)
  *
  *                  % dns-sd -R Test '_test._tcp,s\.one,s\,two,s\\three,s\000four' local 123
  *
- *                  When a service is registered, all the clients browsing for the registered
- *                  type ("regtype") will discover it. If the discovery should be
- *                  restricted to a smaller set of well known peers, the service can be
- *                  registered with additional data (group identifier) that is known
- *                  only to a smaller set of peers. The group identifier should follow primary
- *                  service type using a colon (":") as a delimeter. If subtypes are also present,
- *                  it should be given before the subtype as shown below.
- *
- *                  % dns-sd -R _test1 _http._tcp:mygroup1 local 1001 
- *                  % dns-sd -R _test2 _http._tcp:mygroup2 local 1001 
- *                  % dns-sd -R _test3 _http._tcp:mygroup3,HasFeatureA local 1001 
- *
- *                  Now:
- *                  % dns-sd -B _http._tcp:"mygroup1"                # will discover only test1
- *                  % dns-sd -B _http._tcp:"mygroup2"                # will discover only test2
- *                  % dns-sd -B _http._tcp:"mygroup3",HasFeatureA    # will discover only test3
- *                  
- *                  By specifying the group information, only the members of that group are
- *                  discovered.
- *
- *                  The group identifier itself is not sent in clear. Only a hash of the group
- *                  identifier is sent and the clients discover them anonymously. The group identifier
- *                  may be up to 256 bytes long and may contain any eight bit values except comma which
- *                  should be escaped.
- *
  * 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).
@@ -1478,12 +1490,17 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
 
 /* DNSServiceBrowse() Parameters:
  *
- * 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().
+ * sdRef:           A pointer to an uninitialized DNSServiceRef
+ *                  (or, if the kDNSServiceFlagsShareConnection flag is used,
+ *                  a copy of the shared connection reference that is to be used).
+ *                  If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ *                  returns kDNSServiceErr_NoError, and the browse operation
+ *                  will remain active indefinitely until the client terminates it
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ *                  (or by closing the underlying shared connection, if used).
  *
- * flags:           Currently ignored, reserved for future use.
+ * flags:           Possible values are:
+ *                  kDNSServiceFlagsShareConnection to use a shared connection.
  *
  * 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()
@@ -1495,10 +1512,7 @@ typedef void (DNSSD_API *DNSServiceBrowseReply)
  *                  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. Additionally, a group identifier may
- *                  also be specified before the subtype e.g., _primarytype._tcp:GroupID, which
- *                  will discover only the members that register the service with GroupID. See
- *                  DNSServiceRegister for more details.
+ *                  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
@@ -1607,12 +1621,18 @@ typedef void (DNSSD_API *DNSServiceResolveReply)
 
 /* DNSServiceResolve() Parameters
  *
- * 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().
+ * sdRef:           A pointer to an uninitialized DNSServiceRef
+ *                  (or, if the kDNSServiceFlagsShareConnection flag is used,
+ *                  a copy of the shared connection reference that is to be used).
+ *                  If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ *                  returns kDNSServiceErr_NoError, and the resolve operation
+ *                  will remain active indefinitely until the client terminates it
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ *                  (or by closing the underlying shared connection, if used).
  *
- * flags:           Specifying kDNSServiceFlagsForceMulticast will cause query to be
+ * flags:           Possible values are:
+ *                  kDNSServiceFlagsShareConnection to use a shared connection.
+ *                  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.")
  *
@@ -1729,12 +1749,18 @@ typedef void (DNSSD_API *DNSServiceQueryRecordReply)
 
 /* 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().
+ * sdRef:           A pointer to an uninitialized DNSServiceRef
+ *                  (or, if the kDNSServiceFlagsShareConnection flag is used,
+ *                  a copy of the shared connection reference that is to be used).
+ *                  If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ *                  returns kDNSServiceErr_NoError, and the query operation
+ *                  will remain active indefinitely until the client terminates it
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ *                  (or by closing the underlying shared connection, if used).
  *
- * flags:           kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
+ * flags:           Possible values are:
+ *                  kDNSServiceFlagsShareConnection to use a shared connection.
+ *                  kDNSServiceFlagsForceMulticast or kDNSServiceFlagsLongLivedQuery.
  *                  Pass kDNSServiceFlagsLongLivedQuery to create a "long-lived" unicast
  *                  query to a unicast DNS server that implements the protocol. This flag
  *                  has no effect on link-local multicast queries.
@@ -1835,12 +1861,18 @@ typedef void (DNSSD_API *DNSServiceGetAddrInfoReply)
 
 /* 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().
+ * sdRef:           A pointer to an uninitialized DNSServiceRef
+ *                  (or, if the kDNSServiceFlagsShareConnection flag is used,
+ *                  a copy of the shared connection reference that is to be used).
+ *                  If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ *                  returns kDNSServiceErr_NoError, and the address query operation
+ *                  will remain active indefinitely until the client terminates it
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ *                  (or by closing the underlying shared connection, if used).
  *
- * flags:           kDNSServiceFlagsForceMulticast
+ * flags:           Possible values are:
+ *                  kDNSServiceFlagsShareConnection to use a shared connection.
+ *                  kDNSServiceFlagsForceMulticast
  *
  * 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.
@@ -1896,13 +1928,14 @@ DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo
  *
  * Parameters:
  *
- * sdRef:           A pointer to an uninitialized DNSServiceRef. Deallocating
- *                  the reference (via DNSServiceRefDeallocate()) severs the
- *                  connection and deregisters all records registered on this connection.
+ * sdRef:           A pointer to an uninitialized DNSServiceRef.
+ *                  Deallocating the reference (via DNSServiceRefDeallocate())
+ *                  severs the connection and cancels all operations and
+ *                  deregisters all records registered on this connection.
  *
  * return value:    Returns kDNSServiceErr_NoError on success, otherwise returns
- *                  an error code indicating the specific failure that occurred (in which
- *                  case the DNSServiceRef is not initialized).
+ *                  an error code indicating the specific failure that occurred
+ *                  (in which case the DNSServiceRef is not initialized).
  */
 
 DNSSD_EXPORT
@@ -1954,8 +1987,7 @@ typedef void (DNSSD_API *DNSServiceRegisterRecordReply)
  *                  and deallocate each of their corresponding DNSServiceRecordRefs, call
  *                  DNSServiceRefDeallocate()).
  *
- * flags:           Possible values are kDNSServiceFlagsShared or kDNSServiceFlagsUnique
- *                  (see flag type definitions for details).
+ * flags:           One of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique must be set.
  *
  * 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()
@@ -2175,15 +2207,20 @@ typedef void (DNSSD_API *DNSServiceNATPortMappingReply)
 
 /* DNSServiceNATPortMappingCreate() Parameters:
  *
- * 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().
+ * sdRef:           A pointer to an uninitialized DNSServiceRef
+ *                  (or, if the kDNSServiceFlagsShareConnection flag is used,
+ *                  a copy of the shared connection reference that is to be used).
+ *                  If the call succeeds then it initializes (or updates) the DNSServiceRef,
+ *                  returns kDNSServiceErr_NoError, and the NAT port mapping
+ *                  will remain active indefinitely until the client terminates it
+ *                  by passing this DNSServiceRef to DNSServiceRefDeallocate()
+ *                  (or by closing the underlying shared connection, if used).
  *
- * flags:           Currently ignored, reserved for future use.
+ * flags:           Possible values are:
+ *                  kDNSServiceFlagsShareConnection to use a shared connection.
  *
- * 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:  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.
  *
  * protocol:        To request a port mapping, pass in kDNSServiceProtocol_UDP, or kDNSServiceProtocol_TCP,
  *                  or (kDNSServiceProtocol_UDP | kDNSServiceProtocol_TCP) to map both.
@@ -2315,7 +2352,11 @@ typedef union _TXTRecordRef_t { char PrivateData[16]; char *ForceNaturalAlignmen
  *
  * If the buffer parameter is NULL, or the specified storage size is not
  * large enough to hold a key subsequently added using TXTRecordSetValue(),
- * then additional memory will be added as needed using malloc().
+ * then additional memory will be added as needed using malloc(). Note that
+ * an existing TXT record buffer should not be passed to TXTRecordCreate
+ * to create a copy of another TXT Record. The correct way to copy TXTRecordRef
+ * is creating an empty TXTRecordRef with TXTRecordCreate() first, and using
+ * TXTRecordSetValue to set the same value.  
  *
  * On some platforms, when memory is low, malloc() may fail. In this
  * case, TXTRecordSetValue() will return kDNSServiceErr_NoMemory, and this
@@ -2613,7 +2654,7 @@ uint16_t DNSSD_API TXTRecordGetCount
  * keyBufLen:       The size of the string buffer being supplied.
  *
  * key:             A string buffer used to store the key name.
- *                  On return, the buffer contains a null-terminated C string
+ *                  On return, the buffer contains a null-terminated C-string
  *                  giving the key name. DNS-SD TXT keys are usually
  *                  9 characters or fewer. To hold the maximum possible
  *                  key name, the buffer should be 256 bytes long.
@@ -2670,6 +2711,8 @@ DNSServiceErrorType DNSSD_API TXTRecordGetItemAtIndex
  * DNSServiceSetDispatchQueue a second time to schedule the DNSServiceRef onto a different serial dispatch
  * queue. Once scheduled onto a dispatch queue a DNSServiceRef will deliver events to that queue until
  * the application no longer requires that operation and terminates it using DNSServiceRefDeallocate.
+ * Note that the call to DNSServiceRefDeallocate() must be done on the same queue originally passed 
+ * as an argument to DNSServiceSetDispatchQueue().
  *
  * service:         DNSServiceRef that was allocated and returned to the application, when the
  *                  application calls one of the DNSService API.
index 2d4297336184c9b50db8fbf6af83495f81048fec..0c5d2c9465bbed2a9ad26c7599d1b429a1b9b3c0 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  * 
- * Copyright (c) 2015-2018 Apple Inc. All rights reserved.
+ * Copyright (c) 2015-2019 Apple Inc. All rights reserved.
  */
 
 #ifndef _DNS_SD_PRIVATE_H
@@ -8,9 +8,15 @@
 
 #include <dns_sd.h>
 
-// Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour) from dns_sd.h
+// Private flags (kDNSServiceFlagsPrivateOne, kDNSServiceFlagsPrivateTwo, kDNSServiceFlagsPrivateThree, kDNSServiceFlagsPrivateFour, kDNSServiceFlagsPrivateFive) from dns_sd.h
 enum
 {
+    kDNSServiceFlagsDenyConstrained        = 0x2000,
+    /*
+     * This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
+     * DNS resolutions on interfaces defined as constrained for that request.
+     */
+
     kDNSServiceFlagsDenyCellular           = 0x8000000,
     /*
      * This flag is meaningful only for Unicast DNS queries. When set, the daemon will restrict
@@ -36,8 +42,7 @@ enum
      */
 };
 
-
-#if !DNSSD_NO_CREATE_DELEGATE_CONNECTION
+#if !defined(DNSSD_NO_CREATE_DELEGATE_CONNECTION) || !DNSSD_NO_CREATE_DELEGATE_CONNECTION
 /* DNSServiceCreateDelegateConnection()
  *
  * Parameters:
index cbdab57c47c2ac625ea3dd9fc40cafe564797a8d..11a24e40b9bc26dce6c62b57537a03064bdb6a7a 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2015 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2002-2019 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.
@@ -302,7 +301,7 @@ mDNSlocal TCPSocket *ConnectToServer(DaemonInfo *d)
         mDNSIPPort port = zeroIPPort;
         int fd;
 
-        TCPSocket *sock = mDNSPlatformTCPSocket(0, &port, mDNSfalse );
+        TCPSocket *sock = mDNSPlatformTCPSocket(0, mDNSAddrType_IPv4, &port, NULL, mDNSfalse );
         if ( !sock ) { LogErr("ConnectToServer", "socket");  return NULL; }
         fd = mDNSPlatformTCPGetFD( sock );
         if (!connect( fd, (struct sockaddr *)&d->ns_addr, sizeof(d->ns_addr))) return sock;
@@ -2316,7 +2315,8 @@ mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
 {
     DNSQuestion q;
     LargeCacheRecord opt;
-    int i, err = -1;
+    unsigned int i;
+    int err = -1;
     char addr[32];
     const mDNSu8 *qptr = pkt->msg.data;
     const mDNSu8 *end = (mDNSu8 *)&pkt->msg + pkt->len;
@@ -2343,7 +2343,7 @@ mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
     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 (!aptr) { Log("Malformatted LLQ from %s: could not get Additional record %u", addr, i); goto end; }
         if (opt.r.resrec.RecordType != kDNSRecordTypePacketNegative && opt.r.resrec.rrtype == kDNSType_OPT) break;
     }
 
@@ -2355,7 +2355,7 @@ mDNSlocal int RecvLLQ( DaemonInfo *d, PktMsg *pkt, TCPSocket *sock )
     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; }
+        if (!qptr) { Log("Malformatted LLQ from %s: cannot read question %u", addr, i); goto end; }
         llq = &opt.r.resrec.rdata->u.opt[i].u.llq; // 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; }
 
@@ -3100,9 +3100,9 @@ void mDNSCoreReceive(mDNS *const m, DNSMessage *const msg, const mDNSu8 *const e
                      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 int serviceID, const mDNSAddr *addr, const mDNSIPPort port, 
-                             mDNSu32 scoped, mDNSu32 timeout, mDNSBool cellIntf, mDNSBool isExpensive, mDNSBool isCLAT46, mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
-{ ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scoped; ( void ) timeout; (void) cellIntf; (void) isExpensive; (void) isCLAT46;
- (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
+                             mDNSu32 scopedType, mDNSu32 timeout, mDNSBool isCell, mDNSBool isExpensive, mDNSBool isConstrained,  mDNSBool isCLAT46, mDNSu32 resGroupID, mDNSBool reqA, mDNSBool reqAAAA, mDNSBool reqDO)
+{ ( void ) m; ( void ) d; ( void ) interface; ( void ) serviceID; ( void ) addr; ( void ) port; ( void ) scopedType; ( void ) timeout; (void) isCell; (void) isExpensive; (void) isConstrained; (void) isCLAT46;
   (void) resGroupID; (void) reqA; (void) reqAAAA; (void) reqDO; return(NULL); }
 void mDNS_AddSearchDomain(const domainname *const domain, mDNSInterfaceID InterfaceID) { (void)domain; (void) InterfaceID;}
 void mDNS_AddDynDNSHostName(mDNS *m, const domainname *fqdn, mDNSRecordCallback *StatusCallback, const void *StatusContext)
 { ( void ) m; ( void ) fqdn; ( void ) StatusCallback; ( void ) StatusContext; }
@@ -3124,13 +3124,11 @@ void mDNS_SetPrimaryInterfaceInfo(mDNS *m, const mDNSAddr *v4addr,  const mDNSAd
 { ( 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, const domainname *hostname, mDNSIPPort *port, mDNSBool autoTunnel)
-{ ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; ( void ) autoTunnel; return 0; }
+                                const domainname *domain, const domainname *keyname, const char *b64keydata, const domainname *hostname, mDNSIPPort *port)
+{ ( void ) m; ( void ) info; ( void ) domain; ( void ) keyname; ( void ) b64keydata; ( void ) hostname; (void) port; return 0; }
 mStatus mDNS_StopQuery(mDNS *const m, DNSQuestion *const question) { ( void ) m; ( void ) question; return 0; }
 void TriggerEventCompletion(void);
 void TriggerEventCompletion() {}
-int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q);
-int AnonInfoAnswersQuestion(const ResourceRecord *const rr, const DNSQuestion *const q) { ( void ) rr; ( void ) q; return 1;}
 mDNS mDNSStorage;
 
 
index 67927c9b9b2b516c31d7d01fab18fb3256608811..a6a1668c2f819454c4bc19fb99c780cc32979e1a 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2018 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.
@@ -20,9 +20,9 @@
 #define _dnsextd_h
 
 
-#include <mDNSEmbeddedAPI.h>
-#include <DNSCommon.h>
-#include <GenLinkedList.h>
+#include "mDNSEmbeddedAPI.h"
+#include "DNSCommon.h"
+#include "GenLinkedList.h"
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
index c0a309d558b6f41a6468c967c47c5bcc2a57deaf..d3e9a44605f9172a65d945f7d152f4d6525a31ec 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
@@ -25,6 +24,8 @@
 
 #include "dns_sd.h"             // Defines the interface to the client layer above
 #include "mDNSEmbeddedAPI.h"        // The interface we're building on top of
+#include <sys/socket.h>
+#include <netinet/in.h>
 extern mDNS mDNSStorage;        // We need to pass the address of this storage to the lower-layer functions
 
 #if MDNS_BUILDINGSHAREDLIBRARY || MDNS_BUILDINGSTUBLIBRARY
@@ -87,6 +88,16 @@ typedef struct
     DNSQuestion q;
 } mDNS_DirectOP_QueryRecord;
 
+typedef struct
+{
+    mDNS_DirectOP_Dispose     *disposefn;
+    DNSServiceGetAddrInfoReply callback;
+    void                      *context;
+    mDNSu32                    interfaceIndex;
+    DNSQuestion                a;
+    DNSQuestion                aaaa;
+} mDNS_DirectOP_GetAddrInfo;
+
 dnssd_sock_t DNSServiceRefSockFD(DNSServiceRef sdRef)
 {
     (void)sdRef;    // Unused
@@ -106,6 +117,19 @@ void DNSServiceRefDeallocate(DNSServiceRef sdRef)
     op->disposefn(op);
 }
 
+static mDNSInterfaceID DNSServiceInterfaceIndexToID(mDNSu32 interfaceIndex, DNSServiceFlags *flags)
+{
+    // Map kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny with the kDNSServiceFlagsIncludeP2P
+    // flag set so that the resolve will run over P2P interfaces that are not yet created.
+    if (interfaceIndex == kDNSServiceInterfaceIndexP2P)
+    {
+        LogOperation("handle_resolve_request: mapping kDNSServiceInterfaceIndexP2P to kDNSServiceInterfaceIndexAny + kDNSServiceFlagsIncludeP2P");
+        if (flags != mDNSNULL) *flags |= kDNSServiceFlagsIncludeP2P;
+        interfaceIndex = kDNSServiceInterfaceIndexAny;
+    }
+    return mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+}
+
 //*************************************************************************************************************
 // Domain Enumeration
 
@@ -245,7 +269,7 @@ DNSServiceErrorType DNSServiceRegister
     // Allocate memory, and handle failure
     if (size < txtLen)
         size = txtLen;
-    x = (mDNS_DirectOP_Register *)mDNSPlatformMemAllocate(sizeof(*x) - sizeof(RDataBody) + size);
+    x = (mDNS_DirectOP_Register *) mDNSPlatformMemAllocateClear(sizeof(*x) - sizeof(RDataBody) + size);
     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
 
     // Set up object
@@ -261,6 +285,7 @@ DNSServiceErrorType DNSServiceRegister
     err = mDNS_RegisterService(&mDNSStorage, &x->s,
                                &x->name, &t, &d, // Name, type, domain
                                &x->host, port, // Host and port
+                                                          mDNSNULL,
                                txtRecord, txtLen, // TXT data, length
                                SubTypes, NumSubTypes, // Subtypes
                                mDNSInterface_Any, // Interface ID
@@ -402,7 +427,7 @@ DNSServiceErrorType DNSServiceBrowse
     if (!MakeDomainNameFromDNSNameString(&d, *domain ? domain : "local.")) { errormsg = "Illegal domain";  goto badparam; }
 
     // Allocate memory, and handle failure
-    x = (mDNS_DirectOP_Browse *)mDNSPlatformMemAllocate(sizeof(*x));
+    x = (mDNS_DirectOP_Browse *) mDNSPlatformMemAllocateClear(sizeof(*x));
     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
 
     // Set up object
@@ -412,7 +437,7 @@ DNSServiceErrorType DNSServiceBrowse
     x->q.QuestionContext = x;
 
     // Do the operation
-    err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSNULL, mDNSInterface_Any, flags, (flags & kDNSServiceFlagsForceMulticast) != 0, (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, x);
+    err = mDNS_StartBrowse(&mDNSStorage, &x->q, &t, &d, mDNSInterface_Any, flags, (flags & kDNSServiceFlagsForceMulticast) != 0, (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, x);
     if (err) { mDNSPlatformMemFree(x); errormsg = "mDNS_StartBrowse"; goto fail; }
 
     // Succeeded: Wrap up and return
@@ -479,9 +504,6 @@ DNSServiceErrorType DNSServiceResolve
     domainname t, d, srv;
     mDNS_DirectOP_Resolve *x;
 
-    (void)flags;            // Unused
-    (void)interfaceIndex;   // Unused
-
     // Check parameters
     if (!name[0]    || !MakeDomainLabelFromLiteralString(&n, name  )) { errormsg = "Bad Instance Name"; goto badparam; }
     if (!regtype[0] || !MakeDomainNameFromDNSNameString(&t, regtype)) { errormsg = "Bad Service Type";  goto badparam; }
@@ -489,7 +511,7 @@ DNSServiceErrorType DNSServiceResolve
     if (!ConstructServiceName(&srv, &n, &t, &d))                      { errormsg = "Bad Name";          goto badparam; }
 
     // Allocate memory, and handle failure
-    x = (mDNS_DirectOP_Resolve *)mDNSPlatformMemAllocate(sizeof(*x));
+    x = (mDNS_DirectOP_Resolve *) mDNSPlatformMemAllocateClear(sizeof(*x));
     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
 
     // Set up object
@@ -500,9 +522,8 @@ DNSServiceErrorType DNSServiceResolve
     x->TXT       = mDNSNULL;
 
     x->qSRV.ThisQInterval       = -1;       // So that DNSServiceResolveDispose() knows whether to cancel this question
-    x->qSRV.InterfaceID         = mDNSInterface_Any;
-    x->qSRV.flags               = 0;
-    x->qSRV.Target              = zeroAddr;
+    x->qSRV.InterfaceID         = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
+    x->qSRV.flags               = flags;
     AssignDomainName(&x->qSRV.qname, &srv);
     x->qSRV.qtype               = kDNSType_SRV;
     x->qSRV.qclass              = kDNSClass_IN;
@@ -511,25 +532,20 @@ DNSServiceErrorType DNSServiceResolve
     x->qSRV.ForceMCast          = mDNSfalse;
     x->qSRV.ReturnIntermed      = mDNSfalse;
     x->qSRV.SuppressUnusable    = mDNSfalse;
-    x->qSRV.SearchListIndex     = 0;
     x->qSRV.AppendSearchDomains = 0;
-    x->qSRV.RetryWithSearchDomains = mDNSfalse;
     x->qSRV.TimeoutQuestion     = 0;
     x->qSRV.WakeOnResolve       = 0;
-    x->qSRV.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+    x->qSRV.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
     x->qSRV.ValidationRequired  = 0;
     x->qSRV.ValidatingResponse  = 0;
     x->qSRV.ProxyQuestion       = 0;
-    x->qSRV.qnameOrig           = mDNSNULL;
-    x->qSRV.AnonInfo            = mDNSNULL;
     x->qSRV.pid                 = mDNSPlatformGetPID();
     x->qSRV.QuestionCallback    = FoundServiceInfo;
     x->qSRV.QuestionContext     = x;
 
     x->qTXT.ThisQInterval       = -1;       // So that DNSServiceResolveDispose() knows whether to cancel this question
-    x->qTXT.InterfaceID         = mDNSInterface_Any;
-    x->qTXT.flags               = 0;
-    x->qTXT.Target              = zeroAddr;
+    x->qTXT.InterfaceID         = DNSServiceInterfaceIndexToID(interfaceIndex, mDNSNULL);
+    x->qTXT.flags               = flags;
     AssignDomainName(&x->qTXT.qname, &srv);
     x->qTXT.qtype               = kDNSType_TXT;
     x->qTXT.qclass              = kDNSClass_IN;
@@ -538,17 +554,13 @@ DNSServiceErrorType DNSServiceResolve
     x->qTXT.ForceMCast          = mDNSfalse;
     x->qTXT.ReturnIntermed      = mDNSfalse;
     x->qTXT.SuppressUnusable    = mDNSfalse;
-    x->qTXT.SearchListIndex     = 0;
     x->qTXT.AppendSearchDomains = 0;
-    x->qTXT.RetryWithSearchDomains = mDNSfalse;
     x->qTXT.TimeoutQuestion     = 0;
     x->qTXT.WakeOnResolve       = 0;
-    x->qTXT.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+    x->qTXT.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
     x->qTXT.ValidationRequired  = 0;
     x->qTXT.ValidatingResponse  = 0;
     x->qTXT.ProxyQuestion       = 0;
-    x->qTXT.qnameOrig           = mDNSNULL;
-    x->qTXT.AnonInfo            = mDNSNULL;
     x->qTXT.pid                 = mDNSPlatformGetPID();
     x->qTXT.QuestionCallback    = FoundServiceInfo;
     x->qTXT.QuestionContext     = x;
@@ -637,25 +649,22 @@ mDNSlocal void DNSServiceQueryRecordResponse(mDNS *const m, DNSQuestion *questio
 
 DNSServiceErrorType DNSServiceQueryRecord
 (
-    DNSServiceRef                       *sdRef,
-    DNSServiceFlags flags,
-    uint32_t interfaceIndex,
-    const char                          *fullname,
-    uint16_t rrtype,
-    uint16_t rrclass,
+    DNSServiceRef             *sdRef,
+    DNSServiceFlags            flags,
+    uint32_t                   interfaceIndex,
+    const char                *fullname,
+    uint16_t                   rrtype,
+    uint16_t                   rrclass,
     DNSServiceQueryRecordReply callback,
-    void                                *context  /* may be NULL */
+    void                      *context  /* may be NULL */
 )
 {
     mStatus err = mStatus_NoError;
     const char *errormsg = "Unknown";
     mDNS_DirectOP_QueryRecord *x;
 
-    (void)flags;            // Unused
-    (void)interfaceIndex;   // Unused
-
     // Allocate memory, and handle failure
-    x = (mDNS_DirectOP_QueryRecord *)mDNSPlatformMemAllocate(sizeof(*x));
+    x = (mDNS_DirectOP_QueryRecord *) mDNSPlatformMemAllocateClear(sizeof(*x));
     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
 
     // Set up object
@@ -663,32 +672,27 @@ DNSServiceErrorType DNSServiceQueryRecord
     x->callback  = callback;
     x->context   = context;
 
-    x->q.ThisQInterval       = -1;      // So that DNSServiceResolveDispose() knows whether to cancel this question
-    x->q.InterfaceID         = mDNSInterface_Any;
-    x->q.flags               = flags;
-    x->q.Target              = zeroAddr;
+    x->q.ThisQInterval        = -1;      // So that DNSServiceResolveDispose() knows whether to cancel this question
+    x->q.InterfaceID          = DNSServiceInterfaceIndexToID(interfaceIndex, &flags);
+    x->q.flags                = flags;
     MakeDomainNameFromDNSNameString(&x->q.qname, fullname);
-    x->q.qtype               = rrtype;
-    x->q.qclass              = rrclass;
-    x->q.LongLived           = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
-    x->q.ExpectUnique        = mDNSfalse;
-    x->q.ForceMCast          = (flags & kDNSServiceFlagsForceMulticast) != 0;
-    x->q.ReturnIntermed      = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
-    x->q.SuppressUnsable     = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
-    x->q.SearchListIndex     = 0;
-    x->q.AppendSearchDomains = 0;
-    x->q.RetryWithSearchDomains = mDNSfalse;
-    x->q.TimeoutQuestion     = 0;
-    x->q.WakeOnResolve       = 0;
-    x->q.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
-    x->q.ValidationRequired  = 0;
-    x->q.ValidatingResponse  = 0;
-    x->q.ProxyQuestion       = 0;
-    x->q.qnameOrig           = mDNSNULL;
-    x->q.AnonInfo            = mDNSNULL;
-    x->q.pid                 = mDNSPlatformGetPID();
-    x->q.QuestionCallback    = DNSServiceQueryRecordResponse;
-    x->q.QuestionContext     = x;
+    x->q.qtype                = rrtype;
+    x->q.qclass               = rrclass;
+    x->q.LongLived            = (flags & kDNSServiceFlagsLongLivedQuery) != 0;
+    x->q.ExpectUnique         = mDNSfalse;
+    x->q.ForceMCast           = (flags & kDNSServiceFlagsForceMulticast) != 0;
+    x->q.ReturnIntermed       = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
+    x->q.SuppressUnusable     = (flags & kDNSServiceFlagsSuppressUnusable) != 0;
+    x->q.AppendSearchDomains  = 0;
+    x->q.TimeoutQuestion      = 0;
+    x->q.WakeOnResolve        = 0;
+    x->q.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+    x->q.ValidationRequired   = 0;
+    x->q.ValidatingResponse   = 0;
+    x->q.ProxyQuestion        = 0;
+    x->q.pid                  = mDNSPlatformGetPID();
+    x->q.QuestionCallback     = DNSServiceQueryRecordResponse;
+    x->q.QuestionContext      = x;
 
     err = mDNS_StartQuery(&mDNSStorage, &x->q);
     if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
@@ -704,71 +708,184 @@ fail:
 
 //*************************************************************************************************************
 // DNSServiceGetAddrInfo
+//
 
 static void DNSServiceGetAddrInfoDispose(mDNS_DirectOP *op)
 {
     mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)op;
-    if (x->aQuery) DNSServiceRefDeallocate(x->aQuery);
+    if (x->a.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->a);
+    if (x->aaaa.ThisQInterval >= 0) mDNS_StopQuery(&mDNSStorage, &x->aaaa);
     mDNSPlatformMemFree(x);
 }
 
-static void DNSSD_API DNSServiceGetAddrInfoResponse(
-    DNSServiceRef inRef,
-    DNSServiceFlags inFlags,
-    uint32_t inInterfaceIndex,
-    DNSServiceErrorType inErrorCode,
-    const char *        inFullName,
-    uint16_t inRRType,
-    uint16_t inRRClass,
-    uint16_t inRDLen,
-    const void *        inRData,
-    uint32_t inTTL,
-    void *              inContext )
-{
-    mDNS_DirectOP_GetAddrInfo *     x = (mDNS_DirectOP_GetAddrInfo*)inContext;
-    struct sockaddr_in sa4;
-
-    mDNSPlatformMemZero(&sa4, sizeof(sa4));
-    if (inErrorCode == kDNSServiceErr_NoError && inRRType == kDNSServiceType_A)
+mDNSlocal void DNSServiceGetAddrInfoResponse(mDNS *const m, DNSQuestion *question,
+                                             const ResourceRecord *const answer, QC_result addRecord)
+{
+    mDNS_DirectOP_GetAddrInfo *x = (mDNS_DirectOP_GetAddrInfo*)question->QuestionContext;
+    char fullname[MAX_ESCAPED_DOMAIN_NAME];
+
+    struct sockaddr_storage sas;
+       struct sockaddr_in *sin = (struct sockaddr_in *)&sas;
+       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sas;
+    void *sa_ap = mDNSNULL;
+    int sa_as = 0;
+    mStatus err = mStatus_NoError;
+
+    (void)m;    // Unused
+
+       mDNSPlatformMemZero(&sas, sizeof sas);
+
+    ConvertDomainNameToCString(answer->name, fullname);
+
+    if (addRecord == QC_suppressed || answer->RecordType == kDNSRecordTypePacketNegative)
     {
-        sa4.sin_family = AF_INET;
-        mDNSPlatformMemCopy(&sa4.sin_addr.s_addr, inRData, 4);
+        err = mStatus_NoSuchRecord;
+    }
+        
+    // There are three checks here for bad data: class != IN, RRTYPE not in {A,AAAA} and wrong length.
+    // None of these should be possible, because the cache code wouldn't cache malformed data and wouldn't
+    // return records we didn't ask for, but it doesn't hurt to check.
+    if (answer->rrclass != kDNSServiceClass_IN)
+    {
+        LogMsg("DNSServiceGetAddrInfoResponse: response of class %d received, which is bogus", answer->rrclass);
+    totally_invalid:
+        if (x->a.ThisQInterval >= 0)
+        {
+            sin->sin_family = AF_INET;
+#ifndef NOT_HAVE_SA_LEN
+            sin->sin_len = sizeof *sin;
+#endif
+            x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
+                        (const struct sockaddr *)&sas, 0, x->context);
+        }
+        if (x->aaaa.ThisQInterval >= 0)
+        {
+            sin6->sin6_family = AF_INET6;
+#ifndef NOT_HAVE_SA_LEN
+            sin6->sin6_len = sizeof *sin6;
+#endif
+            x->callback((DNSServiceRef)x, 0, x->interfaceIndex, kDNSServiceErr_Invalid, fullname,
+                        (const struct sockaddr *)&sas, 0, x->context);
+        }
+        return;
+    }
+    else if (answer->rrtype == kDNSServiceType_A)
+    {
+        sin->sin_family = AF_INET;
+#ifndef NOT_HAVE_SA_LEN
+        sin->sin_len = sizeof *sin;
+#endif
+        sa_ap = &sin->sin_addr;
+        sa_as = sizeof sin->sin_addr.s_addr;
+    }
+    else if (answer->rrtype == kDNSServiceType_AAAA)
+    {
+        sin6->sin6_family = AF_INET6;
+#ifndef NOT_HAVE_SA_LEN
+        sin6->sin6_len = sizeof *sin6;
+#endif
+        sa_ap = &sin6->sin6_addr;
+        sa_as = sizeof sin6->sin6_addr.s6_addr;
+    }
+    else
+    {
+        LogMsg("DNSServiceGetAddrInfoResponse: response of type %d received, which is bogus", answer->rrtype);
+        goto totally_invalid;
+    }
+    
+    if (err == kDNSServiceErr_NoError && sa_ap != mDNSNULL)
+    {
+        if (err == mStatus_NoError)
+        {
+            if (answer->rdlength == sa_as)
+            {
+                mDNSPlatformMemCopy(sa_ap, answer->rdata->u.data, answer->rdlength);
+            }
+            else
+            {
+                LogMsg("DNSServiceGetAddrInfoResponse: %s rrtype with length %d received",
+                       answer->rrtype == kDNSServiceType_A ? "A" : "AAAA", answer->rdlength);
+                goto totally_invalid;
+            }
+        }
     }
 
-    x->callback((DNSServiceRef)x, inFlags, inInterfaceIndex, inErrorCode, inFullName,
-                (const struct sockaddr *) &sa4, inTTL, x->context);
+    x->callback((DNSServiceRef)x, addRecord ? kDNSServiceFlagsAdd : (DNSServiceFlags)0, x->interfaceIndex, err,
+                fullname, (const struct sockaddr *)&sas, answer->rroriginalttl, x->context);
 }
 
 DNSServiceErrorType DNSSD_API DNSServiceGetAddrInfo(
-    DNSServiceRef *             outRef,
-    DNSServiceFlags inFlags,
-    uint32_t inInterfaceIndex,
-    DNSServiceProtocol inProtocol,
-    const char *                inHostName,
+    DNSServiceRef             *outRef,
+    DNSServiceFlags            inFlags,
+    uint32_t                   inInterfaceIndex,
+    DNSServiceProtocol         inProtocol,
+    const char                *inHostName,
     DNSServiceGetAddrInfoReply inCallback,
-    void *                      inContext )
+    void                      *inContext )
 {
-    const char *                    errormsg = "Unknown";
-    DNSServiceErrorType err;
-    mDNS_DirectOP_GetAddrInfo *     x;
+    const char                *errormsg = "Unknown";
+    DNSServiceErrorType        err;
+    mDNS_DirectOP_GetAddrInfo *x;
 
     // Allocate memory, and handle failure
-    x = (mDNS_DirectOP_GetAddrInfo *)mDNSPlatformMemAllocate(sizeof(*x));
+    x = (mDNS_DirectOP_GetAddrInfo *) mDNSPlatformMemAllocateClear(sizeof(*x));
     if (!x) { err = mStatus_NoMemoryErr; errormsg = "No memory"; goto fail; }
 
     // Set up object
-    x->disposefn = DNSServiceGetAddrInfoDispose;
-    x->callback  = inCallback;
-    x->context   = inContext;
-    x->aQuery    = mDNSNULL;
-
-    // Start the query.
-    // (It would probably be more efficient to code this using mDNS_StartQuery directly,
-    // instead of wrapping DNSServiceQueryRecord, which then unnecessarily allocates
-    // more memory and then just calls through to mDNS_StartQuery. -- SC June 2010)
-    err = DNSServiceQueryRecord(&x->aQuery, inFlags, inInterfaceIndex, inHostName, kDNSServiceType_A,
-                                kDNSServiceClass_IN, DNSServiceGetAddrInfoResponse, x);
-    if (err) { DNSServiceGetAddrInfoDispose((mDNS_DirectOP*)x); errormsg = "DNSServiceQueryRecord"; goto fail; }
+    x->disposefn      = DNSServiceGetAddrInfoDispose;
+    x->callback       = inCallback;
+    x->context        = inContext;
+    x->interfaceIndex = inInterfaceIndex;
+
+    // Validate and default the protocols.
+    if ((inProtocol & ~(kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) != 0)
+    {
+        err = mStatus_BadParamErr;
+        errormsg = "Unsupported protocol";
+        goto fail;
+    }
+    // In theory this API checks to see if we have a routable IPv6 address, but 
+    if ((inProtocol & (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6)) == 0)
+    {
+        inProtocol = kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6;
+        inFlags |= kDNSServiceFlagsSuppressUnusable;
+    }
+    
+    x->a.ThisQInterval        = -1;      // So we know whether to cancel this question
+    x->a.InterfaceID          = DNSServiceInterfaceIndexToID(inInterfaceIndex, &inFlags);
+    x->a.flags                = inFlags;
+    MakeDomainNameFromDNSNameString(&x->a.qname, inHostName);
+    x->a.qtype                = kDNSType_A;
+    x->a.qclass               = kDNSClass_IN;
+    x->a.LongLived            = (inFlags & kDNSServiceFlagsLongLivedQuery) != 0;
+    x->a.ExpectUnique         = mDNSfalse;
+    x->a.ForceMCast           = (inFlags & kDNSServiceFlagsForceMulticast) != 0;
+    x->a.ReturnIntermed       = (inFlags & kDNSServiceFlagsReturnIntermediates) != 0;
+    x->a.SuppressUnusable     = (inFlags & kDNSServiceFlagsSuppressUnusable) != 0;
+    x->a.AppendSearchDomains  = 0;
+    x->a.TimeoutQuestion      = 0;
+    x->a.WakeOnResolve        = 0;
+    x->a.UseBackgroundTraffic = (inFlags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+    x->a.ValidationRequired   = 0;
+    x->a.ValidatingResponse   = 0;
+    x->a.ProxyQuestion        = 0;
+    x->a.pid                  = mDNSPlatformGetPID();
+    x->a.QuestionCallback     = DNSServiceGetAddrInfoResponse;
+    x->a.QuestionContext      = x;
+
+       x->aaaa = x->a;
+       x->aaaa.qtype = kDNSType_AAAA;
+
+    if (inProtocol & kDNSServiceProtocol_IPv4)
+    {
+        err = mDNS_StartQuery(&mDNSStorage, &x->a);
+        if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
+    }
+    if (inProtocol & kDNSServiceProtocol_IPv6)
+    {
+        err = mDNS_StartQuery(&mDNSStorage, &x->aaaa);
+        if (err) { DNSServiceResolveDispose((mDNS_DirectOP*)x); errormsg = "mDNS_StartQuery"; goto fail; }
+    }
 
     *outRef = (DNSServiceRef)x;
     return(mStatus_NoError);
@@ -807,5 +924,13 @@ DNSServiceErrorType DNSSD_API DNSServiceReconfirmRecord
     return(kDNSServiceErr_Unsupported);
 }
 
+#endif // !MDNS_BUILDINGSTUBLIBRARY
 
-#endif  // !MDNS_BUILDINGSTUBLIBRARY
+// Local Variables:
+// mode: C
+// tab-width: 4
+// c-file-style: "bsd"
+// c-basic-offset: 4
+// fill-column: 108
+// indent-tabs-mode: nil
+// End:
index e8600cba257de8762bdedd4102b1697d09976e1e..fbeeb121643d8aec7745f4ffd8c9a30a1be79eb4 100644 (file)
@@ -80,7 +80,7 @@ static void syslog( int priority, const char * message, ...)
 }
 #else
 
-    #include <sys/fcntl.h>      // For O_RDWR etc.
+    #include <fcntl.h>      // For O_RDWR etc.
     #include <sys/time.h>
     #include <sys/socket.h>
     #include <syslog.h>
@@ -90,9 +90,11 @@ static void syslog( int priority, const char * message, ...)
 
 #endif
 
+#if defined(_WIN32)
 // <rdar://problem/4096913> Specifies how many times we'll try and connect to the server.
 
 #define DNSSD_CLIENT_MAXTRIES 4
+#endif // _WIN32
 
 // 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
@@ -185,11 +187,13 @@ static void SetUDSPath(struct sockaddr_un *saddr, const char *path)
 }
 #endif
 
+enum { write_all_success = 0, write_all_fail = -1, write_all_defunct = -2 };
+
 // Write len bytes. Return 0 on success, -1 on error
 static int write_all(dnssd_sock_t sd, char *buf, size_t len)
 {
     // Don't use "MSG_WAITALL"; it returns "Invalid argument" on some Linux versions; use an explicit while() loop instead.
-    //if (send(sd, buf, len, MSG_WAITALL) != len) return -1;
+    //if (send(sd, buf, len, MSG_WAITALL) != len) return write_all_fail;
     while (len)
     {
         ssize_t num_written = send(sd, buf, (long)len, 0);
@@ -210,21 +214,22 @@ static int write_all(dnssd_sock_t sd, char *buf, size_t len)
                        (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
             else
                 syslog(LOG_INFO, "dnssd_clientstub write_all(%d) DEFUNCT", sd);
+            return defunct ? write_all_defunct : write_all_fail;
 #else
             syslog(LOG_WARNING, "dnssd_clientstub write_all(%d) failed %ld/%ld %d %s", sd,
                    (long)num_written, (long)len,
                    (num_written < 0) ? dnssd_errno                 : 0,
                    (num_written < 0) ? dnssd_strerror(dnssd_errno) : "");
+            return write_all_fail;
 #endif
-            return -1;
         }
         buf += num_written;
         len -= num_written;
     }
-    return 0;
+    return write_all_success;
 }
 
-enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2 };
+enum { read_all_success = 0, read_all_fail = -1, read_all_wouldblock = -2, read_all_defunct = -3 };
 
 // Read len bytes. Return 0 on success, read_all_fail on error, or read_all_wouldblock for
 static int read_all(dnssd_sock_t sd, char *buf, int len)
@@ -272,7 +277,7 @@ static int read_all(dnssd_sock_t sd, char *buf, int len)
                        (num_read < 0) ? dnssd_strerror(dnssd_errno) : "");
             else if (defunct)
                 syslog(LOG_INFO, "dnssd_clientstub read_all(%d) DEFUNCT", sd);
-            return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : read_all_fail;
+            return (num_read < 0 && dnssd_errno == dnssd_EWOULDBLOCK) ? read_all_wouldblock : (defunct ? read_all_defunct : read_all_fail);
         }
         buf += num_read;
         len -= num_read;
@@ -294,6 +299,7 @@ static int more_bytes(dnssd_sock_t sd)
     FD_SET(sd, fs);
     ret = select((int)sd+1, fs, (fd_set*)NULL, (fd_set*)NULL, &tv);
 #else
+    // This whole thing would probably be better done using kevent() instead of select()
     if (sd < FD_SETSIZE)
     {
         fs = &readfds;
@@ -332,6 +338,10 @@ static int set_waitlimit(dnssd_sock_t sock, int timeout)
 {
     int gDaemonErr = kDNSServiceErr_NoError;
 
+    // The comment below is wrong. The select() routine does not cause stack corruption.
+    // The use of FD_SET out of range for the bitmap is what causes stack corruption.
+    // For how to do this correctly, see the example using calloc() in more_bytes() above.
+    // Even better, both should be changed to use kevent() instead of select().
     // To prevent stack corruption since select does not work with timeout if fds > FD_SETSIZE(1024)
     if (!gDaemonErr && sock < FD_SETSIZE)
     {
@@ -430,9 +440,6 @@ static void FreeDNSServiceOp(DNSServiceOp *x)
     // then sockfd could legitimately contain a failing value (e.g. dnssd_InvalidSocket)
     if ((x->sockfd ^ x->validator) != ValidatorBits)
     {
-        static DNSServiceOp *op_were_not_going_to_free_but_we_need_to_fool_the_analyzer;
-        syslog(LOG_WARNING, "dnssd_clientstub attempt to dispose invalid DNSServiceRef %p %08X %08X", x, x->sockfd, x->validator);
-        op_were_not_going_to_free_but_we_need_to_fool_the_analyzer = x;
     }
     else
     {
@@ -468,7 +475,9 @@ static void FreeDNSServiceOp(DNSServiceOp *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 defined(_WIN32)
     int NumTries = 0;
+    #endif // _WIN32
 
     dnssd_sockaddr_t saddr;
     DNSServiceOp *sdr;
@@ -503,7 +512,7 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
         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()) 
+    if (IsSystemServiceDisabled())
         NumTries = DNSSD_CLIENT_MAXTRIES;
     #endif
 
@@ -573,6 +582,22 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
             FreeDNSServiceOp(sdr);
             return kDNSServiceErr_NoMemory;
         }
+#if !defined(_WIN32)
+        int fcntl_flags = fcntl(sdr->sockfd, F_GETFD);
+        if (fcntl_flags != -1)
+        {
+            fcntl_flags |= FD_CLOEXEC;
+            int ret = fcntl(sdr->sockfd, F_SETFD, fcntl_flags);
+            if (ret == -1)
+                syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to set FD_CLOEXEC on socket %d %s",
+                       dnssd_errno, dnssd_strerror(dnssd_errno));
+        }
+        else
+        {
+            syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: Failed to get the file descriptor flags of socket %d %s",
+                   dnssd_errno, dnssd_strerror(dnssd_errno));
+        }
+#endif // !defined(_WIN32)
         #ifdef SO_NOSIGPIPE
         // Some environments (e.g. OS X) support turning off SIGPIPE for a socket
         if (setsockopt(sdr->sockfd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)) < 0)
@@ -593,12 +618,14 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
         }
         #endif
         #endif
-        
+
+        #if defined(_WIN32)
         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 wait 1 sec and try again.
@@ -606,21 +633,33 @@ static DNSServiceErrorType ConnectToServer(DNSServiceRef *ref, DNSServiceFlags f
             // then we give up and return a failure code.
             if (++NumTries < DNSSD_CLIENT_MAXTRIES)
             {
-                syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);  
+                syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect()-> No of tries: %d", NumTries);
                 sleep(1); // Sleep a bit, then try again
             }
-            else 
+            else
             {
                 #if !defined(USE_TCP_LOOPBACK)
-                syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s", 
+                syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
                        uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
                 #endif
-                dnssd_close(sdr->sockfd); 
-                FreeDNSServiceOp(sdr); 
-                return kDNSServiceErr_ServiceNotRunning; 
+                dnssd_close(sdr->sockfd);
+                FreeDNSServiceOp(sdr);
+                return kDNSServiceErr_ServiceNotRunning;
             }
         }
-        //printf("ConnectToServer opened socket %d\n", sdr->sockfd);
+        #else
+        int err = connect(sdr->sockfd, (struct sockaddr *) &saddr, sizeof(saddr));
+        if (err)
+        {
+            #if !defined(USE_TCP_LOOPBACK)
+            syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: connect() failed path:%s Socket:%d Err:%d Errno:%d %s",
+                   uds_serverpath, sdr->sockfd, err, dnssd_errno, dnssd_strerror(dnssd_errno));
+            #endif
+            dnssd_close(sdr->sockfd);
+            FreeDNSServiceOp(sdr);
+            return kDNSServiceErr_ServiceNotRunning;
+        }
+        #endif
     }
 
     *ref = sdr;
@@ -636,6 +675,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
     dnssd_sock_t listenfd = dnssd_InvalidSocket, errsd = dnssd_InvalidSocket;
     DNSServiceErrorType err = kDNSServiceErr_Unknown;   // Default for the "goto cleanup" cases
     int MakeSeparateReturnSocket;
+    int ioresult;
     #if defined(USE_TCP_LOOPBACK) || defined(USE_NAMED_ERROR_RETURN_SOCKET)
     char *data;
     #endif
@@ -719,7 +759,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
                 {
                     int defunct = 1;
                     if (setsockopt(errsd, SOL_SOCKET, SO_DEFUNCTOK, &defunct, sizeof(defunct)) < 0)
-                        syslog(LOG_WARNING, "dnssd_clientstub ConnectToServer: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
+                        syslog(LOG_WARNING, "dnssd_clientstub deliver_request: SO_DEFUNCTOK failed %d %s", dnssd_errno, dnssd_strerror(dnssd_errno));
                 }
                 #endif
             }
@@ -747,18 +787,25 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
     for (i=0; i<datalen + sizeof(ipc_msg_hdr); i++)
     {
         syslog(LOG_WARNING, "dnssd_clientstub deliver_request writing %d", i);
-        if (write_all(sdr->sockfd, ((char *)hdr)+i, 1) < 0)
-        { syslog(LOG_WARNING, "write_all (byte %u) failed", i); goto cleanup; }
+        ioresult = write_all(sdr->sockfd, ((char *)hdr)+i, 1);
+        if (ioresult < write_all_success)
+        {
+            syslog(LOG_WARNING, "dnssd_clientstub deliver_request write_all (byte %u) failed", i);
+            err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+            goto cleanup;
+        }
         usleep(10000);
     }
 #else
-    if (write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr)) < 0)
+    ioresult = write_all(sdr->sockfd, (char *)hdr, datalen + sizeof(ipc_msg_hdr));
+    if (ioresult < write_all_success)
     {
         // write_all already prints an error message if there is an error writing to
         // the socket except for DEFUNCT. Logging here is unnecessary and also wrong
         // in the case of DEFUNCT sockets
         syslog(LOG_INFO, "dnssd_clientstub deliver_request ERROR: write_all(%d, %lu bytes) failed",
                sdr->sockfd, (unsigned long)(datalen + sizeof(ipc_msg_hdr)));
+        err = (ioresult == write_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
         goto cleanup;
     }
 #endif
@@ -800,9 +847,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
                 {
                     snprintf(p, sizeof(p), "/dev/bpf%d", i);
                     listenfd = open(p, O_RDWR, 0);
-                    //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "Sending fd %d for %s", listenfd, p);
+                    //if (dnssd_SocketValid(listenfd)) syslog(LOG_WARNING, "dnssd_clientstub deliver_request Sending fd %d for %s", listenfd, p);
                     if (!dnssd_SocketValid(listenfd) && dnssd_errno != EBUSY)
-                        syslog(LOG_WARNING, "Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
+                        syslog(LOG_WARNING, "dnssd_clientstub deliver_request Error opening %s %d (%s)", p, dnssd_errno, dnssd_strerror(dnssd_errno));
                     if (dnssd_SocketValid(listenfd) || dnssd_errno != EBUSY) break;
                 }
             }
@@ -821,7 +868,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
 #endif
 
 #if DEBUG_64BIT_SCM_RIGHTS
-        syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
+        syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d %ld %ld %ld/%ld/%ld/%ld",
                errsd, listenfd, sizeof(dnssd_sock_t), sizeof(void*),
                sizeof(struct cmsghdr) + sizeof(dnssd_sock_t),
                CMSG_LEN(sizeof(dnssd_sock_t)), (long)CMSG_SPACE(sizeof(dnssd_sock_t)),
@@ -837,7 +884,7 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
         }
 
 #if DEBUG_64BIT_SCM_RIGHTS
-        syslog(LOG_WARNING, "dnssd_clientstub sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
+        syslog(LOG_WARNING, "dnssd_clientstub deliver_request sendmsg read sd=%d write sd=%d okay", errsd, listenfd);
 #endif // DEBUG_64BIT_SCM_RIGHTS
 
 #endif
@@ -857,8 +904,9 @@ static DNSServiceErrorType deliver_request(ipc_msg_hdr *hdr, DNSServiceOp *sdr)
         err = kDNSServiceErr_NoError;
     else if ((err = set_waitlimit(errsd, DNSSD_CLIENT_TIMEOUT)) == kDNSServiceErr_NoError)
     {
-        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
+        ioresult = read_all(errsd, (char*)&err, (int)sizeof(err));
+        if (ioresult < read_all_success)
+            err = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; // On failure read_all will have written a message to syslog for us
         else
             err = ntohl(err);
     }
@@ -946,7 +994,7 @@ static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
                 if (rec->AppCallback) ((DNSServiceRegisterRecordReply)rec->AppCallback)(sdr, 0, 0, error, rec->AppContext);
                 // The Callback can call DNSServiceRefDeallocate which in turn frees sdr and all the records.
                 // Detect that and return early
-                if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:Record: CallbackwithError morebytes zero"); return;}
+                if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:Record: CallbackwithError morebytes zero"); return; }
                 rec = recnext;
             }
             break;
@@ -964,7 +1012,7 @@ static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
         //
         // If DNSServiceRefDeallocate was not called in the callback, then set moreptr to NULL so that
         // we don't access the stack variable after we return from this function.
-        if (!morebytes) {syslog(LOG_WARNING, "dnssdclientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return;}
+        if (!morebytes) { syslog(LOG_WARNING, "dnssd_clientstub:sdRef: CallbackwithError morebytes zero sdr %p", sdr); return; }
         else {sdr->moreptr = NULL;}
         sdr = sdrNext;
     }
@@ -976,6 +1024,8 @@ static void CallbackWithError(DNSServiceRef sdRef, DNSServiceErrorType error)
 DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
 {
     int morebytes = 0;
+    int ioresult;
+    DNSServiceErrorType error;
 
     if (!sdRef) { syslog(LOG_WARNING, "dnssd_clientstub DNSServiceProcessResult called with NULL DNSServiceRef"); return kDNSServiceErr_BadParam; }
 
@@ -1008,9 +1058,11 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
         // where a non-blocking socket is told there is data, but it was a false positive.
         // On error, read_all will write a message to syslog for us, so don't need to duplicate that here
         // Note: If we want to properly support using non-blocking sockets in the future
-        int result = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
-        if (result == read_all_fail)
+        ioresult = read_all(sdRef->sockfd, (void *)&cbh.ipc_hdr, sizeof(cbh.ipc_hdr));
+        if (ioresult == read_all_fail || ioresult == read_all_defunct)
         {
+            error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+            
             // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
             // in the callback.
             sdRef->ProcessReply = NULL;
@@ -1025,13 +1077,13 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
                 dispatch_source_cancel(sdRef->disp_source);
                 dispatch_release(sdRef->disp_source);
                 sdRef->disp_source = NULL;
-                CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+                CallbackWithError(sdRef, error);
             }
 #endif
             // Don't touch sdRef anymore as it might have been deallocated
-            return kDNSServiceErr_ServiceNotRunning;
+            return error;
         }
-        else if (result == read_all_wouldblock)
+        else if (ioresult == read_all_wouldblock)
         {
             if (morebytes && sdRef->logcounter < 100)
             {
@@ -1051,8 +1103,11 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
 
         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
+        ioresult = read_all(sdRef->sockfd, data, cbh.ipc_hdr.datalen);
+        if (ioresult < read_all_success) // On error, read_all will write a message to syslog for us
         {
+            error = (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning;
+            
             // Set the ProcessReply to NULL before callback as the sdRef can get deallocated
             // in the callback.
             sdRef->ProcessReply = NULL;
@@ -1065,12 +1120,12 @@ DNSServiceErrorType DNSSD_API DNSServiceProcessResult(DNSServiceRef sdRef)
                 dispatch_source_cancel(sdRef->disp_source);
                 dispatch_release(sdRef->disp_source);
                 sdRef->disp_source = NULL;
-                CallbackWithError(sdRef, kDNSServiceErr_ServiceNotRunning);
+                CallbackWithError(sdRef, error);
             }
 #endif
             // Don't touch sdRef anymore as it might have been deallocated
             free(data);
-            return kDNSServiceErr_ServiceNotRunning;
+            return error;
         }
         else
         {
@@ -1189,6 +1244,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *
     ipc_msg_hdr *hdr;
     DNSServiceOp *tmp;
     uint32_t actualsize;
+    int ioresult;
 
     if (!property || !result || !size)
         return kDNSServiceErr_BadParam;
@@ -1204,12 +1260,14 @@ DNSServiceErrorType DNSSD_API DNSServiceGetProperty(const char *property, void *
     err = deliver_request(hdr, tmp);        // Will free hdr for us
     if (err) { DNSServiceRefDeallocate(tmp); return err; }
 
-    if (read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize)) < 0)
-    { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+    ioresult = read_all(tmp->sockfd, (char*)&actualsize, (int)sizeof(actualsize));
+    if (ioresult < read_all_success)
+    { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
 
     actualsize = ntohl(actualsize);
-    if (read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size) < 0)
-    { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+    ioresult = read_all(tmp->sockfd, (char*)result, actualsize < *size ? actualsize : *size);
+    if (ioresult < read_all_success)
+    { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
     DNSServiceRefDeallocate(tmp);
 
     // Swap version result back to local process byte order
@@ -1226,6 +1284,7 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *
     ipc_msg_hdr *hdr;
     DNSServiceOp *tmp = NULL;
     size_t len = sizeof(int32_t);
+    int ioresult;
 
     DNSServiceErrorType err = ConnectToServer(&tmp, 0, getpid_request, NULL, NULL, NULL);
     if (err) return err;
@@ -1237,8 +1296,9 @@ DNSServiceErrorType DNSSD_API DNSServiceGetPID(const uint16_t srcport, int32_t *
     err = deliver_request(hdr, tmp);        // Will free hdr for us
     if (err) { DNSServiceRefDeallocate(tmp); return err; }
 
-    if (read_all(tmp->sockfd, (char*)pid, sizeof(int32_t)) < 0)
-    { DNSServiceRefDeallocate(tmp); return kDNSServiceErr_ServiceNotRunning; }
+    ioresult = read_all(tmp->sockfd, (char*)pid, sizeof(int32_t));
+    if (ioresult < read_all_success)
+    { DNSServiceRefDeallocate(tmp); return (ioresult == read_all_defunct) ? kDNSServiceErr_DefunctConnection : kDNSServiceErr_ServiceNotRunning; }
 
     DNSServiceRefDeallocate(tmp);
     return kDNSServiceErr_NoError;
@@ -1269,7 +1329,7 @@ fail:
     syslog(LOG_WARNING, "dnssd_clientstub handle_resolve_response: error reading result from daemon");
 }
 
-#if TARGET_OS_EMBEDDED
+#if TARGET_OS_IPHONE
 
 static int32_t libSystemVersion = 0;
 
@@ -1287,7 +1347,7 @@ static int includeP2PWithIndexAny()
         return 0;
 }
 
-#else   // TARGET_OS_EMBEDDED
+#else   // TARGET_OS_IPHONE
 
 // always return false for non iOS platforms
 static int includeP2PWithIndexAny()
@@ -1295,7 +1355,7 @@ static int includeP2PWithIndexAny()
     return 0;
 }
 
-#endif  // TARGET_OS_EMBEDDED
+#endif  // TARGET_OS_IPHONE
 
 DNSServiceErrorType DNSSD_API DNSServiceResolve
 (
@@ -1761,12 +1821,12 @@ static void ConnectionResponse(DNSServiceOp *const sdr, const CallbackHeader *co
         // error if the record is not found.
         if (!rec)
         {
-            syslog(LOG_INFO, "ConnectionResponse: Record not found");
+            syslog(LOG_INFO, "dnssd_clientstub ConnectionResponse: Record not found");
             return;
         }
         if (rec->sdr != sdr)
         {
-            syslog(LOG_WARNING, "ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
+            syslog(LOG_WARNING, "dnssd_clientstub ConnectionResponse: Record sdr mismatch: rec %p sdr %p", rec->sdr, sdr);
             return;
         }
 
@@ -1802,7 +1862,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateConnection(DNSServiceRef *sdRef)
     return err;
 }
 
-#if APPLE_OSX_mDNSResponder && !TARGET_IPHONE_SIMULATOR
+#if APPLE_OSX_mDNSResponder && !TARGET_OS_SIMULATOR
 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
 {
     char *ptr;
@@ -1832,7 +1892,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *
 
     if (pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED, &pid, sizeof(pid)) == -1)
     { 
-        syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno)); 
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for PID[%d], no entitlements or process(pid) invalid errno:%d (%s)", pid, errno, strerror(errno)); 
         // Free the hdr in case we return before calling deliver_request() 
         if (hdr)
             free(hdr);
@@ -1843,7 +1903,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *
 
     if (!pid && setsockopt((*sdRef)->sockfd, SOL_SOCKET, SO_DELEGATED_UUID, uuid, sizeof(uuid_t)) == -1)
     {
-        syslog(LOG_WARNING, "dnssdclientstub: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceCreateDelegateConnection: Could not setsockopt() for UUID, no entitlements or process(uuid) invalid errno:%d (%s) ", errno, strerror(errno));
         // Free the hdr in case we return before calling deliver_request()
         if (hdr)
             free(hdr);
@@ -1862,7 +1922,7 @@ DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *
     }
     return err;
 }
-#elif TARGET_IPHONE_SIMULATOR // This hack is for Simulator platform only
+#elif TARGET_OS_SIMULATOR // This hack is for Simulator platform only
 DNSServiceErrorType DNSSD_API DNSServiceCreateDelegateConnection(DNSServiceRef *sdRef, int32_t pid, uuid_t uuid)
 {
     (void) pid;
@@ -1892,9 +1952,11 @@ DNSServiceErrorType DNSSD_API DNSServiceRegisterRecord
     ipc_msg_hdr *hdr = NULL;
     DNSRecordRef rref = NULL;
     DNSRecord **p;
+    // Verify that only one of the following flags is set.
     int f1 = (flags & kDNSServiceFlagsShared) != 0;
     int f2 = (flags & kDNSServiceFlagsUnique) != 0;
-    if (f1 + f2 != 1) return kDNSServiceErr_BadParam;
+    int f3 = (flags & kDNSServiceFlagsKnownUnique) != 0;
+    if (f1 + f2 + f3 != 1) return kDNSServiceErr_BadParam;
 
     if ((interfaceIndex == kDNSServiceInterfaceIndexAny) && includeP2PWithIndexAny())
         flags |= kDNSServiceFlagsIncludeP2P;
@@ -2258,13 +2320,13 @@ DNSServiceErrorType DNSSD_API DNSServiceSetDispatchQueue
     }
     if (service->disp_source)
     {
-        syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch source set already");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch source set already");
         return kDNSServiceErr_BadParam;
     }
     service->disp_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, dnssd_fd, 0, queue);
     if (!service->disp_source)
     {
-        syslog(LOG_WARNING, "DNSServiceSetDispatchQueue dispatch_source_create failed");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSetDispatchQueue dispatch_source_create failed");
         return kDNSServiceErr_NoMemory;
     }
     service->disp_queue = queue;
@@ -2285,7 +2347,7 @@ static void DNSSD_API SleepKeepaliveCallback(DNSServiceRef sdRef, DNSRecordRef r
     (void)flags;    // Unused
 
     if (sdRef->kacontext != context)
-        syslog(LOG_WARNING, "SleepKeepaliveCallback context mismatch");
+        syslog(LOG_WARNING, "dnssd_clientstub SleepKeepaliveCallback context mismatch");
 
     if (ka->AppCallback)
         ((DNSServiceSleepKeepaliveReply)ka->AppCallback)(sdRef, errorCode, ka->AppContext);
@@ -2323,20 +2385,20 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
     len1 = sizeof(lss);
     if (getsockname(fd, (struct sockaddr *)&lss, &len1) < 0)
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getsockname %d\n", errno);
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getsockname %d\n", errno);
         return kDNSServiceErr_BadParam;
     }
 
     len2 = sizeof(rss);
     if (getpeername(fd, (struct sockaddr *)&rss, &len2) < 0)
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive: getpeername %d\n", errno);
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive: getpeername %d\n", errno);
         return kDNSServiceErr_BadParam;
     }
 
     if (len1 != len2)
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive local/remote info not same");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local/remote info not same");
         return kDNSServiceErr_Unknown;
     }
 
@@ -2349,12 +2411,12 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
 
         if (!inet_ntop(AF_INET, (const void *)&sr->sin_addr, target_str, sizeof (target_str)))
         {
-            syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote info failed %d", errno);
+            syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote info failed %d", errno);
             return kDNSServiceErr_Unknown;
         }
         if (!inet_ntop(AF_INET, (const void *)&sl->sin_addr, source_str, sizeof (source_str)))
         {
-            syslog(LOG_WARNING, "DNSServiceSleepKeepalive local info failed %d", errno);
+            syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local info failed %d", errno);
             return kDNSServiceErr_Unknown;
         }
         // Sum of all bytes in the local address and port should result in a unique
@@ -2372,12 +2434,12 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
 
         if (!inet_ntop(AF_INET6, (const void *)&sr6->sin6_addr, target_str, sizeof (target_str)))
         {
-            syslog(LOG_WARNING, "DNSServiceSleepKeepalive remote6 info failed %d", errno);
+            syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive remote6 info failed %d", errno);
             return kDNSServiceErr_Unknown;
         }
         if (!inet_ntop(AF_INET6, (const void *)&sl6->sin6_addr, source_str, sizeof (source_str)))
         {
-            syslog(LOG_WARNING, "DNSServiceSleepKeepalive local6 info failed %d", errno);
+            syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive local6 info failed %d", errno);
             return kDNSServiceErr_Unknown;
         }
         for (i = 0; i < sizeof(struct in6_addr); i++)
@@ -2388,7 +2450,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
 
     if (len >= (sizeof(buf) - 1))
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit local/remote info");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit local/remote info");
         return kDNSServiceErr_Unknown;
     }
     // Include the NULL byte also in the first byte. The total length of the record includes the
@@ -2399,14 +2461,14 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
     len = snprintf(name, sizeof(name), "%u", unique);
     if (len >= sizeof(name))
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit unique");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit unique");
         return kDNSServiceErr_Unknown;
     }
 
     len = snprintf(recname, sizeof(recname), "%s.%s", name, "_keepalive._dns-sd._udp.local");
     if (len >= sizeof(recname))
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive could not fit name");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive could not fit name");
         return kDNSServiceErr_Unknown;
     }
 
@@ -2418,7 +2480,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
     err = DNSServiceCreateConnection(sdRef);
     if (err)
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
         free(ka);
         return err;
     }
@@ -2428,7 +2490,7 @@ DNSServiceErrorType DNSSD_API DNSServiceSleepKeepalive
                                    kDNSServiceType_NULL,  kDNSServiceClass_IN, proxyreclen, buf,  kDNSServiceInterfaceIndexAny, SleepKeepaliveCallback, ka);
     if (err)
     {
-        syslog(LOG_WARNING, "DNSServiceSleepKeepalive cannot create connection");
+        syslog(LOG_WARNING, "dnssd_clientstub DNSServiceSleepKeepalive cannot create connection");
         free(ka);
         return err;
     }
index 0fd75824f559bf64fc230c9c3b288f55522f030e..625c88e4d28dad703da083a2b319217e67b3b04d 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2011 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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:
@@ -102,9 +101,11 @@ uint16_t get_uint16(const char **ptr, const char *end)
 
 int put_string(const char *str, char **ptr)
 {
+    size_t len;
     if (!str) str = "";
-    strcpy(*ptr, str);
-    *ptr += strlen(str) + 1;
+    len = strlen(str) + 1;
+    memcpy(*ptr, str, len);
+    *ptr += len;
     return 0;
 }
 
index dfe77a1d0d8c95835128ce255de16f0b34743417..47f5eba96ec3d3d3bed2ffddddc995e24637d962 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
@@ -15,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "mDNSDebug.h"
-
 #include <stdio.h>
 
 #if defined(WIN32) || defined(EFI32) || defined(EFI64) || defined(EFIX64)
@@ -47,37 +44,49 @@ mDNSexport int mDNS_DebugMode = mDNSfalse;
 mDNSexport void verbosedebugf_(const char *format, ...)
 {
     char buffer[512];
-    va_list ptr;
-    va_start(ptr,format);
-    buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, ptr)] = 0;
-    va_end(ptr);
+    va_list args;
+    va_start(args, format);
+    buffer[mDNS_vsnprintf(buffer, sizeof(buffer), format, args)] = 0;
+    va_end(args);
     mDNSPlatformWriteDebugMsg(buffer);
 }
 #endif
 
 // Log message with default "mDNSResponder" ident string at the start
-mDNSlocal void LogMsgWithLevelv(mDNSLogLevel_t logLevel, const char *format, va_list ptr)
+#if MDNSRESPONDER_SUPPORTS(APPLE, OS_LOG)
+mDNSlocal void LogMsgWithLevelv(os_log_t category, os_log_type_t level, const char *format, va_list args)
+{
+    char buffer[512];
+    mDNS_vsnprintf(buffer, (mDNSu32)sizeof(buffer), format, args);
+    os_log_with_type(category ? category : mDNSLogCategory_Default, level, "%{private}s", buffer);
+}
+#else
+mDNSlocal void LogMsgWithLevelv(const char *category, mDNSLogLevel_t level, const char *format, va_list args)
 {
     char buffer[512];
-    buffer[mDNS_vsnprintf((char *)buffer, sizeof(buffer), format, ptr)] = 0;
-    mDNSPlatformWriteLogMsg(ProgramName, buffer, logLevel);
+    char *dst = buffer;
+    const char *const lim = &buffer[512];
+    if (category) mDNS_snprintf_add(&dst, lim, "%s: ", category);
+    mDNS_vsnprintf(dst, (mDNSu32)(lim - dst), format, args);
+    mDNSPlatformWriteLogMsg(ProgramName, buffer, level);
 }
+#endif
 
-#define LOG_HELPER_BODY(L) \
+#define LOG_HELPER_BODY(CATEGORY, LEVEL) \
     { \
-        va_list ptr; \
-        va_start(ptr,format); \
-        LogMsgWithLevelv(L, format, ptr); \
-        va_end(ptr); \
+        va_list args; \
+        va_start(args,format); \
+        LogMsgWithLevelv(CATEGORY, LEVEL, format, args); \
+        va_end(args); \
     }
 
 // see mDNSDebug.h
 #if !MDNS_HAS_VA_ARG_MACROS
-void LogMsg_(const char *format, ...)       LOG_HELPER_BODY(MDNS_LOG_MSG)
-void LogOperation_(const char *format, ...) LOG_HELPER_BODY(MDNS_LOG_OPERATION)
-void LogSPS_(const char *format, ...)       LOG_HELPER_BODY(MDNS_LOG_SPS)
-void LogInfo_(const char *format, ...)      LOG_HELPER_BODY(MDNS_LOG_INFO)
-void LogDebug_(const char *format, ...)     LOG_HELPER_BODY(MDNS_LOG_DEBUG)
+void LogMsg_(const char *format, ...)       LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogOperation_(const char *format, ...) LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogSPS_(const char *format, ...)       LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogInfo_(const char *format, ...)      LOG_HELPER_BODY(NULL, MDNS_LOG_INFO)
+void LogDebug_(const char *format, ...)     LOG_HELPER_BODY(NULL, MDNS_LOG_DEBUG)
 #endif
 
 #if MDNS_DEBUGMSGS
@@ -85,5 +94,20 @@ void debugf_(const char *format, ...)       LOG_HELPER_BODY(MDNS_LOG_DEBUG)
 #endif
 
 // Log message with default "mDNSResponder" ident string at the start
-mDNSexport void LogMsgWithLevel(mDNSLogLevel_t logLevel, const char *format, ...)
-LOG_HELPER_BODY(logLevel)
+mDNSexport void LogMsgWithLevel(mDNSLogCategory_t category, mDNSLogLevel_t level, const char *format, ...)
+LOG_HELPER_BODY(category, level)
+
+mDNSexport void LogToFD(int fd, const char *format, ...)
+{
+    va_list args;
+    va_start(args, format);
+#if APPLE_OSX_mDNSResponder
+    char buffer[1024];
+    buffer[mDNS_vsnprintf(buffer, (mDNSu32)sizeof(buffer), format, args)] = '\0';
+    dprintf(fd, "%s\n", buffer);
+#else
+    (void)fd;
+    LogMsgWithLevelv(NULL, MDNS_LOG_INFO, format, args);
+#endif
+    va_end(args);
+}
diff --git a/mDNSShared/mDNSFeatures.h b/mDNSShared/mDNSFeatures.h
new file mode 100644 (file)
index 0000000..3f2f79e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2019 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.
+ */
+
+#ifndef __mDNSFeatures_h
+#define __mDNSFeatures_h
+
+#if MDNSRESPONDER_PLATFORM_APPLE
+#include "ApplePlatformFeatures.h"
+#endif
+
+// Common Features
+
+#undef MDNSRESPONDER_PLATFORM_COMMON
+#define MDNSRESPONDER_PLATFORM_COMMON       1
+
+// Feature: DNS Push
+// Radar:   <rdar://problem/23226275>
+// Enabled: Yes, for Apple.
+
+#if !defined(MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH)
+    #if defined(MDNSRESPONDER_PLATFORM_APPLE) && MDNSRESPONDER_PLATFORM_APPLE
+        #define MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH      1
+    #else
+        #define MDNSRESPONDER_SUPPORTS_COMMON_DNS_PUSH      0
+    #endif
+#endif
+
+#define HAS_FEATURE_CAT(A, B)       A ## B
+#define HAS_FEATURE_CHECK_0         1
+#define HAS_FEATURE_CHECK_1         1
+#define HAS_FEATURE(X)              ((X) / HAS_FEATURE_CAT(HAS_FEATURE_CHECK_, X))
+
+#define MDNSRESPONDER_SUPPORTS(PLATFORM, FEATURE) \
+    (defined(MDNSRESPONDER_PLATFORM_ ## PLATFORM) && MDNSRESPONDER_PLATFORM_ ## PLATFORM && \
+    HAS_FEATURE(MDNSRESPONDER_SUPPORTS_ ## PLATFORM ## _ ## FEATURE))
+
+#endif  // __mDNSFeatures_h
index 4d110e7aba253a065a2484f1418d5b7f7b5312b0..e6224a275ba04b1fae3f18436323324e270277c4 100644 (file)
@@ -1,6 +1,5 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2018 Apple Inc. All rights reserved.
+/*
+ * Copyright (c) 2003-2019 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.
 #include "uds_daemon.h"
 #include "dns_sd_internal.h"
 
-// Normally we append search domains only for queries with a single label that are not
-// fully qualified. This can be overridden to apply search domains for queries (that are
-// not fully qualified) with any number of labels e.g., moon, moon.cs, moon.cs.be, etc.
-mDNSBool AlwaysAppendSearchDomains = mDNSfalse;
-
-//  Control enabling ioptimistic DNS
-mDNSBool EnableAllowExpired = mDNStrue;
-
 // Apple-specific functionality, not required for other platforms
 #if APPLE_OSX_mDNSResponder
+#include <os/log.h>
 #include <sys/ucred.h>
 #ifndef PID_FILE
-#define PID_FILE ""
+#define NO_PID_FILE // We need to signal that this platform has no PID file, and not just that we are taking the default
 #endif
 #endif
 
@@ -59,34 +51,18 @@ mDNSBool EnableAllowExpired = mDNStrue;
 #include <libproc.h>        // for proc_pidinfo()
 #endif //LOCAL_PEEREPID
 
-#ifdef UNIT_TEST
-#include "unittest.h"
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
+#include "D2D.h"
 #endif
 
 #if APPLE_OSX_mDNSResponder
-#include <WebFilterDNS/WebFilterDNS.h>
 #include "BLE.h"
-
-#if !NO_WCF
-
-int WCFIsServerRunning(WCFConnection *conn) __attribute__((weak_import));
-int WCFNameResolvesToAddr(WCFConnection *conn, char* domainName, struct sockaddr* address, uid_t userid) __attribute__((weak_import));
-int WCFNameResolvesToName(WCFConnection *conn, char* fromName, char* toName, uid_t userid) __attribute__((weak_import));
-
-// Do we really need to define a macro for "if"?
-#define CHECK_WCF_FUNCTION(X) if (X)
-#endif // ! NO_WCF
-
-#else
-#define NO_WCF 1
-#endif // APPLE_OSX_mDNSResponder
+#endif
 
 // 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)
 
-#define MAX_ANONYMOUS_DATA      256
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -119,7 +95,7 @@ static mDNSu32 n_mrecords; // tracks the current active mcast records for McastL
 static mDNSu32 n_mquests;  // tracks the current active mcast questions for McastLogging
 
 
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
 mDNSu32 curr_num_regservices = 0;
 mDNSu32 max_num_regservices = 0;
 #endif
@@ -149,8 +125,6 @@ mDNSexport DNameListElem *AutoBrowseDomains;        // List created from those l
 #define PID_FILE "/var/run/mDNSResponder.pid"
 #endif
 
-mDNSlocal char *AnonDataToString(const mDNSu8 *ad, int adlen, char *adstr, int adstrlen);
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -315,7 +289,11 @@ mDNSexport void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstat
 mDNSlocal void abort_request(request_state *req)
 {
     if (req->terminate == (req_termination_fn) ~0)
-    { LogMsg("abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req, req->terminate); return; }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "[R%d] abort_request: ERROR: Attempt to abort operation %p with req->terminate %p", req->request_id, req, req->terminate);
+        return;
+    }
 
     // First stop whatever mDNSCore operation we were doing
     // If this is actually a shared connection operation, then its req->terminate function will scan
@@ -323,13 +301,25 @@ mDNSlocal void abort_request(request_state *req)
     if (req->terminate) req->terminate(req);
 
     if (!dnssd_SocketValid(req->sd))
-    { LogMsg("abort_request: ERROR: Attempt to abort operation %p with invalid fd %d",     req, req->sd);        return; }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "[R%d] abort_request: ERROR: Attempt to abort operation %p with invalid fd %d", req->request_id, req, req->sd);
+        return;
+    }
 
     // Now, if this request_state is not subordinate to some other primary, close file descriptor and discard replies
     if (!req->primary)
     {
-        if (req->errsd != req->sd) LogDebug("%3d: Removing FD and closing errsd %d", req->sd, req->errsd);
-        else LogDebug("%3d: Removing FD", req->sd);
+        if (req->errsd != req->sd)
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+                      "[R%d] Removing FD %d and closing errsd %d", req->request_id, req->sd, req->errsd);
+        }
+        else
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+                      "[R%d] Removing FD %d", req->request_id, req->sd);
+        }
         udsSupportRemoveFDFromEventLoop(req->sd, req->platform_data);       // Note: This also closes file descriptor req->sd for us
         if (req->errsd != req->sd) { dnssd_close(req->errsd); req->errsd = req->sd; }
 
@@ -342,9 +332,12 @@ mDNSlocal void abort_request(request_state *req)
     }
 
     // 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
+#if MDNS_MALLOC_DEBUGGING
+    // Don't use dnssd_InvalidSocket (-1) because that's the sentinel value MDNS_MALLOC_DEBUGGING uses
     // for detecting when the memory for an object is inadvertently freed while the object is still on some list
+#ifdef WIN32
+#error This will not work on Windows, look at IsValidSocket in mDNSShared/CommonServices.h to see why
+#endif
     req->sd = req->errsd = -2;
 #else
     req->sd = req->errsd = dnssd_InvalidSocket;
@@ -390,8 +383,8 @@ mDNSlocal reply_state *create_reply(const reply_op_t op, const size_t datalen, r
         return NULL;
     }
 
-    reply = mallocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
-    if (!reply) FatalError("ERROR: malloc");
+    reply = (reply_state *) callocL("reply_state", sizeof(reply_state) + datalen - sizeof(reply_hdr));
+    if (!reply) FatalError("ERROR: calloc");
 
     reply->next     = mDNSNULL;
     reply->totallen = (mDNSu32)datalen + sizeof(ipc_msg_hdr);
@@ -520,7 +513,7 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
 {
     DNSServiceFlags flags  = get_flags(&request->msgptr, request->msgend);
     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
-    char name[256];
+    char name[MAX_ESCAPED_DOMAIN_NAME];
     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);
@@ -531,6 +524,7 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
     AuthRecord *rr;
     mDNSInterfaceID InterfaceID;
     AuthRecType artype;
+    mDNSu8 recordType;
 
     request->flags = flags;
     request->interfaceIndex = interfaceIndex;
@@ -541,16 +535,32 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
 
     if (validate_flags &&
         !((flags & kDNSServiceFlagsShared) == kDNSServiceFlagsShared) &&
-        !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique))
+        !((flags & kDNSServiceFlagsUnique) == kDNSServiceFlagsUnique) &&
+        !((flags & kDNSServiceFlagsKnownUnique) == kDNSServiceFlagsKnownUnique))
     {
-        LogMsg("ERROR: Bad resource record flags (must be kDNSServiceFlagsShared or kDNSServiceFlagsUnique)");
+        LogMsg("ERROR: Bad resource record flags (must be one of either kDNSServiceFlagsShared, kDNSServiceFlagsUnique or kDNSServiceFlagsKnownUnique)");
         return NULL;
     }
 
-    rr = mallocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
-    if (!rr) FatalError("ERROR: malloc");
+    rr = (AuthRecord *) callocL("AuthRecord/read_rr_from_ipc_msg", sizeof(AuthRecord) - sizeof(RDataBody) + storage_size);
+    if (!rr) FatalError("ERROR: calloc");
 
     InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
+
+    // The registration is scoped to a specific interface index, but the interface is not currently on our list.
+    if ((InterfaceID == mDNSInterface_Any) && (interfaceIndex != kDNSServiceInterfaceIndexAny))
+    {
+        // On Apple platforms, an interface's mDNSInterfaceID is equal to its index. Using an interface index that isn't
+        // currently valid will cause the registration to take place as soon as it becomes valid. On other platforms,
+        // mDNSInterfaceID is actually a pointer to a platform-specific interface object, but we don't know what the pointer
+        // for the interface index will be ahead of time. For now, just return NULL to indicate an error condition since the
+        // interface index is invalid. Otherwise, the registration would be performed on all interfaces.
+#if APPLE_OSX_mDNSResponder
+        InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
+#else
+        return NULL;
+#endif
+    }
     if (InterfaceID == mDNSInterface_LocalOnly)
         artype = AuthRecordLocalOnly;
     else if (InterfaceID == mDNSInterface_P2P || InterfaceID == mDNSInterface_BLE)
@@ -565,8 +575,14 @@ mDNSlocal AuthRecord *read_rr_from_ipc_msg(request_state *request, int GetTTL, i
     else
         artype = AuthRecordAny;
 
-    mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0,
-                             (mDNSu8) ((flags & kDNSServiceFlagsShared) ? kDNSRecordTypeShared : kDNSRecordTypeUnique), artype, mDNSNULL, mDNSNULL);
+    if (flags & kDNSServiceFlagsShared)
+        recordType = (mDNSu8) kDNSRecordTypeShared;
+    else if (flags & kDNSServiceFlagsKnownUnique)
+        recordType = (mDNSu8) kDNSRecordTypeKnownUnique;
+    else
+        recordType = (mDNSu8) kDNSRecordTypeUnique;
+
+    mDNS_SetupResourceRecord(rr, mDNSNULL, InterfaceID, type, 0, recordType, artype, mDNSNULL, mDNSNULL);
 
     if (!MakeDomainNameFromDNSNameString(&rr->namestorage, name))
     {
@@ -644,29 +660,7 @@ mDNSlocal mDNSBool AuthorizedDomain(const request_state * const request, const d
 #pragma mark - external helpers
 #endif
 
-mDNSexport mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags)
-{
-#if APPLE_OSX_mDNSResponder
-
-    // Only call D2D layer routines if request applies to a D2D interface and the domain is "local".
-    if (    (((InterfaceID == mDNSInterface_Any) && (flags & (kDNSServiceFlagsIncludeP2P | kDNSServiceFlagsIncludeAWDL | kDNSServiceFlagsAutoTrigger)))
-            || mDNSPlatformInterfaceIsD2D(InterfaceID) || (InterfaceID == mDNSInterface_BLE))
-        && IsLocalDomain(domain))
-    {
-        return mDNStrue;
-    }
-    else
-        return mDNSfalse;
-
-#else
-    (void) InterfaceID;
-    (void) domain;
-    (void) flags;
-
-    return mDNSfalse;
-#endif  // APPLE_OSX_mDNSResponder
-}
-
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
 mDNSlocal void external_start_advertising_helper(service_instance *const instance)
 {
     AuthRecord *st = instance->subtypes;
@@ -686,7 +680,6 @@ mDNSlocal void external_start_advertising_helper(service_instance *const instanc
 
     external_start_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
     external_start_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
-
     external_start_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
 
     for (e = instance->srs.Extras; e; e = e->next)
@@ -705,18 +698,26 @@ mDNSlocal void external_stop_advertising_helper(service_instance *const instance
 
     LogInfo("external_stop_advertising_helper: calling external_stop_advertising_service");
 
-    for ( i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
-        external_stop_advertising_service(&st[i].resrec, instance->request->flags);
+    if (instance->request)
+    {
+        for (i = 0; i < instance->request->u.servicereg.num_subtypes; i++)
+        {
+            external_stop_advertising_service(&st[i].resrec, instance->request->flags);
+        }
 
-    external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
-    external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
-    external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
+        external_stop_advertising_service(&instance->srs.RR_PTR.resrec, instance->request->flags);
+        external_stop_advertising_service(&instance->srs.RR_SRV.resrec, instance->request->flags);
+        external_stop_advertising_service(&instance->srs.RR_TXT.resrec, instance->request->flags);
 
-    for (e = instance->srs.Extras; e; e = e->next)
-        external_stop_advertising_service(&e->r.resrec, instance->request->flags);
+        for (e = instance->srs.Extras; e; e = e->next)
+        {
+            external_stop_advertising_service(&e->r.resrec, instance->request->flags);
+        }
+    }
 
     instance->external_advertise = mDNSfalse;
 }
+#endif  // MDNSRESPONDER_SUPPORTS(APPLE, D2D)
 
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
@@ -742,7 +743,9 @@ mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
 {
     ExtraResourceRecord *e = srv->srs.Extras, *tmp;
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
     external_stop_advertising_helper(srv);
+#endif
 
     // clear pointers from parent struct
     if (srv->request)
@@ -771,11 +774,6 @@ mDNSlocal void unlink_and_free_service_instance(service_instance *srv)
         freeL("ServiceSubTypes", srv->subtypes);
         srv->subtypes = NULL;
     }
-    if (srv->srs.AnonData)
-    {
-        freeL("Anonymous", (void *)srv->srs.AnonData);
-        srv->srs.AnonData = NULL;
-    }
     freeL("service_instance", srv);
 }
 
@@ -827,10 +825,18 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
     reply_state         *rep;
     (void)m; // Unused
 
-    if (!srs)      { LogMsg("regservice_callback: srs is NULL %d",                 result); return; }
+    if (!srs)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: srs is NULL %d", result);
+        return;
+    }
 
     instance = srs->ServiceContext;
-    if (!instance) { LogMsg("regservice_callback: srs->ServiceContext is NULL %d", result); return; }
+    if (!instance)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "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 &&
@@ -840,18 +846,33 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
 
     if (mDNS_LoggingEnabled)
     {
-        const char *const fmt =
-            (result == mStatus_NoError)      ? "%s DNSServiceRegister(%##s, %u) REGISTERED"    :
-            (result == mStatus_MemFree)      ? "%s DNSServiceRegister(%##s, %u) DEREGISTERED"  :
-            (result == mStatus_NameConflict) ? "%s DNSServiceRegister(%##s, %u) NAME CONFLICT" :
-            "%s DNSServiceRegister(%##s, %u) %s %d";
-        char prefix[16] = "---:";
-        if (instance->request) mDNS_snprintf(prefix, sizeof(prefix), "%3d:", instance->request->sd);
-        LogOperation(fmt, prefix, srs->RR_SRV.resrec.name->c, mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port),
-                     SuppressError ? "suppressed error" : "CALLBACK", result);
+        const char *result_description;
+        char description[32]; // 32-byte is enough for holding "suppressed error -2147483648\0"
+        mDNSu32 request_id = instance->request ? instance->request->request_id : 0;
+        switch (result) {
+            case mStatus_NoError:
+                result_description = "REGISTERED";
+                break;
+            case mStatus_MemFree:
+                result_description = "DEREGISTERED";
+                break;
+            case mStatus_NameConflict:
+                result_description = "NAME CONFLICT";
+                break;
+            default:
+                mDNS_snprintf(description, sizeof(description), "%s %d", SuppressError ? "suppressed error" : "CALLBACK", result);
+                result_description = description;
+                break;
+        }
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegister(" PRI_DM_NAME ", %u) %s",
+                  request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c), mDNSVal16(srs->RR_SRV.resrec.rdata->u.srv.port), result_description);
     }
 
-    if (!instance->request && result != mStatus_MemFree) { LogMsg("regservice_callback: instance->request is NULL %d", result); return; }
+    if (!instance->request && result != mStatus_MemFree)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regservice_callback: instance->request is NULL %d", result);
+        return;
+    }
 
     if (result == mStatus_NoError)
     {
@@ -866,28 +887,33 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
         }
 
         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->request->sd, srs->RR_SRV.resrec.name->c);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c));
         else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
         if (callExternalHelpers(instance->request->u.servicereg.InterfaceID, &instance->domain, instance->request->flags))
         {
-            LogInfo("regservice_callback: calling external_start_advertising_helper()");
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] regservice_callback: calling external_start_advertising_helper()", instance->request->request_id);
             external_start_advertising_helper(instance);
         }
+#endif
         if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
             RecordUpdatedNiceLabel(0);   // Successfully got new name, tell user immediately
     }
     else if (result == mStatus_MemFree)
     {
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
         curr_num_regservices--;
 #endif
         if (instance->request && instance->renameonmemfree)
         {
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
             external_stop_advertising_helper(instance);
+#endif
             instance->renameonmemfree = 0;
             err = mDNS_RenameAndReregisterService(m, srs, &instance->request->u.servicereg.name);
-            if (err) LogMsg("ERROR: regservice_callback - RenameAndReregisterService returned %d", err);
+            if (err)
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] ERROR: regservice_callback - RenameAndReregisterService returned %d", instance->request->request_id, err);
             // error should never happen - safest to log and continue
         }
         else
@@ -897,7 +923,9 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
     {
         if (instance->request->u.servicereg.autorename)
         {
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
             external_stop_advertising_helper(instance);
+#endif
             if (instance->request->u.servicereg.autoname && CountPeerRegistrations(srs) == 0)
             {
                 // On conflict for an autoname service, rename and reregister *all* autoname services
@@ -915,7 +943,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
             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->request->sd, srs->RR_SRV.resrec.name->c);
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c));
                 else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
             }
             unlink_and_free_service_instance(instance);
@@ -926,7 +954,7 @@ mDNSlocal void regservice_callback(mDNS *const m, ServiceRecordSet *const srs, m
         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->request->sd, srs->RR_SRV.resrec.name->c);
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[R%u] regservice_callback: " PRI_DM_NAME " is not valid DNS-SD SRV name", instance->request->request_id, DM_NAME_PARAM(srs->RR_SRV.resrec.name->c));
             else { append_reply(instance->request, rep); instance->clientnotified = mDNStrue; }
         }
     }
@@ -938,10 +966,11 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
     if (!rr->RecordContext)     // parent struct already freed by termination callback
     {
         if (result == mStatus_NoError)
-            LogMsg("Error: regrecord_callback: successful registration of orphaned record %s", ARDisplayString(m, rr));
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Error: regrecord_callback: successful registration of orphaned record " PRI_S, ARDisplayString(m, rr));
         else
         {
-            if (result != mStatus_MemFree) LogMsg("regrecord_callback: error %d received after parent termination", result);
+            if (result != mStatus_MemFree)
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "regrecord_callback: error %d received after parent termination", result);
 
             // We come here when the record is being deregistered either from DNSServiceRemoveRecord or connection_termination.
             // If the record has been updated, we need to free the rdata. Every time we call mDNS_Update, it calls update_callback
@@ -958,11 +987,26 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
 
         if (mDNS_LoggingEnabled)
         {
-            char *fmt = (result == mStatus_NoError)      ? "%3d: DNSServiceRegisterRecord(%u %s) REGISTERED"    :
-                        (result == mStatus_MemFree)      ? "%3d: DNSServiceRegisterRecord(%u %s) DEREGISTERED"  :
-                        (result == mStatus_NameConflict) ? "%3d: DNSServiceRegisterRecord(%u %s) NAME CONFLICT" :
-                        "%3d: DNSServiceRegisterRecord(%u %s) %d";
-            LogOperation(fmt, request->sd, re->key, RRDisplayString(m, &rr->resrec), result);
+            const char *result_description;
+            char description[16]; // 16-byte is enough for holding -2147483648\0
+            switch (result) {
+                case mStatus_NoError:
+                    result_description = "REGISTERED";
+                    break;
+                case mStatus_MemFree:
+                    result_description = "DEREGISTERED";
+                    break;
+                case mStatus_NameConflict:
+                    result_description = "NAME CONFLICT";
+                    break;
+                default:
+                    mDNS_snprintf(description, sizeof(description), "%d", result);
+                    result_description = description;
+                    break;
+            }
+
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%u] DNSServiceRegisterRecord(%u " PRI_S ")" PUB_S,
+                      request->request_id, re->key, RRDisplayString(m, &rr->resrec), result_description);
         }
 
         if (result != mStatus_MemFree)
@@ -981,14 +1025,20 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
             // If this is a callback to a keepalive record, do not free it.
             if (result == mStatus_BadStateErr)
             {
-                LogInfo("regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.");
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[R%u] regrecord_callback: Callback with error code mStatus_BadStateErr - not freeing the record.", request->request_id);
             }
             else
             {
                 // 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; }
+                if (!*ptr)
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                              "[R%u] regrecord_callback - record not in list!", request->request_id);
+                    return;
+                }
                 *ptr = (*ptr)->next;
                 freeL("registered_record_entry AuthRecord regrecord_callback", re->rr);
                 freeL("registered_record_entry regrecord_callback", re);
@@ -996,14 +1046,21 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
         }
         else
         {
-            if (re->external_advertise) LogMsg("regrecord_callback: external_advertise already set!");
+            if (re->external_advertise)
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                          "[R%u] regrecord_callback: external_advertise already set!", request->request_id);
+            }
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
             if (callExternalHelpers(re->origInterfaceID, &rr->namestorage, request->flags))
             {
-                LogInfo("regrecord_callback: calling external_start_advertising_service");
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                          "[R%u] regrecord_callback: calling external_start_advertising_service", request->request_id);
                 external_start_advertising_service(&rr->resrec, request->flags);
                 re->external_advertise = mDNStrue;
             }
+#endif
         }
     }
 }
@@ -1012,11 +1069,11 @@ mDNSlocal void regrecord_callback(mDNS *const m, AuthRecord *rr, mStatus result)
 // This accounts for 2 places (connect_callback, request_callback)
 mDNSlocal void set_peer_pid(request_state *request)
 {
-    pid_t           p    = (pid_t) -1;
-    socklen_t       len  = sizeof(p);
     request->pid_name[0] = '\0';
     request->process_id  = -1;
 #ifdef LOCAL_PEEREPID
+    pid_t           p    = (pid_t) -1;
+    socklen_t       len  = sizeof(p);
     if (request->sd < 0)
         return;
     // to extract the effective pid value
@@ -1029,7 +1086,6 @@ mDNSlocal void set_peer_pid(request_state *request)
     request->process_id = p;
     debugf("set_peer_pid: Client PEEREPID is %d %s", p, request->pid_name);
 #else   // !LOCAL_PEEREPID
-    len = 0;
     LogInfo("set_peer_pid: Not Supported on this version of OS");
     if (request->sd < 0)
         return;
@@ -1042,7 +1098,9 @@ mDNSlocal void connection_termination(request_state *request)
     // and terminate any subbordinate operations sharing this file descriptor
     request_state **req = &all_requests;
 
-    LogOperation("%3d: DNSServiceCreateConnection STOP PID[%d](%s)", request->sd, request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceCreateConnection STOP PID[%d](" PUB_S ")",
+           request->request_id, request->process_id, request->pid_name);
 
     while (*req)
     {
@@ -1063,13 +1121,18 @@ mDNSlocal void connection_termination(request_state *request)
     while (request->u.reg_recs)
     {
         registered_record_entry *ptr = request->u.reg_recs;
-        LogOperation("%3d: DNSServiceRegisterRecord(%u %s) STOP PID[%d](%s)", request->sd, ptr->key, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id, request->pid_name);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") STOP PID[%d](" PUB_S ")",
+               request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &ptr->rr->resrec), request->process_id,
+               request->pid_name);
         request->u.reg_recs = request->u.reg_recs->next;
         ptr->rr->RecordContext = NULL;
         if (ptr->external_advertise)
         {
             ptr->external_advertise = mDNSfalse;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
             external_stop_advertising_service(&ptr->rr->resrec, request->flags);
+#endif
         }
         LogMcastS(ptr->rr, request, reg_stop);
         mDNS_Deregister(&mDNSStorage, ptr->rr);     // Will free ptr->rr for us
@@ -1080,7 +1143,8 @@ mDNSlocal void connection_termination(request_state *request)
 mDNSlocal void handle_cancel_request(request_state *request)
 {
     request_state **req = &all_requests;
-    LogDebug("%3d: Cancel %08X %08X", request->sd, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "[R%d] Cancel %08X %08X",
+           request->request_id, request->hdr.client_context.u32[1], request->hdr.client_context.u32[0]);
     while (*req)
     {
         if ((*req)->primary == request &&
@@ -1120,9 +1184,8 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request)
             return (mStatus_BadParamErr);
         }
         // allocate registration entry, link into list
-        re = mallocL("registered_record_entry", sizeof(registered_record_entry));
-        if (!re)
-            FatalError("ERROR: malloc");
+        re = (registered_record_entry *) callocL("registered_record_entry", sizeof(*re));
+        if (!re) FatalError("ERROR: calloc");
         re->key                   = request->hdr.reg_index;
         re->rr                    = rr;
         re->regrec_client_context = request->hdr.client_context;
@@ -1140,13 +1203,17 @@ mDNSlocal mStatus handle_regrecord_request(request_state *request)
         if (rr->resrec.rroriginalttl == 0)
             rr->resrec.rroriginalttl = DefaultTTLforRRType(rr->resrec.rrtype);
 
-        LogOperation("%3d: DNSServiceRegisterRecord(%u %s) START PID[%d](%s)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec),
-                     request->process_id, request->pid_name);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d] DNSServiceRegisterRecord(0x%X, %d, " PRI_S ") START PID[%d](" PUB_S ")",
+               request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), request->process_id,
+               request->pid_name);
 
         err = mDNS_Register(&mDNSStorage, rr);
         if (err)
         {
-            LogOperation("%3d: DNSServiceRegisterRecord(%u %s) ERROR (%d)", request->sd, re->key, RRDisplayString(&mDNSStorage, &rr->resrec), err);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                   "[R%d] DNSServiceRegisterRecord(0x%X, %d," PRI_S ") ERROR (%d)",
+                   request->request_id, request->flags, request->interfaceIndex, RRDisplayString(&mDNSStorage, &rr->resrec), err);
             freeL("registered_record_entry", re);
             freeL("registered_record_entry/AuthRecord", rr);
         }
@@ -1174,10 +1241,13 @@ mDNSlocal void regservice_termination_callback(request_state *request)
         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 PID[%d](%s)", request->sd, p->srs.RR_SRV.resrec.name->c,
-                     mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRegister(" PRI_DM_NAME ", %u) STOP PID[%d](" PUB_S ")",
+               request->request_id, DM_NAME_PARAM(p->srs.RR_SRV.resrec.name->c),
+               mDNSVal16(p->srs.RR_SRV.resrec.rdata->u.srv.port), request->process_id, request->pid_name);
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
         external_stop_advertising_helper(p);
+#endif
 
         // 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
@@ -1220,10 +1290,10 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance
     ServiceRecordSet *srs = &instance->srs;
     mStatus result;
     size_t size = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
-    ExtraResourceRecord *extra = mallocL("ExtraResourceRecord", sizeof(*extra) - sizeof(RDataBody) + size);
+    ExtraResourceRecord *extra = (ExtraResourceRecord *) 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
+    mDNSPlatformMemZero(extra, sizeof(*extra));  // OK if oversized rdata not zero'd
     extra->r.resrec.rrtype = rrtype;
     extra->r.rdatastorage.MaxRDLength = (mDNSu16) size;
     extra->r.resrec.rdlength = rdlen;
@@ -1240,12 +1310,14 @@ mDNSlocal mStatus add_record_to_service(request_state *request, service_instance
     LogMcastS(&srs->RR_PTR, request, reg_start);
 
     extra->ClientID = request->hdr.reg_index;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
     if (   instance->external_advertise
            && callExternalHelpers(request->u.servicereg.InterfaceID, &instance->domain, request->flags))
     {
         LogInfo("add_record_to_service: calling external_start_advertising_service");
         external_start_advertising_service(&extra->r.resrec, request->flags);
     }
+#endif
     return result;
 }
 
@@ -1261,22 +1333,36 @@ mDNSlocal mStatus handle_add_request(request_state *request)
     if (!ttl) ttl = DefaultTTLforRRType(rrtype);
     (void)flags; // Unused
 
-    if (!request->msgptr) { LogMsg("%3d: DNSServiceAddRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+    if (!request->msgptr)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceAddRecord(unreadable parameters)", request->request_id);
+        return(mStatus_BadParamErr);
+    }
 
     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
 
     if (request->terminate != regservice_termination_callback)
-    { LogMsg("%3d: DNSServiceAddRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceAddRecord(not a registered service ref)", request->request_id);
+        return(mStatus_BadParamErr);
+    }
 
     // For a service registered with zero port, don't allow adding records. This mostly happens due to a bug
     // in the application. See radar://9165807.
     if (mDNSIPPortIsZero(request->u.servicereg.port))
-    { LogMsg("%3d: DNSServiceAddRecord: adding record to a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
-
-    LogOperation("%3d: DNSServiceAddRecord(%X, %##s, %s, %d) PID[%d](%s)", request->sd, flags,
-                 (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL, DNSTypeName(rrtype), rdlen,
-                 request->process_id, request->pid_name);
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceAddRecord: adding record to a service registered with zero port", request->request_id);
+        return(mStatus_BadParamErr);
+    }
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceAddRecord(%X, " PRI_DM_NAME ", " PUB_S ", %d) PID[%d](" PUB_S ")",
+           request->request_id, flags,
+           DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name->c) : mDNSNULL),
+           DNSTypeName(rrtype), rdlen, request->process_id, request->pid_name);
 
     for (i = request->u.servicereg.instances; i; i = i->next)
     {
@@ -1305,13 +1391,17 @@ mDNSlocal void update_callback(mDNS *const m, AuthRecord *const rr, RData *oldrd
     if (external_advertise)
     {
         ResourceRecord ext = rr->resrec;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
         DNSServiceFlags flags = deriveD2DFlagsFromAuthRecType(rr->ARType);
+#endif
 
         if (ext.rdlength == oldrdlen && mDNSPlatformMemSame(&ext.rdata->u, &oldrd->u, oldrdlen)) goto exit;
         SetNewRData(&ext, oldrd, oldrdlen);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
         external_stop_advertising_service(&ext, flags);
         LogInfo("update_callback: calling external_start_advertising_service");
         external_start_advertising_service(&rr->resrec, flags);
+#endif
     }
 exit:
     if (oldrd != &rr->rdatastorage) freeL("RData/update_callback", oldrd);
@@ -1320,8 +1410,8 @@ exit:
 mDNSlocal mStatus update_record(AuthRecord *rr, mDNSu16 rdlen, const char *rdata, mDNSu32 ttl, const mDNSBool *const external_advertise)
 {
     mStatus result;
-    const size_t rdsize = rdlen > sizeof(RDataBody) ? rdlen : sizeof(RDataBody);
-    RData *newrd = mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
+    const size_t rdsize = (rdlen > sizeof(RDataBody)) ? rdlen : sizeof(RDataBody);
+    RData *newrd = (RData *) mallocL("RData/update_record", sizeof(RData) - sizeof(RDataBody) + rdsize);
     if (!newrd) FatalError("ERROR: malloc");
     newrd->MaxRDLength = (mDNSu16) rdsize;
     mDNSPlatformMemCopy(&newrd->u, rdata, rdlen);
@@ -1352,7 +1442,12 @@ mDNSlocal mStatus handle_update_request(request_state *request)
     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->msgptr)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceUpdateRecord(unreadable parameters)", request->request_id);
+        return(mStatus_BadParamErr);
+    }
 
     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
@@ -1366,9 +1461,11 @@ mDNSlocal mStatus handle_update_request(request_state *request)
             if (reptr->key == hdr->reg_index)
             {
                 result = update_record(reptr->rr, rdlen, rdata, ttl, &reptr->external_advertise);
-                LogOperation("%3d: DNSServiceUpdateRecord(%##s, %s) PID[%d](%s)",
-                             request->sd, reptr->rr->resrec.name->c, reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
-                             request->process_id, request->pid_name);
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                       "[R%d] DNSServiceUpdateRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
+                       request->request_id, DM_NAME_PARAM(reptr->rr->resrec.name->c),
+                       reptr->rr ? DNSTypeName(reptr->rr->resrec.rrtype) : "<NONE>",
+                       request->process_id, request->pid_name);
                 goto end;
             }
         }
@@ -1377,11 +1474,19 @@ mDNSlocal mStatus handle_update_request(request_state *request)
     }
 
     if (request->terminate != regservice_termination_callback)
-    { LogMsg("%3d: DNSServiceUpdateRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceUpdateRecord(not a registered service ref)", request->request_id);
+        return(mStatus_BadParamErr);
+    }
 
     // For a service registered with zero port, only SRV record is initialized. Don't allow any updates.
     if (mDNSIPPortIsZero(request->u.servicereg.port))
-    { LogMsg("%3d: DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->sd); return(mStatus_BadParamErr); }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceUpdateRecord: updating the record of a service registered with zero port", request->request_id);
+        return(mStatus_BadParamErr);
+    }
 
     // update the saved off TXT data for the service
     if (hdr->reg_index == TXT_RECORD_INDEX)
@@ -1440,7 +1545,9 @@ mDNSlocal mStatus remove_record(request_state *request)
     e->rr->RecordContext = NULL;
     if (e->external_advertise)
     {
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
         external_stop_advertising_service(&e->rr->resrec, request->flags);
+#endif
         e->external_advertise = mDNSfalse;
     }
     LogMcastS(e->rr, request, reg_stop);
@@ -1464,7 +1571,9 @@ mDNSlocal mStatus remove_extra(const request_state *const request, service_insta
         if (ptr->ClientID == request->hdr.reg_index) // found match
         {
             *rrtype = ptr->r.resrec.rrtype;
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
             if (serv->external_advertise) external_stop_advertising_service(&ptr->r.resrec, request->flags);
+#endif
             err = mDNS_RemoveRecordFromService(&mDNSStorage, &serv->srs, ptr, FreeExtraRR, ptr);
             break;
         }
@@ -1477,7 +1586,12 @@ 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->msgptr)
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceRemoveRecord(unreadable parameters)", request->request_id);
+        return(mStatus_BadParamErr);
+    }
 
     // If this is a shared connection, check if the operation actually applies to a subordinate request_state object
     if (request->terminate == connection_termination) request = LocateSubordinateRequest(request);
@@ -1485,14 +1599,19 @@ mDNSlocal mStatus handle_removerecord_request(request_state *request)
     if (request->terminate == connection_termination)
         err = remove_record(request);  // remove individually registered record
     else if (request->terminate != regservice_termination_callback)
-    { LogMsg("%3d: DNSServiceRemoveRecord(not a registered service ref)", request->sd); return(mStatus_BadParamErr); }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceRemoveRecord(not a registered service ref)", request->request_id);
+        return(mStatus_BadParamErr);
+    }
     else
     {
         service_instance *i;
         mDNSu16 rrtype = 0;
-        LogOperation("%3d: DNSServiceRemoveRecord(%##s, %s) PID[%d](%s)", request->sd,
-                     (request->u.servicereg.instances) ? request->u.servicereg.instances->srs.RR_SRV.resrec.name->c : NULL,
-                     rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceRemoveRecord(" PRI_DM_NAME ", " PUB_S ") PID[%d](" PUB_S ")",
+               request->request_id,
+               DM_NAME_PARAM((request->u.servicereg.instances) ? (request->u.servicereg.instances->srs.RR_SRV.resrec.name->c) : mDNSNULL),
+               rrtype ? DNSTypeName(rrtype) : "<NONE>", request->process_id, request->pid_name);
         for (i = request->u.servicereg.instances; i; i = i->next)
         {
             err = remove_extra(request, i, &rrtype);
@@ -1507,7 +1626,7 @@ mDNSlocal mStatus handle_removerecord_request(request_state *request)
 // 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, char **AnonData)
+mDNSlocal char *FindFirstSubType(char *p)
 {
     while (*p)
     {
@@ -1520,11 +1639,6 @@ mDNSlocal char *FindFirstSubType(char *p, char **AnonData)
             *p++ = 0;
             return(p);
         }
-        else if (p[0] == ':' && p[1])
-        {
-            *p++ = 0;
-            *AnonData = p;
-        }
         else
         {
             p++;
@@ -1556,10 +1670,10 @@ mDNSlocal char *FindNextSubType(char *p)
 }
 
 // Returns -1 if illegal subtype found
-mDNSexport mDNSs32 ChopSubTypes(char *regtype, char **AnonData)
+mDNSlocal mDNSs32 ChopSubTypes(char *regtype)
 {
     mDNSs32 NumSubTypes = 0;
-    char *stp = FindFirstSubType(regtype, AnonData);
+    char *stp = FindFirstSubType(regtype);
     while (stp && *stp)                 // If we found a comma...
     {
         if (*stp == ',') return(-1);
@@ -1570,65 +1684,26 @@ mDNSexport mDNSs32 ChopSubTypes(char *regtype, char **AnonData)
     return(NumSubTypes);
 }
 
-mDNSexport AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData)
+mDNSlocal AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p)
 {
     AuthRecord *st = mDNSNULL;
-    //
-    // "p" is pointing at the regtype e.g., _http._tcp followed by ":<AnonData>" indicated
-    // by AnonData being non-NULL which is in turn follwed by ",<SubTypes>" indicated by
-    // NumSubTypes being non-zero. We need to skip the initial regtype to get to the actual
-    // data that we want. When we come here, ChopSubTypes has null terminated like this e.g.,
-    //
-    // _http._tcp<NULL><AnonData><NULL><SubType1><NULL><SubType2><NULL> etc.
-    //
-    // 1. If we have Anonymous data and subtypes, skip the regtype (e.g., "_http._tcp")
-    //    to get the AnonData and then skip the AnonData to get to the SubType.
-    //
-    // 2. If we have only SubTypes, skip the regtype to get to the SubType data.
-    //
-    // 3. If we have only AnonData, skip the regtype to get to the AnonData.
-    //
-    // 4. If we don't have AnonData or NumStypes, it is a noop.
-    //
-    if (AnonData)
-    {
-        int len;
-
-        // Skip the regtype
-        while (*p) p++;
-        p++;
-
-        len = strlen(p) + 1;
-        *AnonData = mallocL("Anonymous", len);
-        if (!(*AnonData))
-        {
-           return (mDNSNULL);
-        }
-        mDNSPlatformMemCopy(*AnonData, p, len);
-    }
     if (NumSubTypes)
     {
         mDNSs32 i;
-        st = mallocL("ServiceSubTypes", NumSubTypes * sizeof(AuthRecord));
+        st = (AuthRecord *) callocL("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, AuthRecordAny, mDNSNULL, mDNSNULL);
-            // First time through we skip the regtype or AnonData. Subsequently, the
-            // previous subtype.
             while (*p) p++;
             p++;
             if (!MakeDomainNameFromDNSNameString(&st[i].namestorage, p))
             {
                 freeL("ServiceSubTypes", st);
-                if (AnonData && *AnonData)
-                    freeL("AnonymousData", *AnonData);
                 return(mDNSNULL);
             }
         }
     }
-    // If NumSubTypes is zero and AnonData is non-NULL, we still return NULL but AnonData has been
-    // initialized. The caller knows how to handle this.
     return(st);
 }
 
@@ -1657,8 +1732,8 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
         }
     }
 
-    instance = mallocL("service_instance", sizeof(*instance) + extra_size);
-    if (!instance) { my_perror("ERROR: malloc"); return mStatus_NoMemoryErr; }
+    instance = (service_instance *) callocL("service_instance", sizeof(*instance) + extra_size);
+    if (!instance) { my_perror("ERROR: calloc"); return mStatus_NoMemoryErr; }
 
     instance->next                          = mDNSNULL;
     instance->request                       = request;
@@ -1668,18 +1743,7 @@ mDNSlocal mStatus register_service_instance(request_state *request, const domain
     instance->external_advertise            = mDNSfalse;
     AssignDomainName(&instance->domain, domain);
 
-    instance->srs.AnonData = mDNSNULL;
-    if (!request->u.servicereg.AnonData)
-    {
-        instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string, mDNSNULL);
-    }
-    else
-    {
-        char *AnonData = mDNSNULL;
-        instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string, &AnonData);
-        if (AnonData)
-            instance->srs.AnonData = (const mDNSu8 *)AnonData;
-    }
+    instance->subtypes = AllocateSubTypes(request->u.servicereg.num_subtypes, request->u.servicereg.type_as_string);
 
     if (request->u.servicereg.num_subtypes && !instance->subtypes)
     {
@@ -1772,55 +1836,6 @@ mDNSlocal void udsserver_default_reg_domain_changed(const DNameListElem *const d
     }
 }
 
-// Don't allow normal and anonymous registration to coexist.
-mDNSlocal mDNSBool CheckForMixedRegistrations(domainname *regtype, domainname *domain, mDNSBool AnonData)
-{
-    request_state *request;
-
-    // We only care about local domains where the anonymous extension is
-    // implemented.
-    if (!SameDomainName(domain, (const domainname *) "\x5" "local"))
-    {
-        return mDNStrue;
-    }
-
-    for (request = all_requests; request; request = request->next)
-    {
-        service_instance *ptr;
-
-        if (request->terminate != regservice_termination_callback) continue;
-        for (ptr = request->u.servicereg.instances; ptr ; ptr = ptr->next)
-        {
-            if (!SameDomainName(&ptr->domain, (const domainname *)"\x5" "local") ||
-                !SameDomainName(&request->u.servicereg.type, regtype))
-            {
-                continue;
-            }
-
-            // If we are about to register a anonymous registraion, we dont't want to
-            // allow the regular ones and vice versa.
-            if (AnonData)
-            {
-                if (!ptr->srs.AnonData)
-                {
-                    LogMsg("CheckForMixedRegistrations: Normal registration already exists for %##s", regtype->c);
-                    return mDNSfalse;
-                }
-            }
-            else
-            {
-                // Allow multiple regular registrations
-                if (ptr->srs.AnonData)
-                {
-                    LogMsg("CheckForMixedRegistrations: Anonymous registration already exists for %##s", regtype->c);
-                    return mDNSfalse;
-                }
-            }
-        }
-    }
-    return mDNStrue;
-}
-
 // Returns true if the interfaceIndex value matches one of the pre-defined
 // special values listed in the switch statement below.
 mDNSlocal mDNSBool PreDefinedInterfaceIndex(mDNSu32 interfaceIndex)
@@ -1842,10 +1857,9 @@ 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];
+    char type_as_string[MAX_ESCAPED_DOMAIN_NAME];  // Note that this service type may include a trailing list of subtypes
     domainname d, srv;
     mStatus err;
-    char *AnonData = mDNSNULL;
     const char *msgTXTData;
 
     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
@@ -1880,10 +1894,10 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
         LogInfo("handle_regservice_request: registration pending for interface index %d", interfaceIndex);
     }
 
-    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)
+    if (get_string(&request->msgptr, request->msgend, name,           sizeof(name          )) < 0 ||
+        get_string(&request->msgptr, request->msgend, type_as_string, sizeof(type_as_string)) < 0 ||
+        get_string(&request->msgptr, request->msgend, domain,         sizeof(domain        )) < 0 ||
+        get_string(&request->msgptr, request->msgend, host,           sizeof(host          )) < 0)
     { LogMsg("ERROR: handle_regservice_request - Couldn't read name/regtype/domain"); return(mStatus_BadParamErr); }
 
     request->flags = flags;
@@ -1914,26 +1928,12 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
     }
 
     // Check for sub-types after the service type
-    request->u.servicereg.num_subtypes = ChopSubTypes(request->u.servicereg.type_as_string, &AnonData);    // Note: Modifies regtype string to remove trailing subtypes
+    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);
         goto bad_param;
     }
-    if (AnonData)
-    {
-        int AnonDataLen = strlen(AnonData);
-        if (AnonDataLen > MAX_ANONYMOUS_DATA)
-        {
-            LogMsg("ERROR: handle_regservice_request: AnonDataLen %d", AnonDataLen);
-            goto bad_param;
-        }
-        request->u.servicereg.AnonData = mDNStrue;
-    }
-    else
-    {
-        request->u.servicereg.AnonData = mDNSfalse;
-    }
 
     // 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))
@@ -1969,9 +1969,6 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
         MakeDomainNameFromDNSNameString(&d, "local.");
     }
 
-    // We don't allow the anonymous and the regular ones to coexist
-    if (!CheckForMixedRegistrations(&request->u.servicereg.type, &d, request->u.servicereg.AnonData)) { goto bad_param; }
-
     if (!ConstructServiceName(&srv, &request->u.servicereg.name, &request->u.servicereg.type, &d))
     {
         LogMsg("ERROR: handle_regservice_request - Couldn't ConstructServiceName from, “%#s” “%##s” “%##s”",
@@ -2003,21 +2000,22 @@ mDNSlocal mStatus handle_regservice_request(request_state *request)
     }
 #endif  // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
 
-    LogOperation("%3d: DNSServiceRegister(%X, %d, \"%s\", \"%s\", \"%s\", \"%s\", %u) START PID[%d](%s)",
-                 request->sd, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
-                 mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceRegister(%X, %d, \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", \"" PRI_S "\", %u) START PID[%d](" PUB_S ")",
+           request->request_id, request->flags, interfaceIndex, name, request->u.servicereg.type_as_string, domain, host,
+           mDNSVal16(request->u.servicereg.port), request->process_id, request->pid_name);
 
     // We need to unconditionally set request->terminate, because even if we didn't successfully
     // start any registrations right now, subsequent configuration changes may cause successful
     // registrations to be added, and we'll need to cancel them before freeing this memory.
     // We also need to set request->terminate first, before adding additional service instances,
-    // because the uds_validatelists uses the request->terminate function pointer to determine
+    // because the udsserver_validatelists uses the request->terminate function pointer to determine
     // what kind of request this is, and therefore what kind of list validation is required.
     request->terminate = regservice_termination_callback;
 
     err = register_service_instance(request, &d);
     
-#if TARGET_OS_EMBEDDED
+#if MDNSRESPONDER_SUPPORTS(APPLE, METRICS)
     ++curr_num_regservices;
     if (curr_num_regservices > max_num_regservices)
         max_num_regservices = curr_num_regservices;
@@ -2093,9 +2091,11 @@ mDNSlocal void FoundInstance(mDNS *const m, DNSQuestion *question, const Resourc
 
 validReply:
 
-    LogOperation("%3d: DNSServiceBrowse(%##s, %s) RESULT %s interface %d: %s",
-                 req->sd, question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
-                 mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse), RRDisplayString(m, answer));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d->Q%d] DNSServiceBrowse(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: " PRI_S,
+           req->request_id, mDNSVal16(question->TargetQID), DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype),
+           AddRecord ? "ADD" : "RMV", mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
+           RRDisplayString(m, answer));
 
     append_reply(req, rep);
 }
@@ -2137,12 +2137,11 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
         { debugf("add_domain_to_browser %##s already in list", d->c); return mStatus_AlreadyRegistered; }
     }
 
-    b = mallocL("browser_t", sizeof(*b));
+    b = (browser_t *) callocL("browser_t", sizeof(*b));
     if (!b) return mStatus_NoMemoryErr;
-    mDNSPlatformMemZero(b, sizeof(*b));
     AssignDomainName(&b->domain, d);
     SetQuestionPolicy(&b->q, info);
-    err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.AnonData, info->u.browser.interface_id, info->flags,
+    err = mDNS_StartBrowse(&mDNSStorage, &b->q, &info->u.browser.regtype, d, info->u.browser.interface_id, info->flags,
                             info->u.browser.ForceMCast, (info->flags & kDNSServiceFlagsBackgroundTrafficClass) != 0, FoundInstance, info);
     if (err)
     {
@@ -2165,6 +2164,7 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
 #endif  // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
 
         LogMcastQ(&b->q, info, q_start);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
         if (callExternalHelpers(info->u.browser.interface_id, &b->domain, info->flags))
         {
             domainname tmp;
@@ -2172,6 +2172,7 @@ mDNSlocal mStatus add_domain_to_browser(request_state *info, const domainname *d
             LogDebug("add_domain_to_browser: calling external_start_browsing_for_service()");
             external_start_browsing_for_service(info->u.browser.interface_id, &tmp, kDNSType_PTR, info->flags);
         }
+#endif
     }
     return err;
 }
@@ -2184,12 +2185,11 @@ mDNSlocal void browse_termination_callback(request_state *info)
         LogInfo("%3d: DNSServiceBrowse Cancel WAB PID[%d](%s)", info->sd, info->process_id, info->pid_name);
         uDNS_StopWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
     }
-    if (info->u.browser.AnonData)
-        freeL("Anonymous", (void *)info->u.browser.AnonData);
     while (info->u.browser.browsers)
     {
         browser_t *ptr = info->u.browser.browsers;
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
         if (callExternalHelpers(ptr->q.InterfaceID, &ptr->domain, ptr->q.flags))
         {
             domainname tmp;
@@ -2197,9 +2197,11 @@ mDNSlocal void browse_termination_callback(request_state *info)
             LogInfo("browse_termination_callback: calling external_stop_browsing_for_service()");
             external_stop_browsing_for_service(ptr->q.InterfaceID, &tmp, kDNSType_PTR, ptr->q.flags);
         }
-
-        LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\") STOP PID[%d](%s)",
-                     info->sd, info->flags, info->interfaceIndex, ptr->q.qname.c, info->process_id, info->pid_name);
+#endif
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
+               info->request_id, info->flags, info->interfaceIndex, DM_NAME_PARAM(ptr->q.qname.c),
+               info->process_id, info->pid_name);
 
         info->u.browser.browsers = ptr->next;
         mDNS_StopBrowse(&mDNSStorage, &ptr->q);  // no need to error-check result
@@ -2276,7 +2278,7 @@ mDNSlocal void RegisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, int
 {
     // allocate/register legacy and non-legacy _browse PTR record
     mStatus err;
-    ARListElem *ptr = mDNSPlatformMemAllocate(sizeof(*ptr));
+    ARListElem *ptr = (ARListElem *) mDNSPlatformMemAllocateClear(sizeof(*ptr));
 
     debugf("Incrementing %s refcount for %##s",
            (type == mDNS_DomainTypeBrowse         ) ? "browse domain   " :
@@ -2328,7 +2330,7 @@ mDNSlocal void DeregisterLocalOnlyDomainEnumPTR(mDNS *m, const domainname *d, in
 
 mDNSlocal void AddAutoBrowseDomain(const mDNSu32 uid, const domainname *const name)
 {
-    DNameListElem *new = mDNSPlatformMemAllocate(sizeof(DNameListElem));
+    DNameListElem *new = (DNameListElem *) mDNSPlatformMemAllocateClear(sizeof(*new));
     if (!new) { LogMsg("ERROR: malloc"); return; }
     AssignDomainName(&new->name, name);
     new->uid = uid;
@@ -2508,12 +2510,11 @@ mDNSlocal void AutomaticBrowseDomainChange(mDNS *const m, DNSQuestion *q, const
 
 mDNSlocal mStatus handle_browse_request(request_state *request)
 {
+    // Note that regtype may include a trailing subtype
     char regtype[MAX_ESCAPED_DOMAIN_NAME], domain[MAX_ESCAPED_DOMAIN_NAME];
     domainname typedn, d, temp;
     mDNSs32 NumSubTypes;
-    char *AnonData = mDNSNULL;
     mStatus err = mStatus_NoError;
-    int AnonDataLen;
 
     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
     mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
@@ -2536,32 +2537,20 @@ mDNSlocal mStatus handle_browse_request(request_state *request)
         LogInfo("handle_browse_request: browse pending for interface index %d", interfaceIndex);
     }
 
-    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 (get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+        get_string(&request->msgptr, request->msgend, domain,  sizeof(domain )) < 0) return(mStatus_BadParamErr);
 
     if (!request->msgptr) { LogMsg("%3d: DNSServiceBrowse(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
     request->flags = flags;
     request->interfaceIndex = interfaceIndex;
     typedn.c[0] = 0;
-    NumSubTypes = ChopSubTypes(regtype, &AnonData);    // Note: Modifies regtype string to remove trailing subtypes
+    NumSubTypes = ChopSubTypes(regtype);    // Note: Modifies regtype string to remove trailing subtypes
     if (NumSubTypes < 0 || NumSubTypes > 1)
         return(mStatus_BadParamErr);
-    AnonDataLen = 0;
-    if (AnonData)
-    {
-        AnonDataLen = strlen(AnonData);
-        if (AnonDataLen > MAX_ANONYMOUS_DATA)
-        {
-            LogMsg("handle_browse_request: AnonDataLen %d", AnonDataLen);
-            return(mStatus_BadParamErr);
-        }
-        // Account for the null byte
-        AnonDataLen += 1;
-    }
     if (NumSubTypes == 1)
     {
-        if (!AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1 + AnonDataLen))
+        if (!AppendDNSNameString(&typedn, regtype + strlen(regtype) + 1))
             return(mStatus_BadParamErr);
     }
 
@@ -2578,25 +2567,18 @@ mDNSlocal mStatus handle_browse_request(request_state *request)
     request->u.browser.default_domain = !domain[0];
     request->u.browser.browsers = NULL;
 
-    LogOperation("%3d: DNSServiceBrowse(%X, %d, \"%##s\", \"%s\") START PID[%d](%s)",
-                 request->sd, request->flags, interfaceIndex, request->u.browser.regtype.c, domain, request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceBrowse(%X, %d, \"" PRI_DM_NAME "\", \"" PRI_S "\") START PID[%d](" PUB_S ")",
+           request->request_id, request->flags, interfaceIndex, DM_NAME_PARAM(request->u.browser.regtype.c), domain,
+           request->process_id, request->pid_name);
 
     if (request->u.browser.default_domain)
     {
         // Start the domain enumeration queries to discover the WAB browse domains
-        LogInfo("%3d: DNSServiceBrowse Start WAB PID[%d](%s)", request->sd, request->process_id, request->pid_name);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d] DNSServiceBrowse Start WAB PID[%d](" PUB_S ")",
+               request->request_id, request->process_id, request->pid_name);
         uDNS_StartWABQueries(&mDNSStorage, UDNS_WAB_LBROWSE_QUERY);
     }
-    request->u.browser.AnonData = mDNSNULL;
-    if (AnonData)
-    {
-        int len = strlen(AnonData) + 1;
-        request->u.browser.AnonData = mallocL("Anonymous", len);
-        if (!request->u.browser.AnonData)
-            return mStatus_NoMemoryErr;
-        else
-            mDNSPlatformMemCopy((void *)request->u.browser.AnonData, AnonData, len);
-    }
     // We need to unconditionally set request->terminate, because even if we didn't successfully
     // start any browses right now, subsequent configuration changes may cause successful
     // browses to be added, and we'll need to cancel them before freeing this memory.
@@ -2688,19 +2670,25 @@ mDNSlocal void resolve_result_callback(mDNS *const m, DNSQuestion *question, con
     put_uint16(req->u.resolve.txt->rdlength, &data);
     put_rdata (req->u.resolve.txt->rdlength, req->u.resolve.txt->rdata->u.data, &data);
 
-    LogOperation("%3d: DNSServiceResolve(%s) RESULT   %s:%d", req->sd, fullname, target, mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d->Q%d] DNSServiceResolve(" PRI_S ") RESULT   " PRI_S ":%d",
+           req->request_id, mDNSVal16(question->TargetQID), fullname, target,
+           mDNSVal16(req->u.resolve.srv->rdata->u.srv.port));
     append_reply(req, rep);
 }
 
 mDNSlocal void resolve_termination_callback(request_state *request)
 {
-    LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") STOP PID[%d](%s)",
-                 request->sd, request->flags, request->interfaceIndex, request->u.resolve.qtxt.qname.c, request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") STOP PID[%d](" PUB_S ")",
+           request->request_id, request->flags, request->interfaceIndex, DM_NAME_PARAM(request->u.resolve.qtxt.qname.c),
+           request->process_id, request->pid_name);
     mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qtxt);
     mDNS_StopQuery(&mDNSStorage, &request->u.resolve.qsrv);
     LogMcastQ(&request->u.resolve.qsrv, request, q_stop);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
     if (request->u.resolve.external_advertise)
         external_stop_resolving_service(request->u.resolve.qsrv.InterfaceID, &request->u.resolve.qsrv.qname, request->flags);
+#endif
 }
 
 mDNSlocal mStatus handle_resolve_request(request_state *request)
@@ -2742,9 +2730,9 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
         LogInfo("handle_resolve_request: resolve pending for interface index %d", interfaceIndex);
     }
 
-    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)
+    if (get_string(&request->msgptr, request->msgend, name,    sizeof(name   )) < 0 ||
+        get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+        get_string(&request->msgptr, request->msgend, domain,  sizeof(domain )) < 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); }
@@ -2769,7 +2757,6 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
     // format questions
     request->u.resolve.qsrv.InterfaceID      = InterfaceID;
     request->u.resolve.qsrv.flags            = flags;
-    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;
@@ -2778,17 +2765,13 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
     request->u.resolve.qsrv.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
     request->u.resolve.qsrv.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
     request->u.resolve.qsrv.SuppressUnusable = mDNSfalse;
-    request->u.resolve.qsrv.SearchListIndex  = 0;
     request->u.resolve.qsrv.AppendSearchDomains = 0;
-    request->u.resolve.qsrv.RetryWithSearchDomains = mDNSfalse;
     request->u.resolve.qsrv.TimeoutQuestion  = 0;
     request->u.resolve.qsrv.WakeOnResolve    = (flags & kDNSServiceFlagsWakeOnResolve) != 0;
-    request->u.resolve.qsrv.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+    request->u.resolve.qsrv.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
     request->u.resolve.qsrv.ValidationRequired = 0;
     request->u.resolve.qsrv.ValidatingResponse = 0;
     request->u.resolve.qsrv.ProxyQuestion    = 0;
-    request->u.resolve.qsrv.qnameOrig        = mDNSNULL;
-    request->u.resolve.qsrv.AnonInfo         = mDNSNULL;
     request->u.resolve.qsrv.pid              = request->process_id;
     request->u.resolve.qsrv.euid             = request->uid;
     request->u.resolve.qsrv.QuestionCallback = resolve_result_callback;
@@ -2796,7 +2779,6 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
 
     request->u.resolve.qtxt.InterfaceID      = InterfaceID;
     request->u.resolve.qtxt.flags            = flags;
-    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;
@@ -2805,17 +2787,13 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
     request->u.resolve.qtxt.ForceMCast       = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
     request->u.resolve.qtxt.ReturnIntermed   = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
     request->u.resolve.qtxt.SuppressUnusable = mDNSfalse;
-    request->u.resolve.qtxt.SearchListIndex  = 0;
     request->u.resolve.qtxt.AppendSearchDomains = 0;
-    request->u.resolve.qtxt.RetryWithSearchDomains = mDNSfalse;
     request->u.resolve.qtxt.TimeoutQuestion  = 0;
     request->u.resolve.qtxt.WakeOnResolve    = 0;
-    request->u.resolve.qtxt.UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
+    request->u.resolve.qtxt.UseBackgroundTraffic = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
     request->u.resolve.qtxt.ValidationRequired = 0;
     request->u.resolve.qtxt.ValidatingResponse = 0;
     request->u.resolve.qtxt.ProxyQuestion    = 0;
-    request->u.resolve.qtxt.qnameOrig        = mDNSNULL;
-    request->u.resolve.qtxt.AnonInfo         = mDNSNULL;
     request->u.resolve.qtxt.pid              = request->process_id;
     request->u.resolve.qtxt.euid             = request->uid;
     request->u.resolve.qtxt.QuestionCallback = resolve_result_callback;
@@ -2830,8 +2808,10 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
 #endif
 
     // ask the questions
-    LogOperation("%3d: DNSServiceResolve(%X, %d, \"%##s\") START PID[%d](%s)", request->sd, flags, interfaceIndex,
-                 request->u.resolve.qsrv.qname.c, request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceResolve(%X, %d, \"" PRI_DM_NAME "\") START PID[%d](" PUB_S ")",
+           request->request_id, flags, interfaceIndex, DM_NAME_PARAM(request->u.resolve.qsrv.qname.c),
+           request->process_id, request->pid_name);
 
     err = mDNS_StartQuery(&mDNSStorage, &request->u.resolve.qsrv);
 
@@ -2846,12 +2826,14 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
         {
             request->terminate = resolve_termination_callback;
             LogMcastQ(&request->u.resolve.qsrv, request, q_start);
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
             if (callExternalHelpers(InterfaceID, &fqdn, flags))
             {
                 request->u.resolve.external_advertise    = mDNStrue;
                 LogInfo("handle_resolve_request: calling external_start_resolving_service()");
                 external_start_resolving_service(InterfaceID, &fqdn, flags);
             }
+#endif
         }
     }
 
@@ -2864,344 +2846,41 @@ mDNSlocal mStatus handle_resolve_request(request_state *request)
 #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.
-
-// Returns -1 to tell the caller that it should not try to reissue the query anymore
-// Returns 1 on successfully appending a search domain and the caller should reissue the new query
-// Returns 0 when there are no more search domains and the caller should reissue the query
-mDNSlocal int AppendNewSearchDomain(DNSQuestion *question)
+mDNSlocal void queryrecord_result_reply(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord, DNSServiceErrorType error, void *context)
 {
-    domainname *sd;
-    mStatus err;
-
-    // Sanity check: The caller already checks this. We use -1 to indicate that we have searched all
-    // the domains and should try the single label query directly on the wire.
-    if (question->SearchListIndex == -1)
-    {
-        LogMsg("AppendNewSearchDomain: question %##s (%s) SearchListIndex is -1", question->qname.c, DNSTypeName(question->qtype));
-        return -1;
-    }
-
-    if (!question->AppendSearchDomains)
-    {
-        LogMsg("AppendNewSearchDomain: question %##s (%s) AppendSearchDoamins is 0", question->qname.c, DNSTypeName(question->qtype));
-        return -1;
-    }
-
-    // Save the original name, before we modify them below.
-    if (!question->qnameOrig)
-    {
-        question->qnameOrig =  mallocL("AppendNewSearchDomain", sizeof(domainname));
-        if (!question->qnameOrig) { LogMsg("AppendNewSearchDomain: ERROR!!  malloc failure"); return -1; }
-        question->qnameOrig->c[0] = 0;
-        AssignDomainName(question->qnameOrig, &question->qname);
-        LogInfo("AppendSearchDomain: qnameOrig %##s", question->qnameOrig->c);
-    }
-
-    sd = uDNS_GetNextSearchDomain(question->InterfaceID, &question->SearchListIndex, !question->AppendLocalSearchDomains);
-    // We use -1 to indicate that we have searched all the domains and should try the single label
-    // query directly on the wire. uDNS_GetNextSearchDomain should never return a negative value
-    if (question->SearchListIndex == -1)
-    {
-        LogMsg("AppendNewSearchDomain: ERROR!! uDNS_GetNextSearchDomain returned -1");
-        return -1;
-    }
-
-    // Not a common case. Perhaps, we should try the next search domain if it exceeds ?
-    if (sd && (DomainNameLength(question->qnameOrig) + DomainNameLength(sd)) > MAX_DOMAIN_NAME)
-    {
-        LogMsg("AppendNewSearchDomain: ERROR!! exceeding max domain length for %##s (%s) SearchDomain %##s length %d, Question name length %d", question->qnameOrig->c, DNSTypeName(question->qtype), sd->c, DomainNameLength(question->qnameOrig), DomainNameLength(sd));
-        return -1;
-    }
-
-    // if there are no more search domains and we have already tried this question
-    // without appending search domains, then we are done.
-    if (!sd && !ApplySearchDomainsFirst(question))
-    {
-        LogInfo("AppendNewSearchDomain: No more search domains for question with name %##s (%s), not trying anymore", question->qname.c, DNSTypeName(question->qtype));
-        return -1;
-    }
-
-    // Stop the question before changing the name as negative cache entries could be pointing at this question.
-    // Even if we don't change the question in the case of returning 0, the caller is going to restart the
-    // question.
-    err = mDNS_StopQuery(&mDNSStorage, question);
-    if (err) { LogMsg("AppendNewSearchDomain: ERROR!! %##s %s mDNS_StopQuery: %d, while retrying with search domains", question->qname.c, DNSTypeName(question->qtype), (int)err); }
+    char name[MAX_ESCAPED_DOMAIN_NAME];
+    size_t len;
+    DNSServiceFlags flags = 0;
+    reply_state *rep;
+    char *data;
+    request_state *req = (request_state *)context;
 
-    AssignDomainName(&question->qname, question->qnameOrig);
-    if (sd)
-    {
-        AppendDomainName(&question->qname, sd);
-        LogInfo("AppnedNewSearchDomain: Returning question with name %##s, SearchListIndex %d", question->qname.c, question->SearchListIndex);
-        return 1;
-    }
+    ConvertDomainNameToCString(answer->name, name);
 
-    // Try the question as single label
-    LogInfo("AppnedNewSearchDomain: No more search domains for question with name %##s (%s), trying one last time", question->qname.c, DNSTypeName(question->qtype));
-    return 0;
-}
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+       "[R%u->Q%u] DNSService" PUB_S "(" PRI_DM_NAME ", " PUB_S ") RESULT " PUB_S " interface %d: (" PUB_S ")" PRI_S,
+       req->request_id, mDNSVal16(question->TargetQID), req->hdr.op == query_request ? "QueryRecord" : "GetAddrInfo",
+       DM_NAME_PARAM(question->qname.c), DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
+       mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
+       MortalityDisplayString(answer->mortality), RRDisplayString(m, answer));
 
-#if APPLE_OSX_mDNSResponder
+    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
 
-mDNSlocal mDNSBool DomainInSearchList(const domainname *domain, mDNSBool excludeLocal)
-{
-    const SearchListElem *s;
-    int qcount, scount;
+    rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
 
-    qcount = CountLabels(domain);
-    for (s=SearchList; s; s=s->next)
-    {
-        if (excludeLocal && SameDomainName(&s->domain, &localdomain))
-            continue;
-        scount = CountLabels(&s->domain);
-        if (qcount >= scount)
-        {
-            // Note: When qcount == scount, we do a complete match of the domain
-            // which is expected by the callers.
-            const domainname *d = SkipLeadingLabels(domain, (qcount - scount));
-            if (SameDomainName(&s->domain, d))
-            {
-                return mDNStrue;
-            }
-        }
-    }
-    return mDNSfalse;
-}
-
-// The caller already checks that this is a dotlocal question.
-mDNSlocal mDNSBool ShouldDeliverNegativeResponse(DNSQuestion *question)
-{
-    mDNSu16 qtype;
-
-    // If the question matches the search domain exactly or the search domain is a
-    // subdomain of the question, it is most likely a valid unicast domain and hence
-    // don't suppress negative responses.
-    //
-    // If the user has configured ".local" as a search domain, we don't want
-    // to deliver a negative response for names ending in ".local" as that would
-    // prevent bonjour discovery. Passing mDNStrue for the last argument excludes
-    // ".local" search domains.
-    if (DomainInSearchList(&question->qname, mDNStrue))
-    {
-        LogOperation("ShouldDeliverNegativeResponse: Question %##s (%s) in SearchList", question->qname.c, DNSTypeName(question->qtype));
-        return mDNStrue;
-    }
-
-    // Deliver negative response for A/AAAA if there was a positive response for AAAA/A respectively.
-    if (question->qtype != kDNSType_A && question->qtype != kDNSType_AAAA)
-    {
-        LogOperation("ShouldDeliverNegativeResponse: Question %##s (%s) not answering local question with negative unicast response",
-            question->qname.c, DNSTypeName(question->qtype));
-        return mDNSfalse;
-    }
-    qtype = (question->qtype == kDNSType_A ? kDNSType_AAAA : kDNSType_A);
-    if (!mDNS_CheckForCacheRecord(&mDNSStorage, question, qtype))
-    {
-        LogOperation("ShouldDeliverNegativeResponse:Question %##s (%s) not answering local question with negative unicast response"
-            " (can't find positive record)", question->qname.c, DNSTypeName(question->qtype));
-        return mDNSfalse;
-    }
-    LogOperation("ShouldDeliverNegativeResponse:Question %##s (%s) answering local with negative unicast response (found positive record)",
-        question->qname.c, DNSTypeName(question->qtype));
-    return mDNStrue;
-}
-
-// Workaround for networks using Microsoft Active Directory using "local" as a private internal
-// top-level domain
-mDNSlocal mStatus SendAdditionalQuery(DNSQuestion *q, request_state *request, mStatus err)
-{
-#ifndef UNICAST_DISABLED
-    extern domainname ActiveDirectoryPrimaryDomain;
-    DNSQuestion **question2;
-    #define VALID_MSAD_SRV_TRANSPORT(T) (SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_tcp") || SameDomainLabel((T)->c, (const mDNSu8 *)"\x4_udp"))
-    #define VALID_MSAD_SRV(Q) ((Q)->qtype == kDNSType_SRV && VALID_MSAD_SRV_TRANSPORT(SecondLabel(&(Q)->qname)))
-
-    question2 = mDNSNULL;
-    if (request->hdr.op == query_request)
-        question2 = &request->u.queryrecord.q2;
-    else if (request->hdr.op == addrinfo_request)
-    {
-        if (q->qtype == kDNSType_A)
-            question2 = &request->u.addrinfo.q42;
-        else if (q->qtype == kDNSType_AAAA)
-            question2 = &request->u.addrinfo.q62;
-    }
-    if (!question2)
-    {
-        LogMsg("SendAdditionalQuery: question2 NULL for %##s (%s)", q->qname.c, DNSTypeName(q->qtype));
-        return mStatus_BadParamErr;
-    }
-
-    // Sanity check: If we already sent an additonal query, we don't need to send one more.
-    //
-    // 1. When the application calls DNSServiceQueryRecord or DNSServiceGetAddrInfo with a .local name, this function
-    // is called to see whether a unicast query should be sent or not.
-    //
-    // 2. As a result of appending search domains, the question may be end up with a .local suffix even though it
-    // was not a .local name to start with. In that case, queryrecord_result_callback calls this function to
-    // send the additional query.
-    //
-    // Thus, it should not be called more than once.
-    if (*question2)
-    {
-        LogInfo("SendAdditionalQuery: question2 already sent for %##s (%s), no more q2", q->qname.c, DNSTypeName(q->qtype));
-        return err;
-    }
-
-    if (!q->ForceMCast && SameDomainLabel(LastLabel(&q->qname), (const mDNSu8 *)&localdomain))
-        if (q->qtype == kDNSType_A || q->qtype == kDNSType_AAAA || VALID_MSAD_SRV(q))
-        {
-            DNSQuestion *q2;
-            int labels = CountLabels(&q->qname);
-            q2 = mallocL("DNSQuestion", sizeof(DNSQuestion));
-            if (!q2) FatalError("ERROR: SendAdditionalQuery malloc");
-            *question2        = q2;
-            *q2               = *q;
-            q2->InterfaceID   = mDNSInterface_Unicast;
-            q2->ExpectUnique  = mDNStrue;
-            // Always set the QuestionContext to indicate that this question should be stopped
-            // before freeing. Don't rely on "q".
-            q2->QuestionContext = request;
-            // If the query starts as a single label e.g., somehost, and we have search domains with .local,
-            // queryrecord_result_callback calls this function when .local is appended to "somehost".
-            // At that time, the name in "q" is pointing at somehost.local and its qnameOrig pointing at
-            // "somehost". We need to copy that information so that when we retry with a different search
-            // domain e.g., mycompany.local, we get "somehost.mycompany.local".
-            if (q->qnameOrig)
-            {
-                (*question2)->qnameOrig =  mallocL("SendAdditionalQuery", DomainNameLength(q->qnameOrig));
-                if (!(*question2)->qnameOrig) { LogMsg("SendAdditionalQuery: ERROR!!  malloc failure"); return mStatus_NoMemoryErr; }
-                (*question2)->qnameOrig->c[0] = 0;
-                AssignDomainName((*question2)->qnameOrig, q->qnameOrig);
-                LogInfo("SendAdditionalQuery: qnameOrig %##s", (*question2)->qnameOrig->c);
-            }
-            // For names of the form "<one-or-more-labels>.bar.local." we always do a second unicast query in parallel.
-            // For names of the form "<one-label>.local." it's less clear whether we should do a unicast query.
-            // If the name being queried is exactly the same as the name in the DHCP "domain" option (e.g. the DHCP
-            // "domain" is my-small-company.local, and the user types "my-small-company.local" into their web browser)
-            // then that's a hint that it's worth doing a unicast query. Otherwise, we first check to see if the
-            // site's DNS server claims there's an SOA record for "local", and if so, that's also a hint that queries
-            // for names in the "local" domain will be safely answered privately before they hit the root name servers.
-            // Note that in the "my-small-company.local" example above there will typically be an SOA record for
-            // "my-small-company.local" but *not* for "local", which is why the "local SOA" check would fail in that case.
-            // We need to check against both ActiveDirectoryPrimaryDomain and SearchList. If it matches against either
-            // of those, we don't want do the SOA check for the local
-            if (labels == 2 && !SameDomainName(&q->qname, &ActiveDirectoryPrimaryDomain) && !DomainInSearchList(&q->qname, mDNSfalse))
-            {
-                AssignDomainName(&q2->qname, &localdomain);
-                q2->qtype          = kDNSType_SOA;
-                q2->LongLived      = mDNSfalse;
-                q2->ForceMCast     = mDNSfalse;
-                q2->ReturnIntermed = mDNStrue;
-                // Don't append search domains for the .local SOA query
-                q2->AppendSearchDomains = 0;
-                q2->AppendLocalSearchDomains = 0;
-                q2->RetryWithSearchDomains = mDNSfalse;
-                q2->SearchListIndex = 0;
-                q2->TimeoutQuestion = 0;
-                q2->AnonInfo        = mDNSNULL;
-                q2->pid             = request->process_id;
-                q2->euid            = request->uid;
-            }
-            LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast", request->sd, q2->qname.c, DNSTypeName(q2->qtype));
-            err = mDNS_StartQuery(&mDNSStorage, q2);
-            if (err) LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q2->qname.c, DNSTypeName(q2->qtype), (int)err);
-        }
-    return(err);
-#else // !UNICAST_DISABLED
-    (void) q;
-    (void) request;
-    (void) err;
-
-    return mStatus_NoError;
-#endif // !UNICAST_DISABLED
-}
-#endif // APPLE_OSX_mDNSResponder
-
-// This function tries to append a search domain if valid and possible. If so, returns true.
-mDNSlocal mDNSBool RetryQuestionWithSearchDomains(DNSQuestion *question, request_state *req, QC_result AddRecord)
-{
-    int result;
-    // RetryWithSearchDomains tells the core to call us back so that we can retry with search domains if there is no
-    // answer in the cache or /etc/hosts. In the first call back from the core, we clear RetryWithSearchDomains so
-    // that we don't get called back repeatedly. If we got an answer from the cache or /etc/hosts, we don't touch
-    // RetryWithSearchDomains which may or may not be set.
-    //
-    // If we get e.g., NXDOMAIN and the query is neither suppressed nor exhausted the domain search list and
-    // is a valid question for appending search domains, retry by appending domains
-
-    if ((AddRecord != QC_suppressed) && question->SearchListIndex != -1 && question->AppendSearchDomains)
-    {
-        question->RetryWithSearchDomains = 0;
-        result = AppendNewSearchDomain(question);
-        // As long as the result is either zero or 1, we retry the question. If we exahaust the search
-        // domains (result is zero) we try the original query (as it was before appending the search
-        // domains) as such on the wire as a last resort if we have not tried them before. For queries
-        // with more than one label, we have already tried them before appending search domains and
-        // hence don't retry again
-        if (result != -1)
-        {
-            mStatus err;
-            err = mDNS_StartQuery(&mDNSStorage, question);
-            if (!err)
-            {
-                LogOperation("%3d: RetryQuestionWithSearchDomains(%##s, %s), retrying after appending search domain", req->sd, question->qname.c, DNSTypeName(question->qtype));
-                // If the result was zero, it meant that there are no search domains and we just retried the question
-                // as a single label and we should not retry with search domains anymore.
-                if (!result) question->SearchListIndex = -1;
-                return mDNStrue;
-            }
-            else
-            {
-                LogMsg("%3d: ERROR: RetryQuestionWithSearchDomains %##s %s mDNS_StartQuery: %d, while retrying with search domains", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
-                // We have already stopped the query and could not restart. Reset the appropriate pointers
-                // so that we don't call stop again when the question terminates
-                question->QuestionContext = mDNSNULL;
-            }
-        }
-    }
-    else
-    {
-        LogDebug("%3d: RetryQuestionWithSearchDomains: Not appending search domains - SuppressQuery %d, SearchListIndex %d, AppendSearchDomains %d", req->sd, AddRecord, question->SearchListIndex, question->AppendSearchDomains);
-    }
-    return mDNSfalse;
-}
-
-mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord,
-    DNSServiceErrorType error)
-{
-    char name[MAX_ESCAPED_DOMAIN_NAME];
-    size_t len;
-    DNSServiceFlags flags = 0;
-    reply_state *rep;
-    char *data;
-
-    ConvertDomainNameToCString(answer->name, name);
-
-    LogOperation("%3d: %s(%##s, %s) RESULT %s interface %d: (%s)%s", req->sd,
-                 req->hdr.op == query_request ? "DNSServiceQueryRecord" : "DNSServiceGetAddrInfo",
-                 question->qname.c, DNSTypeName(question->qtype), AddRecord ? "ADD" : "RMV",
-                 mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNSfalse),
-                 MortalityDisplayString(answer->mortality), RRDisplayString(m, answer));
-
-    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
-
-    rep = create_reply(req->hdr.op == query_request ? query_reply_op : addrinfo_reply_op, len, req);
-
-    if (AddRecord)
-        flags |= kDNSServiceFlagsAdd;
-    if (answer->mortality == Mortality_Ghost)
-        flags |= kDNSServiceFlagsExpiredAnswer;
-    if (question->ValidationStatus != 0)
+    if (AddRecord)
+        flags |= kDNSServiceFlagsAdd;
+    if (answer->mortality == Mortality_Ghost)
+        flags |= kDNSServiceFlagsExpiredAnswer;
+    if (!question->InitialCacheMiss)
+        flags |= kDNSServiceFlagAnsweredFromCache;
+    if (question->ValidationStatus != 0)
     {
         error =   kDNSServiceErr_NoError;
         if (question->ValidationRequired && question->ValidationState == DNSSECValDone)
@@ -3252,507 +2931,63 @@ mDNSlocal void queryrecord_result_reply(mDNS *const m, request_state *req, DNSQu
     put_uint32(AddRecord ? answer->rroriginalttl : 0, &data);
 
     append_reply(req, rep);
-    // Stop the question, if we just timed out
-    if (error == kDNSServiceErr_Timeout)
-    {
-        mDNS_StopQuery(m, question);
-        // Reset the pointers so that we don't call stop on termination
-        question->QuestionContext = mDNSNULL;
-    }
-    else if ((AddRecord == QC_add) && req->hdr.op == addrinfo_request)
-    {
-        // Note: We count all answers including LocalOnly e.g., /etc/hosts. If we
-        // exclude that, v4ans/v6ans will be zero and we would wrongly think that
-        // we did not answer questions and setup the status to deliver triggers.
-        if (question->qtype == kDNSType_A)
-            req->u.addrinfo.v4ans = 1;
-        if (question->qtype == kDNSType_AAAA)
-            req->u.addrinfo.v6ans = 1;
-    }
-    else if ((AddRecord == QC_add) && req->hdr.op == query_request)
-    {
-        if (question->qtype == kDNSType_A || question->qtype == kDNSType_AAAA)
-            req->u.queryrecord.ans = 1;
-    }
-
-#if APPLE_OSX_mDNSResponder
-#if !NO_WCF
-    CHECK_WCF_FUNCTION(WCFIsServerRunning)
-    {
-        struct xucred x;
-        socklen_t xucredlen = sizeof(x);
-
-        if (WCFIsServerRunning((WCFConnection *)m->WCF) && answer->rdlength != 0)
-        {
-            if (getsockopt(req->sd, 0, LOCAL_PEERCRED, &x, &xucredlen) >= 0 &&
-                (x.cr_version == XUCRED_VERSION))
-            {
-                struct sockaddr_storage addr;
-                addr.ss_len = 0;
-                if (answer->rrtype == kDNSType_A || answer->rrtype == kDNSType_AAAA)
-                {
-                    if (answer->rrtype == kDNSType_A)
-                    {
-                        struct sockaddr_in *const sin = (struct sockaddr_in *)&addr;
-                        sin->sin_port = 0;
-                        // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
-                        // sin->sin_addr.s_addr = answer->rdata->u.ipv4.NotAnInteger;
-                        if (!putRData(mDNSNULL, (mDNSu8 *)&sin->sin_addr, (mDNSu8 *)(&sin->sin_addr + sizeof(mDNSv4Addr)), answer))
-                            LogMsg("queryrecord_result_reply: WCF AF_INET putRData failed");
-                        else
-                        {
-                            addr.ss_len = sizeof (struct sockaddr_in);
-                            addr.ss_family = AF_INET;
-                        }
-                    }
-                    else if (answer->rrtype == kDNSType_AAAA)
-                    {
-                        struct sockaddr_in6 *const sin6 = (struct sockaddr_in6 *)&addr;
-                        sin6->sin6_port = 0;
-                        // Instead of this stupid call to putRData it would be much simpler to just assign the value in the sensible way, like this:
-                        // sin6->sin6_addr.__u6_addr.__u6_addr32[0] = answer->rdata->u.ipv6.l[0];
-                        // sin6->sin6_addr.__u6_addr.__u6_addr32[1] = answer->rdata->u.ipv6.l[1];
-                        // sin6->sin6_addr.__u6_addr.__u6_addr32[2] = answer->rdata->u.ipv6.l[2];
-                        // sin6->sin6_addr.__u6_addr.__u6_addr32[3] = answer->rdata->u.ipv6.l[3];
-                        if (!putRData(mDNSNULL, (mDNSu8 *)&sin6->sin6_addr, (mDNSu8 *)(&sin6->sin6_addr + sizeof(mDNSv6Addr)), answer))
-                            LogMsg("queryrecord_result_reply: WCF AF_INET6 putRData failed");
-                        else
-                        {
-                            addr.ss_len = sizeof (struct sockaddr_in6);
-                            addr.ss_family = AF_INET6;
-                        }
-                    }
-                    if (addr.ss_len)
-                    {
-                        debugf("queryrecord_result_reply: Name %s, uid %u, addr length %d", name, x.cr_uid, addr.ss_len);
-                        CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
-                        {
-                            WCFNameResolvesToAddr(m->WCF, name, (struct sockaddr *)&addr, x.cr_uid);
-                        }
-                    }
-                }
-                else if (answer->rrtype == kDNSType_CNAME)
-                {
-                    domainname cname;
-                    char cname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-                    if (!putRData(mDNSNULL, cname.c, (mDNSu8 *)(cname.c + MAX_DOMAIN_NAME), answer))
-                        LogMsg("queryrecord_result_reply: WCF CNAME putRData failed");
-                    else
-                    {
-                        ConvertDomainNameToCString(&cname, cname_cstr);
-                        CHECK_WCF_FUNCTION((WCFConnection *)WCFNameResolvesToAddr)
-                        {
-                            WCFNameResolvesToName(m->WCF, name, cname_cstr, x.cr_uid);
-                        }
-                    }
-                }
-            }
-            else my_perror("queryrecord_result_reply: ERROR: getsockopt LOCAL_PEERCRED");
-        }
-    }
-#endif
-#endif
-}
-
-mDNSlocal void queryrecord_result_callback(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, QC_result AddRecord)
-{
-    request_state *req = question->QuestionContext;
-    DNSServiceErrorType error = kDNSServiceErr_NoError;
-    DNSQuestion *q = mDNSNULL;
-
-#if APPLE_OSX_mDNSResponder
-    {
-        // Sanity check: QuestionContext is set to NULL after we stop the question and hence we should not
-        // get any callbacks from the core after this.
-        if (!req)
-        {
-            LogMsg("queryrecord_result_callback: ERROR!! QuestionContext NULL for %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-            return;
-        }
-        if (req->hdr.op == query_request && question == req->u.queryrecord.q2)
-            q = &req->u.queryrecord.q;
-        else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q42)
-            q = &req->u.addrinfo.q4;
-        else if (req->hdr.op == addrinfo_request && question == req->u.addrinfo.q62)
-            q = &req->u.addrinfo.q6;
-
-        if (q && question->qtype != q->qtype && !SameDomainName(&question->qname, &q->qname))
-        {
-            mStatus err;
-            domainname *orig = question->qnameOrig;
-
-            LogInfo("queryrecord_result_callback: Stopping q2 local %##s", question->qname.c);
-            mDNS_StopQuery(m, question);
-            question->QuestionContext = mDNSNULL;
-
-            // We got a negative response for the SOA record indicating that .local does not exist.
-            // But we might have other search domains (that does not end in .local) that can be
-            // appended to this question. In that case, we want to retry the question. Otherwise,
-            // we don't want to try this question as unicast.
-            if (answer->RecordType == kDNSRecordTypePacketNegative && !q->AppendSearchDomains)
-            {
-                LogInfo("queryrecord_result_callback: question %##s AppendSearchDomains zero", q->qname.c);
-                return;
-            }
-
-            // If we got a non-negative answer for our "local SOA" test query, start an additional parallel unicast query
-            //
-            // Note: When we copy the original question, we copy everything including the AppendSearchDomains,
-            // RetryWithSearchDomains except for qnameOrig which can be non-NULL if the original question is
-            // e.g., somehost and then we appended e.g., ".local" and retried that question. See comment in
-            // SendAdditionalQuery as to how qnameOrig gets initialized.
-            *question              = *q;
-            question->InterfaceID  = mDNSInterface_Unicast;
-            question->ExpectUnique = mDNStrue;
-            question->qnameOrig    = orig;
-
-            LogOperation("%3d: DNSServiceQueryRecord(%##s, %s) unicast, context %p", req->sd, question->qname.c, DNSTypeName(question->qtype), question->QuestionContext);
-
-            // If the original question timed out, its QuestionContext would already be set to NULL and that's what we copied above.
-            // Hence, we need to set it explicitly here.
-            question->QuestionContext = req;
-            err = mDNS_StartQuery(m, question);
-            if (err) LogMsg("%3d: ERROR: queryrecord_result_callback %##s %s mDNS_StartQuery: %d", req->sd, question->qname.c, DNSTypeName(question->qtype), (int)err);
-
-            // If we got a positive response to local SOA, then try the .local question as unicast
-            if (answer->RecordType != kDNSRecordTypePacketNegative) return;
-
-            // Fall through and get the next search domain. The question is pointing at .local
-            // and we don't want to try that. Try the next search domain. Don't try with local
-            // search domains for the unicast question anymore.
-            //
-            // Note: we started the question above which will be stopped immediately (never sent on the wire)
-            // before we pick the next search domain below. RetryQuestionWithSearchDomains assumes that the
-            // question has already started.
-            question->AppendLocalSearchDomains = 0;
-        }
-
-        if (q && AddRecord && AddRecord != QC_dnssec && (question->InterfaceID == mDNSInterface_Unicast) && !answer->rdlength)
-        {
-            // If we get a negative response to the unicast query that we sent above, retry after appending search domains
-            // Note: We could have appended search domains below (where do it for regular unicast questions) instead of doing it here.
-            // As we ignore negative unicast answers below, we would never reach the code where the search domains are appended.
-            // To keep things simple, we handle unicast ".local" separately here.
-            LogInfo("queryrecord_result_callback: Retrying .local question %##s (%s) as unicast after appending search domains", question->qname.c, DNSTypeName(question->qtype));
-            if (RetryQuestionWithSearchDomains(question, req, AddRecord))
-                return;
-            if (question->AppendSearchDomains && !question->AppendLocalSearchDomains && IsLocalDomain(&question->qname))
-            {
-                // If "local" is the last search domain, we need to stop the question so that we don't send the "local"
-                // question on the wire as we got a negative response for the local SOA. But, we can't stop the question
-                // yet as we may have to timeout the question (done by the "core") for which we need to leave the question
-                // in the list. We leave it disabled so that it does not hit the wire.
-                LogInfo("queryrecord_result_callback: Disabling .local question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-                question->ThisQInterval = 0;
-            }
-        }
-        // If we are here it means that either "question" is not "q2" OR we got a positive response for "q2" OR we have no more search
-        // domains to append for "q2". In all cases, fall through and deliver the response
-    }
-#endif // APPLE_OSX_mDNSResponder
-
-    // If a query is being suppressed for some reason, we don't have to do any other
-    // processing.
-    //
-    // Note: We don't check for "SuppressQuery" and instead use QC_suppressed because
-    // the "core" needs to temporarily turn off SuppressQuery to answer this query.
-    if (AddRecord == QC_suppressed)
-    {
-        LogDebug("queryrecord_result_callback: Suppressed question %##s (%s)", question->qname.c, DNSTypeName(question->qtype));
-        queryrecord_result_reply(m, req, question, answer, AddRecord, kDNSServiceErr_NoSuchRecord);
-        return;
-    }
-
-    if (answer->RecordType == kDNSRecordTypePacketNegative)
-    {
-        // If this question needs to be timed out and we have reached the stop time, mark
-        // the error as timeout. It is possible that we might get a negative response from an
-        // external DNS server at the same time when this question reaches its stop time. We
-        // can't tell the difference as there is no indication in the callback. This should
-        // be okay as we will be timing out this query anyway.
-        mDNS_Lock(m);
-        if (question->TimeoutQuestion)
-        {
-            if ((m->timenow - question->StopTime) >= 0)
-            {
-                LogInfo("queryrecord_result_callback:Question %##s (%s) timing out, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
-                error = kDNSServiceErr_Timeout;
-            }
-        }
-        mDNS_Unlock(m);
-        // When we're doing parallel unicast and multicast queries for dot-local names (for supporting Microsoft
-        // Active Directory sites) we need to ignore negative unicast answers. Otherwise we'll generate negative
-        // answers for just about every single multicast name we ever look up, since the Microsoft Active Directory
-        // server is going to assert that pretty much every single multicast name doesn't exist.
-        //
-        // If we are timing out this query, we need to deliver the negative answer to the application
-        if (error != kDNSServiceErr_Timeout)
-        {
-            if (!answer->InterfaceID && IsLocalDomain(answer->name))
-            {
-                // Sanity check: "q" will be set only if "question" is the .local unicast query.
-                if (!q)
-                {
-                    LogMsg("queryrecord_result_callback: ERROR!! answering multicast question %s with unicast cache record",
-                        RRDisplayString(m, answer));
-                    return;
-                }
-#if APPLE_OSX_mDNSResponder
-                if (!ShouldDeliverNegativeResponse(question))
-                {
-                    return;
-                }
-#endif  // APPLE_OSX_mDNSResponder
-                LogInfo("queryrecord_result_callback:Question %##s (%s) answering local with negative unicast response", question->qname.c,
-                    DNSTypeName(question->qtype));
-            }
-            error = kDNSServiceErr_NoSuchRecord;
-        }
-    }
-    // If we get a negative answer, try appending search domains. Don't append search domains
-    // - if we are timing out this question
-    // - if the negative response was received as a result of a multicast query
-    // - if this is an additional query (q2), we already appended search domains above (indicated by "!q" below)
-    // - if this response is forced e.g., dnssec validation result
-    if (error != kDNSServiceErr_Timeout)
-    {
-        if (!q && !answer->InterfaceID && !answer->rdlength && AddRecord && AddRecord != QC_dnssec)
-        {
-            // If the original question did not end in .local, we did not send an SOA query
-            // to figure out whether we should send an additional unicast query or not. If we just
-            // appended .local, we need to see if we need to send an additional query. This should
-            // normally happen just once because after we append .local, we ignore all negative
-            // responses for .local above.
-            LogDebug("queryrecord_result_callback: Retrying question %##s (%s) after appending search domains", question->qname.c, DNSTypeName(question->qtype));
-            if (RetryQuestionWithSearchDomains(question, req, AddRecord))
-            {
-                // Note: We need to call SendAdditionalQuery every time after appending a search domain as .local could
-                // be anywhere in the search domain list.
-#if APPLE_OSX_mDNSResponder
-                mStatus err = mStatus_NoError;
-                err = SendAdditionalQuery(question, req, err);
-                if (err) LogMsg("queryrecord_result_callback: Sending .local SOA query failed, after appending domains");
-#endif // APPLE_OSX_mDNSResponder
-                return;
-            }
-        }
-    }
-    queryrecord_result_reply(m, req, question, answer, AddRecord, error);
 }
 
 mDNSlocal void queryrecord_termination_callback(request_state *request)
 {
-    LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) STOP PID[%d](%s)",
-        request->sd, request->flags, request->interfaceIndex, request->u.queryrecord.q.qname.c, DNSTypeName(request->u.queryrecord.q.qtype), request->process_id, request->pid_name);
-    if (request->u.queryrecord.q.QuestionContext)
-    {
-        mDNS_StopQuery(&mDNSStorage, &request->u.queryrecord.q);  // no need to error check
-        LogMcastQ(&request->u.queryrecord.q, request, q_stop);
-        request->u.queryrecord.q.QuestionContext = mDNSNULL;
-    }
-    else
-    {
-        DNSQuestion *question = &request->u.queryrecord.q;
-        LogInfo("queryrecord_termination_callback: question %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
-    }
-
-    if (request->u.queryrecord.q.qnameOrig)
-    {
-        freeL("QueryTermination", request->u.queryrecord.q.qnameOrig);
-        request->u.queryrecord.q.qnameOrig = mDNSNULL;
-    }
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%u] DNSServiceQueryRecord(%X, %d, " PRI_DM_NAME ", " PUB_S ") STOP PID[%d](" PUB_S ")",
+           request->request_id, request->flags, request->interfaceIndex,
+           DM_NAME_PARAM(QueryRecordClientRequestGetQName(&request->u.queryrecord)->c),
+           DNSTypeName(QueryRecordClientRequestGetType(&request->u.queryrecord)), request->process_id, request->pid_name);
 
-    if (callExternalHelpers(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.flags))
-    {
-        LogInfo("queryrecord_termination_callback: calling external_stop_browsing_for_service()");
-        external_stop_browsing_for_service(request->u.queryrecord.q.InterfaceID, &request->u.queryrecord.q.qname, request->u.queryrecord.q.qtype, request->u.queryrecord.q.flags);
-    }
-    if (request->u.queryrecord.q2)
-    {
-        if (request->u.queryrecord.q2->QuestionContext)
-        {
-            LogInfo("queryrecord_termination_callback: Stopping q2 %##s", request->u.queryrecord.q2->qname.c);
-            mDNS_StopQuery(&mDNSStorage, request->u.queryrecord.q2);
-            LogMcastQ(request->u.queryrecord.q2, request, q_stop);
-        }
-        else
-        {
-            DNSQuestion *question = request->u.queryrecord.q2;
-            LogInfo("queryrecord_termination_callback: q2 %##s (%s) already stopped, InterfaceID %p", question->qname.c, DNSTypeName(question->qtype), question->InterfaceID);
-        }
-        if (request->u.queryrecord.q2->qnameOrig)
-        {
-            LogInfo("queryrecord_termination_callback: freeing q2 qnameOrig %##s", request->u.queryrecord.q2->qnameOrig->c);
-            freeL("QueryTermination q2", request->u.queryrecord.q2->qnameOrig);
-            request->u.queryrecord.q2->qnameOrig = mDNSNULL;
-        }
-        freeL("queryrecord Q2", request->u.queryrecord.q2);
-        request->u.queryrecord.q2 = mDNSNULL;
-    }
-#if APPLE_OSX_mDNSResponder
-    {
-        if (request->u.queryrecord.ans)
-        {
-            DNSQuestion *v4q, *v6q;
-            // If we are receiving poisitive answers, provide the hint to the
-            // upper layer.
-            v4q = v6q = mDNSNULL;
-            if (request->u.queryrecord.q.qtype == kDNSType_A)
-                v4q = &request->u.queryrecord.q;
-            else if (request->u.queryrecord.q.qtype == kDNSType_AAAA)
-                v6q = &request->u.queryrecord.q;
-            mDNSPlatformTriggerDNSRetry(v4q, v6q);
-        }
-    }
-#endif // APPLE_OSX_mDNSResponder
+    QueryRecordClientRequestStop(&request->u.queryrecord);
 }
 
 mDNSlocal mStatus handle_queryrecord_request(request_state *request)
 {
-    DNSQuestion *const q = &request->u.queryrecord.q;
-    char name[256];
-    size_t nameLen;
-    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);
+    mStatus             err;
+    DNSServiceFlags     flags;
+    mDNSu32             interfaceIndex;
+    mDNSu16             qtype, qclass;
+    char                qname[MAX_ESCAPED_DOMAIN_NAME];
 
-    // The request is scoped to a specific interface index, but the 
-    // interface is not currently in our list.
-    if (interfaceIndex && !InterfaceID)
+    flags           = get_flags(&request->msgptr, request->msgend);
+    interfaceIndex  = get_uint32(&request->msgptr, request->msgend);
+    if (get_string(&request->msgptr, request->msgend, qname, sizeof(qname)) < 0)
     {
-        if (interfaceIndex > 1)
-            LogMsg("handle_queryrecord_request: interfaceIndex %d is currently inactive requested by client[%d][%s]",
-                    interfaceIndex, request->process_id, request->pid_name);
-        // If it's one of the specially defined inteface index values, just return an error.
-        // Also, caller should return an error immediately if lo0 (index 1) is not configured 
-        // into the current active interfaces.  See background in Radar 21967160.
-        if (PreDefinedInterfaceIndex(interfaceIndex) || interfaceIndex == 1)
-        {
-            LogInfo("handle_queryrecord_request: bad interfaceIndex %d", interfaceIndex);
-            return(mStatus_BadParamErr);
-        }
-
-        // Otherwise, use the specified interface index value and the request will
-        // be applied to that interface when it comes up.
-        InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
-        LogInfo("handle_queryrecord_request: query pending for interface index %d", interfaceIndex);
+        err = mStatus_BadParamErr;
+        goto exit;
     }
-
-    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);
+    qtype           = get_uint16(&request->msgptr, request->msgend);
+    qclass          = get_uint16(&request->msgptr, request->msgend);
 
     if (!request->msgptr)
-    { LogMsg("%3d: DNSServiceQueryRecord(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
-
-    request->flags = flags;
-    request->interfaceIndex = interfaceIndex;
-    mDNSPlatformMemZero(&request->u.queryrecord, sizeof(request->u.queryrecord));
-
-    q->InterfaceID         = InterfaceID;
-    q->flags               = flags;
-    q->Target              = zeroAddr;
-    if (!MakeDomainNameFromDNSNameString(&q->qname, name)) return(mStatus_BadParamErr);
-#if 0
-    if (!AuthorizedDomain(request, &q->qname, AutoBrowseDomains)) return (mStatus_NoError);
-#endif
-    q->qtype               = rrtype;
-    q->qclass              = rrclass;
-    q->LongLived           = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
-    q->ExpectUnique        = mDNSfalse;
-    q->ForceMCast          = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
-    q->ReturnIntermed      = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
-    q->SuppressUnusable    = (flags & kDNSServiceFlagsSuppressUnusable   ) != 0;
-    q->TimeoutQuestion     = (flags & kDNSServiceFlagsTimeout            ) != 0;
-    q->allowExpired        = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None;
-    q->WakeOnResolve       = 0;
-    q->UseBackgroundTrafficClass = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
-    if ((flags & kDNSServiceFlagsValidate) != 0)
-        q->ValidationRequired = DNSSEC_VALIDATION_SECURE;
-    else if ((flags & kDNSServiceFlagsValidateOptional) != 0)
-        q->ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
-    q->ValidatingResponse = 0;
-    q->ProxyQuestion      = 0;
-    q->AnonInfo = mDNSNULL;
-    q->QuestionCallback   = queryrecord_result_callback;
-    q->QuestionContext    = request;
-    q->SearchListIndex    = 0;
-    q->StopTime           = 0;
-
-    q->DNSSECAuthInfo = mDNSNULL;
-    q->DAIFreeCallback = mDNSNULL;
-
-    //Turn off dnssec validation for local domains and Question Types: RRSIG/ANY(ANY Type is not supported yet)
-    if ((IsLocalDomain(&q->qname)) || (q->qtype == kDNSServiceType_RRSIG) || (q->qtype == kDNSServiceType_ANY))
-        q->ValidationRequired = 0;
-
-    // Don't append search domains for fully qualified domain names including queries
-    // such as e.g., "abc." that has only one label. We convert all names to FQDNs as internally
-    // we only deal with FQDNs. Hence, we cannot look at qname to figure out whether we should
-    // append search domains or not.  So, we record that information in AppendSearchDomains.
-    //
-    // We append search domains only for queries that are a single label. If overriden using command line 
-    // argument "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified.
-    // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set.
-
-    nameLen = strlen(name);
-    if ((!(q->ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(q->ValidationRequired == DNSSEC_VALIDATION_INSECURE))
-        && (rrtype == kDNSType_A || rrtype == kDNSType_AAAA) && ((nameLen == 0) || (name[nameLen - 1] != '.')) &&
-        (AlwaysAppendSearchDomains || CountLabels(&q->qname) == 1))
-    {
-        q->AppendSearchDomains = 1;
-        q->AppendLocalSearchDomains = 1;
-    }
-    else
     {
-        q->AppendSearchDomains = 0;
-        q->AppendLocalSearchDomains = 0;
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceQueryRecord(unreadable parameters)", request->request_id);
+        err = mStatus_BadParamErr;
+        goto exit;
     }
 
-    // For single label queries that are not fully qualified, look at /etc/hosts, cache and try
-    // search domains before trying them on the wire as a single label query. RetryWithSearchDomains
-    // tell the core to call back into the UDS layer if there is no valid response in /etc/hosts or
-    // the cache
-    q->RetryWithSearchDomains = ApplySearchDomainsFirst(q) ? 1 : 0;
-    q->qnameOrig        = mDNSNULL;
-    SetQuestionPolicy(q, request);
+    request->flags          = flags;
+    request->interfaceIndex = interfaceIndex;
 
-#if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
-    // Determine if this request should be promoted to use BLE triggered discovery.
-    if (shouldUseBLE(InterfaceID, rrtype, (domainname *)SkipLeadingLabels(&q->qname, 1), &q->qname))
-    {
-        q->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
-        request->flags |= (kDNSServiceFlagsAutoTrigger | kDNSServiceFlagsIncludeAWDL);
-        LogInfo("handle_queryrecord_request: request promoted to use kDNSServiceFlagsAutoTrigger");
-    }
-#endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceQueryRecord(%X, %d, " PRI_S ", " PUB_S ") START PID[%d](" PUB_S ")",
+           request->request_id, request->flags, request->interfaceIndex, qname, DNSTypeName(qtype), request->process_id,
+           request->pid_name);
 
-    LogOperation("%3d: DNSServiceQueryRecord(%X, %d, %##s, %s) START PID[%d](%s)",
-        request->sd, request->flags, interfaceIndex, q->qname.c, DNSTypeName(q->qtype), request->process_id, request->pid_name);
-    err = mDNS_StartQuery(&mDNSStorage, q);
+    mDNSPlatformMemZero(&request->u.queryrecord, (mDNSu32)sizeof(request->u.queryrecord));
 
-    if (err)
-    {
-        LogMsg("%3d: ERROR: DNSServiceQueryRecord %##s %s mDNS_StartQuery: %d", request->sd, q->qname.c, DNSTypeName(q->qtype), (int)err);
-    }
-    else
-    {
-        request->terminate = queryrecord_termination_callback;
-        LogMcastQ(q, request, q_start);
-        if (callExternalHelpers(q->InterfaceID, &q->qname, q->flags))
-        {
-            LogDebug("handle_queryrecord_request: calling external_start_browsing_for_service()");
-            external_start_browsing_for_service(q->InterfaceID, &q->qname, q->qtype, q->flags);
-        }
-    }
+    err = QueryRecordClientRequestStart(&request->u.queryrecord, request->request_id, qname, interfaceIndex, flags, qtype,
+        qclass, request->validUUID ? 0 : request->process_id, request->validUUID ? request->uuid : mDNSNULL, request->uid,
+        queryrecord_result_reply, request);
+    if (err) goto exit;
 
-#if APPLE_OSX_mDNSResponder
-    err = SendAdditionalQuery(q, request, err);
-#endif // APPLE_OSX_mDNSResponder
+    request->terminate = queryrecord_termination_callback;
 
+exit:
     return(err);
 }
 
@@ -3833,7 +3068,10 @@ mDNSlocal void enum_result_callback(mDNS *const m,
     reply = format_enumeration_reply(request, domain, flags, kDNSServiceInterfaceIndexAny, kDNSServiceErr_NoError);
     if (!reply) { LogMsg("ERROR: enum_result_callback, format_enumeration_reply"); return; }
 
-    LogOperation("%3d: DNSServiceEnumerateDomains(%#2s) RESULT %s: %s", request->sd, question->qname.c, AddRecord ? "ADD" : "RMV", domain);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d->Q%d] DNSServiceEnumerateDomains(%2.*s) RESULT " PUB_S ": " PRI_S,
+           request->request_id, mDNSVal16(question->TargetQID), question->qname.c[0], &question->qname.c[1],
+           AddRecord ? "ADD" : "RMV", domain);
 
     append_reply(request, reply);
 }
@@ -3941,9 +3179,9 @@ mDNSlocal mStatus handle_release_request(request_state *request)
     // extract the data from the message
     DNSServiceFlags flags = get_flags(&request->msgptr, request->msgend);
 
-    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)
+    if (get_string(&request->msgptr, request->msgend, name,    sizeof(name   )) < 0 ||
+        get_string(&request->msgptr, request->msgend, regtype, sizeof(regtype)) < 0 ||
+        get_string(&request->msgptr, request->msgend, domain,  sizeof(domain )) < 0)
     {
         LogMsg("ERROR: handle_release_request - Couldn't read name/regtype/domain");
         return(mStatus_BadParamErr);
@@ -3961,10 +3199,13 @@ mDNSlocal mStatus handle_release_request(request_state *request)
         return(mStatus_BadParamErr);
     }
 
-    LogOperation("%3d: PeerConnectionRelease(%X %##s) START PID[%d](%s)",
-                 request->sd, flags, instance.c, request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] PeerConnectionRelease(%X " PRI_DM_NAME ") START PID[%d](" PUB_S ")",
+           request->request_id, flags, DM_NAME_PARAM(instance.c), request->process_id, request->pid_name);
 
+#if MDNSRESPONDER_SUPPORTS(APPLE, D2D)
     external_connection_release(&instance);
+#endif
     return(err);
 }
 
@@ -3984,7 +3225,7 @@ mDNSlocal mStatus handle_setdomain_request(request_state *request)
     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 ||
+    if (get_string(&request->msgptr, request->msgend, domainstr, sizeof(domainstr)) < 0 ||
         !MakeDomainNameFromDNSNameString(&domain, domainstr))
     { LogMsg("%3d: DNSServiceSetDefaultDomainForUser(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
 
@@ -4005,7 +3246,8 @@ mDNSlocal void handle_getproperty_request(request_state *request)
     char prop[256];
     if (get_string(&request->msgptr, request->msgend, prop, sizeof(prop)) >= 0)
     {
-        LogOperation("%3d: DNSServiceGetProperty(%s)", request->sd, prop);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%d] DNSServiceGetProperty(" PUB_S ")", request->request_id, prop);
         if (!strcmp(prop, kDNSServiceProperty_DaemonVersion))
         {
             DaemonVersionReply x = { 0, dnssd_htonl(4), dnssd_htonl(_DNS_SD_H) };
@@ -4027,8 +3269,9 @@ mDNSlocal void handle_connection_delegate_request(request_state *request)
     mDNSs32 pid;
     socklen_t len;
 
-    LogOperation("%3d: DNSServiceCreateDelegateConnection START PID[%d](%s)",
-                 request->sd, request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PUB_S  ")",
+           request->request_id, request->process_id, request->pid_name);
     request->terminate = connection_termination;
 
     len = 0;
@@ -4075,63 +3318,6 @@ typedef packedstruct
     mDNSs32 pid;
 } PIDInfo;
 
-mDNSlocal void handle_getpid_request(request_state *request)
-{
-    const request_state *req;
-    mDNSs32 pid = -1;
-    mDNSu16 srcport = get_uint16(&request->msgptr, request->msgend);
-    const DNSQuestion *q = NULL;
-    PIDInfo pi;
-
-    LogMsg("%3d: DNSServiceGetPID START", request->sd);
-
-    for (req = all_requests; req; req=req->next)
-    {
-        if (req->hdr.op == query_request)
-            q = &req->u.queryrecord.q;
-        else if (req->hdr.op == addrinfo_request)
-            q = &req->u.addrinfo.q4;
-        else if (req->hdr.op == addrinfo_request)
-            q = &req->u.addrinfo.q6;
-
-        if (q && q->LocalSocket != NULL)
-        {
-            mDNSu16 port = mDNSPlatformGetUDPPort(q->LocalSocket);
-            if (port == srcport)
-            {
-                pid = req->process_id;
-                LogMsg("DNSServiceGetPID: srcport %d, pid %d [%s] question %##s", htons(srcport), pid, req->pid_name, q->qname.c);
-                break;
-            }
-        }
-    }
-    // If we cannot find in the client requests, look to see if this was
-    // started by mDNSResponder.
-    if (pid == -1)
-    {
-        for (q = mDNSStorage.Questions; q; q = q->next)
-        {
-            if (q && q->LocalSocket != NULL)
-            {
-                mDNSu16 port = mDNSPlatformGetUDPPort(q->LocalSocket);
-                if (port == srcport)
-                {
-#if APPLE_OSX_mDNSResponder
-                    pid = getpid();
-#endif // APPLE_OSX_mDNSResponder
-                    LogMsg("DNSServiceGetPID: srcport %d, pid %d [%s], question %##s", htons(srcport), pid, "_mDNSResponder", q->qname.c);
-                    break;
-                }
-            }
-        }
-    }
-
-    pi.err = 0;
-    pi.pid = pid;
-    send_all(request->sd, (const char *)&pi, sizeof(PIDInfo));
-    LogMsg("%3d: DNSServiceGetPID STOP", request->sd);
-}
-
 // ***************************************************************************
 #if COMPILER_LIKES_PRAGMA_MARK
 #pragma mark -
@@ -4142,10 +3328,11 @@ mDNSlocal void handle_getpid_request(request_state *request)
 
 mDNSlocal void port_mapping_termination_callback(request_state *request)
 {
-    LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](%s)", 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->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO, "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) STOP PID[%d](" PUB_S ")",
+           request->request_id, DNSServiceProtocol(request->u.pm.NATinfo.Protocol),
+           mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
+           request->process_id, request->pid_name);
+
     mDNS_StopNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
 }
 
@@ -4185,10 +3372,12 @@ mDNSlocal void port_mapping_create_request_callback(mDNS *m, NATTraversalInfo *n
     *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);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) RESULT " PRI_IPv4_ADDR ":%u TTL %u",
+           request->request_id, 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);
 }
@@ -4215,7 +3404,11 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
     }
 
     if (!request->msgptr)
-    { LogMsg("%3d: DNSServiceNATPortMappingCreate(unreadable parameters)", request->sd); return(mStatus_BadParamErr); }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+               "[R%d] DNSServiceNATPortMappingCreate(unreadable parameters)", request->request_id);
+        return(mStatus_BadParamErr);
+    }
 
     if (protocol == 0)  // If protocol == 0 (i.e. just request public address) then IntPort, ExtPort, ttl must be zero too
     {
@@ -4236,9 +3429,10 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
     request->u.pm.NATinfo.clientCallback = port_mapping_create_request_callback;
     request->u.pm.NATinfo.clientContext  = request;
 
-    LogOperation("%3d: DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](%s)", request->sd,
-                 protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt), request->u.pm.NATinfo.NATLease,
-                 request->process_id, request->pid_name);
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%d] DNSServiceNATPortMappingCreate(%X, %u, %u, %d) START PID[%d](" PUB_S ")",
+           request->request_id, protocol, mDNSVal16(request->u.pm.NATinfo.IntPort), mDNSVal16(request->u.pm.ReqExt),
+           request->u.pm.NATinfo.NATLease, request->process_id, request->pid_name);
     err = mDNS_StartNATOperation(&mDNSStorage, &request->u.pm.NATinfo);
     if (err) LogMsg("ERROR: mDNS_StartNATOperation: %d", (int)err);
     else request->terminate = port_mapping_termination_callback;
@@ -4254,319 +3448,55 @@ mDNSlocal mStatus handle_port_mapping_request(request_state *request)
 
 mDNSlocal void addrinfo_termination_callback(request_state *request)
 {
-    LogOperation("%3d: DNSServiceGetAddrInfo(%##s) STOP PID[%d](%s)", request->sd, request->u.addrinfo.q4.qname.c,
-                  request->process_id, request->pid_name);
-
-    if (request->u.addrinfo.q4.QuestionContext)
-    {
-        mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q4);
-        LogMcastQ(&request->u.addrinfo.q4, request, q_stop);
-        request->u.addrinfo.q4.QuestionContext = mDNSNULL;
-
-        if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, request->flags))
-        {
-            LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for A record");
-            external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q4.qname, kDNSServiceType_A, request->flags);
-        }
-    }
-    if (request->u.addrinfo.q4.qnameOrig)
-    {
-        freeL("QueryTermination", request->u.addrinfo.q4.qnameOrig);
-        request->u.addrinfo.q4.qnameOrig = mDNSNULL;
-    }
-    if (request->u.addrinfo.q42)
-    {
-        if (request->u.addrinfo.q42->QuestionContext)
-        {
-            LogInfo("addrinfo_termination_callback: Stopping q42 %##s", request->u.addrinfo.q42->qname.c);
-            mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q42);
-            LogMcastQ(request->u.addrinfo.q42, request, q_stop);
-        }
-        if (request->u.addrinfo.q42->qnameOrig)
-        {
-            LogInfo("addrinfo_termination_callback: freeing q42 qnameOrig %##s", request->u.addrinfo.q42->qnameOrig->c);
-            freeL("QueryTermination q42", request->u.addrinfo.q42->qnameOrig);
-            request->u.addrinfo.q42->qnameOrig = mDNSNULL;
-        }
-        freeL("addrinfo Q42", request->u.addrinfo.q42);
-        request->u.addrinfo.q42 = mDNSNULL;
-    }
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%u] DNSServiceGetAddrInfo(" PRI_DM_NAME ") STOP PID[%d](" PUB_S ")",
+           request->request_id, DM_NAME_PARAM(GetAddrInfoClientRequestGetQName(&request->u.addrinfo)->c),
+           request->process_id, request->pid_name);
 
-    if (request->u.addrinfo.q6.QuestionContext)
-    {
-        mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
-        LogMcastQ(&request->u.addrinfo.q6, request, q_stop);
-        request->u.addrinfo.q6.QuestionContext = mDNSNULL;
-
-        if (callExternalHelpers(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, request->flags))
-        {
-            LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record");
-            external_stop_browsing_for_service(request->u.addrinfo.interface_id, &request->u.addrinfo.q6.qname, kDNSServiceType_AAAA, request->flags);
-        }
-    }
-    if (request->u.addrinfo.q6.qnameOrig)
-    {
-        freeL("QueryTermination", request->u.addrinfo.q6.qnameOrig);
-        request->u.addrinfo.q6.qnameOrig = mDNSNULL;
-    }
-    if (request->u.addrinfo.q62)
-    {
-        if (request->u.addrinfo.q62->QuestionContext)
-        {
-            LogInfo("addrinfo_termination_callback: Stopping q62 %##s", request->u.addrinfo.q62->qname.c);
-            mDNS_StopQuery(&mDNSStorage, request->u.addrinfo.q62);
-            LogMcastQ(request->u.addrinfo.q62, request, q_stop);
-        }
-        if (request->u.addrinfo.q62->qnameOrig)
-        {
-            LogInfo("addrinfo_termination_callback: freeing q62 qnameOrig %##s", request->u.addrinfo.q62->qnameOrig->c);
-            freeL("QueryTermination q62", request->u.addrinfo.q62->qnameOrig);
-            request->u.addrinfo.q62->qnameOrig = mDNSNULL;
-        }
-        freeL("addrinfo Q62", request->u.addrinfo.q62);
-        request->u.addrinfo.q62 = mDNSNULL;
-    }
-#if APPLE_OSX_mDNSResponder
-    {
-        DNSQuestion *v4q, *v6q;
-        v4q = v6q = mDNSNULL;
-        if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4)
-        {
-            // If we are not delivering answers, we may be timing out prematurely.
-            // Note down the current state so that we know to retry when we see a
-            // valid response again.
-            if (request->u.addrinfo.q4.TimeoutQuestion && !request->u.addrinfo.v4ans)
-            {
-                mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q4);
-            }
-            // If we have a v4 answer and if we timed out prematurely before, provide
-            // a trigger to the upper layer so that it can retry questions if needed.
-            if (request->u.addrinfo.v4ans)
-                v4q = &request->u.addrinfo.q4;
-        }
-        if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
-        {
-            if (request->u.addrinfo.q6.TimeoutQuestion && !request->u.addrinfo.v6ans)
-            {
-                mDNSPlatformUpdateDNSStatus(&request->u.addrinfo.q6);
-            }
-            if (request->u.addrinfo.v6ans)
-                v6q = &request->u.addrinfo.q6;
-        }
-        mDNSPlatformTriggerDNSRetry(v4q, v6q);
-    }
-#endif // APPLE_OSX_mDNSResponder
+    GetAddrInfoClientRequestStop(&request->u.addrinfo);
 }
 
 mDNSlocal mStatus handle_addrinfo_request(request_state *request)
 {
-    char hostname[256];
-    size_t hostnameLen;
-    domainname d;
-    mStatus err = 0;
-    mDNSs32 serviceIndex   = -1;  // default unscoped value for ServiceID is -1
-    mDNSInterfaceID InterfaceID;
-
-    DNSServiceFlags flags  = get_flags(&request->msgptr, request->msgend);
-
-    mDNSu32 interfaceIndex = get_uint32(&request->msgptr, request->msgend);
+    mStatus             err;
+    DNSServiceFlags     flags;
+    mDNSu32             interfaceIndex;
+    mDNSu32             protocols;
+    char                hostname[MAX_ESCAPED_DOMAIN_NAME];
 
-    if (flags & kDNSServiceFlagsServiceIndex)
+    flags           = get_flags(&request->msgptr, request->msgend);
+    interfaceIndex  = get_uint32(&request->msgptr, request->msgend);
+    protocols       = get_uint32(&request->msgptr, request->msgend);
+    if (get_string(&request->msgptr, request->msgend, hostname, sizeof(hostname)) < 0)
     {
-        // NOTE: kDNSServiceFlagsServiceIndex flag can only be set for DNSServiceGetAddrInfo()
-        LogInfo("DNSServiceGetAddrInfo: kDNSServiceFlagsServiceIndex is SET by the client");
-        // if kDNSServiceFlagsServiceIndex is SET,
-        // interpret the interfaceID as the serviceId and set the interfaceID to 0.
-        serviceIndex   = interfaceIndex;
-        interfaceIndex = 0;
+        err = mStatus_BadParamErr;
+        goto exit;
     }
-
-    mDNSPlatformMemZero(&request->u.addrinfo, sizeof(request->u.addrinfo));
-
-    InterfaceID = mDNSPlatformInterfaceIDfromInterfaceIndex(&mDNSStorage, interfaceIndex);
-
-    // The request is scoped to a specific interface index, but the 
-    // interface is not currently in our list.
-    if (interfaceIndex && !InterfaceID)
+    if (!request->msgptr)
     {
-        if (interfaceIndex > 1)
-            LogMsg("handle_addrinfo_request: interfaceIndex %d is currently inactive requested by client[%d][%s]",
-                    interfaceIndex, request->process_id, request->pid_name);
-        // If it's one of the specially defined inteface index values, just return an error.
-        if (PreDefinedInterfaceIndex(interfaceIndex))
-        {
-            LogInfo("handle_addrinfo_request: bad interfaceIndex %d", interfaceIndex);
-            return(mStatus_BadParamErr);
-        }
-
-        // Otherwise, use the specified interface index value and the request will
-        // be applied to that interface when it comes up.
-        InterfaceID = (mDNSInterfaceID)(uintptr_t)interfaceIndex;
-        LogInfo("handle_addrinfo_request: query pending for interface index %d", interfaceIndex);
+        LogMsg("%3d: DNSServiceGetAddrInfo(unreadable parameters)", request->sd);
+        err = mStatus_BadParamErr;
+        goto exit;
     }
 
-    request->flags                   = flags;
-    request->interfaceIndex          = interfaceIndex;
-    request->u.addrinfo.interface_id = InterfaceID;
-    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); }
-
-#if 0
-    if (!AuthorizedDomain(request, &d, AutoBrowseDomains)) return (mStatus_NoError);
-#endif
-
-    if (!request->u.addrinfo.protocol)
-    {
-        flags |= kDNSServiceFlagsSuppressUnusable;
-        request->u.addrinfo.protocol = (kDNSServiceProtocol_IPv4 | kDNSServiceProtocol_IPv6);
-    }
-
-    request->u.addrinfo.q4.InterfaceID         = request->u.addrinfo.q6.InterfaceID         = request->u.addrinfo.interface_id;
-    request->u.addrinfo.q4.ServiceID           = request->u.addrinfo.q6.ServiceID           = serviceIndex;
-    request->u.addrinfo.q4.flags               = request->u.addrinfo.q6.flags               = flags;
-    request->u.addrinfo.q4.Target              = request->u.addrinfo.q6.Target              = zeroAddr;
-    request->u.addrinfo.q4.qname               = request->u.addrinfo.q6.qname               = d;
-    request->u.addrinfo.q4.qclass              = request->u.addrinfo.q6.qclass              = kDNSServiceClass_IN;
-    request->u.addrinfo.q4.LongLived           = request->u.addrinfo.q6.LongLived           = (flags & kDNSServiceFlagsLongLivedQuery     ) != 0;
-    request->u.addrinfo.q4.ExpectUnique        = request->u.addrinfo.q6.ExpectUnique        = mDNSfalse;
-    request->u.addrinfo.q4.ForceMCast          = request->u.addrinfo.q6.ForceMCast          = (flags & kDNSServiceFlagsForceMulticast     ) != 0;
-    request->u.addrinfo.q4.ReturnIntermed      = request->u.addrinfo.q6.ReturnIntermed      = (flags & kDNSServiceFlagsReturnIntermediates) != 0;
-    request->u.addrinfo.q4.SuppressUnusable    = request->u.addrinfo.q6.SuppressUnusable    = (flags & kDNSServiceFlagsSuppressUnusable   ) != 0;
-    request->u.addrinfo.q4.TimeoutQuestion     = request->u.addrinfo.q6.TimeoutQuestion     = (flags & kDNSServiceFlagsTimeout            ) != 0;
-    request->u.addrinfo.q4.allowExpired        = request->u.addrinfo.q6.allowExpired        = (EnableAllowExpired && (flags & kDNSServiceFlagsAllowExpiredAnswers) != 0) ? AllowExpired_AllowExpiredAnswers : AllowExpired_None;
-    request->u.addrinfo.q4.WakeOnResolve       = request->u.addrinfo.q6.WakeOnResolve    = 0;
-    request->u.addrinfo.q4.UseBackgroundTrafficClass = request->u.addrinfo.q6.UseBackgroundTrafficClass  = (flags & kDNSServiceFlagsBackgroundTrafficClass) != 0;
-    if ((flags & kDNSServiceFlagsValidate) != 0)
-        request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE;
-    else if ((flags & kDNSServiceFlagsValidateOptional) != 0)
-        request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = DNSSEC_VALIDATION_SECURE_OPTIONAL;
-    request->u.addrinfo.q4.ValidatingResponse = request->u.addrinfo.q6.ValidatingResponse = 0;
-    request->u.addrinfo.q4.ProxyQuestion      = request->u.addrinfo.q6.ProxyQuestion      = 0;
-    request->u.addrinfo.q4.qnameOrig          = request->u.addrinfo.q6.qnameOrig          = mDNSNULL;
-    request->u.addrinfo.q4.AnonInfo           = request->u.addrinfo.q6.AnonInfo           = mDNSNULL;
-
-    SetQuestionPolicy(&request->u.addrinfo.q4, request);
-    SetQuestionPolicy(&request->u.addrinfo.q6, request);
-
-    request->u.addrinfo.q4.StopTime = request->u.addrinfo.q6.StopTime  = 0;
-
-    request->u.addrinfo.q4.DNSSECAuthInfo = request->u.addrinfo.q6.DNSSECAuthInfo = mDNSNULL;
-    request->u.addrinfo.q4.DAIFreeCallback = request->u.addrinfo.q6.DAIFreeCallback = mDNSNULL;
-
-    //Turn off dnssec validation for local domains
-    if (IsLocalDomain(&d))
-        request->u.addrinfo.q4.ValidationRequired = request->u.addrinfo.q6.ValidationRequired = 0;
-
-    hostnameLen = strlen(hostname);
-
-    LogOperation("%3d: DNSServiceGetAddrInfo(%X, %d, %d, %##s) START PID[%d](%s)", 
-        request->sd, flags, interfaceIndex, request->u.addrinfo.protocol, d.c, request->process_id, request->pid_name);
-
-    if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
-    {
-        request->u.addrinfo.q6.qtype            = kDNSServiceType_AAAA;
-        request->u.addrinfo.q6.SearchListIndex  = 0;
-        // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set
-        if ((!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q6.ValidationRequired == DNSSEC_VALIDATION_INSECURE))
-            && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
-        {
-            request->u.addrinfo.q6.AppendSearchDomains = 1;
-            request->u.addrinfo.q6.AppendLocalSearchDomains = 1;
-        }
-        else
-        {
-            request->u.addrinfo.q6.AppendSearchDomains = 0;
-            request->u.addrinfo.q6.AppendLocalSearchDomains = 0;
-        }
-        request->u.addrinfo.q6.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q6) ? 1 : 0);
-        request->u.addrinfo.q6.QuestionCallback = queryrecord_result_callback;
-        request->u.addrinfo.q6.QuestionContext  = request;
-        err = mDNS_StartQuery(&mDNSStorage, &request->u.addrinfo.q6);
-        if (err != mStatus_NoError)
-        {
-            LogMsg("ERROR: mDNS_StartQuery: %d", (int)err);
-            request->u.addrinfo.q6.QuestionContext = mDNSNULL;
-        }
-        #if APPLE_OSX_mDNSResponder
-        err = SendAdditionalQuery(&request->u.addrinfo.q6, request, err);
-        #endif // APPLE_OSX_mDNSResponder
-        if (!err)
-        {
-            request->terminate = addrinfo_termination_callback;
-            LogMcastQ(&request->u.addrinfo.q6, request, q_start);
-            if (callExternalHelpers(InterfaceID, &d, flags))
-            {
-                LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for AAAA record");
-                external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags);
-            }
-        }
-    }
+    request->flags          = flags;
+    request->interfaceIndex = interfaceIndex;
 
-    if (!err && (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv4))
-    {
-        request->u.addrinfo.q4.qtype            = kDNSServiceType_A;
-        request->u.addrinfo.q4.SearchListIndex  = 0;
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+           "[R%u] DNSServiceGetAddrInfo(%X, %d, %u, " PRI_S ") START PID[%d](" PUB_S ")",
+           request->request_id, request->flags, request->interfaceIndex, protocols, hostname, request->process_id,
+           request->pid_name);
 
-        // We append search domains only for queries that are a single label. If overriden using cmd line arg
-        // "AlwaysAppendSearchDomains", then we do it for any query which is not fully qualified.
-        // For DNSSEC questions, append search domains only if kDNSServiceFlagsValidateOptional is set.
+    mDNSPlatformMemZero(&request->u.addrinfo, (mDNSu32)sizeof(request->u.addrinfo));
 
-        if ((!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_SECURE)) && (!(request->u.addrinfo.q4.ValidationRequired == DNSSEC_VALIDATION_INSECURE))
-            && ((hostnameLen == 0) || (hostname[hostnameLen - 1] != '.')) && (AlwaysAppendSearchDomains || CountLabels(&d) == 1))
-        {
-            request->u.addrinfo.q4.AppendSearchDomains = 1;
-            request->u.addrinfo.q4.AppendLocalSearchDomains = 1;
-        }
-        else
-        {
-            request->u.addrinfo.q4.AppendSearchDomains = 0;
-            request->u.addrinfo.q4.AppendLocalSearchDomains = 0;
-        }
-        request->u.addrinfo.q4.RetryWithSearchDomains = (ApplySearchDomainsFirst(&request->u.addrinfo.q4) ? 1 : 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;
-            if (request->u.addrinfo.protocol & kDNSServiceProtocol_IPv6)
-            {
-                // If we started a query for IPv6, we need to cancel it
-                mDNS_StopQuery(&mDNSStorage, &request->u.addrinfo.q6);
-                request->u.addrinfo.q6.QuestionContext = mDNSNULL;
+    err = GetAddrInfoClientRequestStart(&request->u.addrinfo, request->request_id, hostname, interfaceIndex, flags,
+        protocols, request->validUUID ? 0 : request->process_id, request->validUUID ? request->uuid : mDNSNULL,
+        request->uid, queryrecord_result_reply, request);
+    if (err) goto exit;
 
-                if (callExternalHelpers(InterfaceID, &d, flags))
-                {
-                    LogInfo("addrinfo_termination_callback: calling external_stop_browsing_for_service() for AAAA record");
-                    external_stop_browsing_for_service(InterfaceID, &d, kDNSServiceType_AAAA, flags);
-                }
-            }
-        }
-        #if APPLE_OSX_mDNSResponder
-        err = SendAdditionalQuery(&request->u.addrinfo.q4, request, err);
-        #endif // APPLE_OSX_mDNSResponder
-        if (!err)
-        {
-            request->terminate = addrinfo_termination_callback;
-            LogMcastQ(&request->u.addrinfo.q4, request, q_start);
-            if (callExternalHelpers(InterfaceID, &d, flags))
-            {
-                LogDebug("handle_addrinfo_request: calling external_start_browsing_for_service() for A record");
-                external_start_browsing_for_service(InterfaceID, &d, kDNSServiceType_A, flags);
-            }
-        }
-    }
+    request->terminate = addrinfo_termination_callback;
 
+exit:
     return(err);
 }
 
@@ -4578,14 +3508,13 @@ mDNSlocal mStatus handle_addrinfo_request(request_state *request)
 
 mDNSlocal request_state *NewRequest(void)
 {
+    request_state *request;
     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);
+    request = (request_state *) callocL("request_state", sizeof(*request));
+    if (!request) FatalError("ERROR: calloc");
+    while (*p) p = &(*p)->next;
+    *p = request;
+    return(request);
 }
 
 // read_msg may be called any time when the transfer state (req->ts) is t_morecoming.
@@ -4593,7 +3522,12 @@ mDNSlocal request_state *NewRequest(void)
 mDNSlocal void read_msg(request_state *req)
 {
     if (req->ts == t_terminated || req->ts == t_error)
-    { LogMsg("%3d: ERROR: read_msg called with transfer state terminated or error", req->sd); req->ts = t_error; return; }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                  "[R%u] ERROR: read_msg called with transfer state terminated or error", req->request_id);
+        req->ts = t_error;
+        return;
+    }
 
     if (req->ts == t_complete)  // this must be death or something is wrong
     {
@@ -4601,13 +3535,19 @@ mDNSlocal void read_msg(request_state *req)
         int nread = udsSupportReadFD(req->sd, buf, 4, 0, req->platform_data);
         if (!nread) { req->ts = t_terminated; return; }
         if (nread < 0) goto rerror;
-        LogMsg("%3d: ERROR: read data from a completed request", req->sd);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                  "[R%u] ERROR: read data from a completed request", req->request_id);
         req->ts = t_error;
         return;
     }
 
     if (req->ts != t_morecoming)
-    { LogMsg("%3d: ERROR: read_msg called with invalid transfer state (%d)", req->sd, req->ts); req->ts = t_error; return; }
+    {
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                  "[R%u] ERROR: read_msg called with invalid transfer state (%d)", req->request_id, req->ts);
+        req->ts = t_error;
+        return;
+    }
 
     if (req->hdr_bytes < sizeof(ipc_msg_hdr))
     {
@@ -4617,25 +3557,39 @@ mDNSlocal void read_msg(request_state *req)
         if (nread < 0) goto rerror;
         req->hdr_bytes += nread;
         if (req->hdr_bytes > sizeof(ipc_msg_hdr))
-        { LogMsg("%3d: ERROR: read_msg - read too many header bytes", req->sd); req->ts = t_error; return; }
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                      "[R%u] ERROR: read_msg - read too many header bytes", req->request_id);
+            req->ts = t_error;
+            return;
+        }
 
         // only read data if header is complete
         if (req->hdr_bytes == sizeof(ipc_msg_hdr))
         {
             ConvertHeaderBytes(&req->hdr);
             if (req->hdr.version != VERSION)
-            { LogMsg("%3d: ERROR: client version 0x%08X daemon version 0x%08X", req->sd, req->hdr.version, VERSION); req->ts = t_error; return; }
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                          "[R%u] ERROR: client version 0x%08X daemon version 0x%08X", req->request_id, req->hdr.version, VERSION);
+                req->ts = t_error;
+                return;
+            }
 
             // Largest conceivable single request is a DNSServiceRegisterRecord() or DNSServiceAddRecord()
             // with 64kB of rdata. Adding 1009 byte for a maximal domain name, plus a safety margin
             // for other overhead, this means any message above 70kB is definitely bogus.
             if (req->hdr.datalen > 70000)
-            { LogMsg("%3d: ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->sd, req->hdr.datalen, req->hdr.datalen); req->ts = t_error; return; }
-            req->msgbuf = mallocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
-            if (!req->msgbuf) { my_perror("ERROR: malloc"); req->ts = t_error; return; }
+            {
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                          "[R%u] ERROR: read_msg: hdr.datalen %u (0x%X) > 70000", req->request_id, req->hdr.datalen, req->hdr.datalen);
+                req->ts = t_error;
+                return;
+            }
+            req->msgbuf = (char *) callocL("request_state msgbuf", req->hdr.datalen + MSG_PAD_BYTES);
+            if (!req->msgbuf) { my_perror("ERROR: calloc"); req->ts = t_error; return; }
             req->msgptr = req->msgbuf;
             req->msgend = req->msgbuf + req->hdr.datalen;
-            mDNSPlatformMemZero(req->msgbuf, req->hdr.datalen + MSG_PAD_BYTES);
         }
     }
 
@@ -4667,12 +3621,19 @@ mDNSlocal void read_msg(request_state *req)
         if (nread < 0) goto rerror;
         req->data_bytes += nread;
         if (req->data_bytes > req->hdr.datalen)
-        { LogMsg("%3d: ERROR: read_msg - read too many data bytes", req->sd); req->ts = t_error; return; }
+        {
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                      "[R%u] ERROR: read_msg - read too many data bytes", req->request_id);
+            req->ts = t_error;
+            return;
+        }
 #if !defined(_WIN32)
         cmsg = CMSG_FIRSTHDR(&msg);
 #if DEBUG_64BIT_SCM_RIGHTS
-        LogMsg("%3d: Expecting %d %d %d %d", req->sd, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS);
-        LogMsg("%3d: Got       %d %d %d %d", req->sd, msg.msg_controllen, cmsg ? cmsg->cmsg_len : -1, cmsg ? cmsg->cmsg_level : -1, cmsg ? cmsg->cmsg_type : -1);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "[R%u] Expecting %d %d %d %d", req->request_id, sizeof(cbuf), sizeof(cbuf), SOL_SOCKET, SCM_RIGHTS);
+        LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                  "[R%u] Got       %d %d %d %d", req->request_id, msg.msg_controllen, cmsg ? cmsg->cmsg_len : -1, cmsg ? cmsg->cmsg_level : -1, cmsg ? cmsg->cmsg_type : -1);
 #endif // DEBUG_64BIT_SCM_RIGHTS
         if (cmsg && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
         {
@@ -4683,19 +3644,22 @@ mDNSlocal void read_msg(request_state *req)
             if (req->hdr.op == send_bpf)
             {
                 dnssd_sock_t x = *(dnssd_sock_t *)CMSG_DATA(cmsg);
-                LogOperation("%3d: Got len %d, BPF %d", req->sd, cmsg->cmsg_len, x);
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                          "[R%u] Got len %d, BPF %d", req->request_id, cmsg->cmsg_len, x);
                 mDNSPlatformReceiveBPF_fd(x);
             }
             else
 #endif // APPLE_OSX_mDNSResponder
             req->errsd = *(dnssd_sock_t *)CMSG_DATA(cmsg);
 #if DEBUG_64BIT_SCM_RIGHTS
-            LogMsg("%3d: read req->errsd %d", req->sd, req->errsd);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT,
+                      "[R%u] read req->errsd %d", req->request_id, req->errsd);
 #endif // DEBUG_64BIT_SCM_RIGHTS
             if (req->data_bytes < req->hdr.datalen)
             {
-                LogMsg("%3d: Client(PID [%d](%s)) sent result code socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
-                       req->sd, req->process_id, req->pid_name, req->errsd, req->data_bytes, req->hdr.datalen);
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG,
+                          "[R%u] Client(PID [%d](" PUB_S ")) sent result code socket %d via SCM_RIGHTS with req->data_bytes %d < req->hdr.datalen %d",
+                          req->request_id, req->process_id, req->pid_name, req->errsd, req->data_bytes, req->hdr.datalen);
                 req->ts = t_error;
                 return;
             }
@@ -4730,7 +3694,12 @@ mDNSlocal void read_msg(request_state *req)
             if (ctrl_path[0] == 0)
             {
                 if (req->errsd == req->sd)
-                { LogMsg("%3d: read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->sd); req->ts = t_error; return; }
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[R%u] read_msg: ERROR failed to get errsd via SCM_RIGHTS", req->request_id);
+                    req->ts = t_error;
+                    return;
+                }
                 goto got_errfd;
             }
 #endif
@@ -4747,12 +3716,21 @@ mDNSlocal void read_msg(request_state *req)
             {
 #if !defined(USE_TCP_LOOPBACK)
                 struct stat sb;
-                LogMsg("%3d: read_msg: Couldn't connect to error return path socket “%s” errno %d (%s)",
-                       req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                          "[R%u] read_msg: Couldn't connect to error return path socket " PUB_S " errno %d (" PUB_S ")",
+                          req->request_id, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
                 if (stat(cliaddr.sun_path, &sb) < 0)
-                    LogMsg("%3d: read_msg: stat failed “%s” errno %d (%s)", req->sd, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[R%u] read_msg: stat failed " PUB_S " errno %d (" PUB_S ")",
+                              req->request_id, cliaddr.sun_path, dnssd_errno, dnssd_strerror(dnssd_errno));
+                }
                 else
-                    LogMsg("%3d: read_msg: file “%s” mode %o (octal) uid %d gid %d", req->sd, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
+                {
+                    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                              "[R%u] read_msg: file " PUB_S " mode %o (octal) uid %d gid %d",
+                              req->request_id, cliaddr.sun_path, sb.st_mode, sb.st_uid, sb.st_gid);
+                }
 #endif
                 req->ts = t_error;
                 return;
@@ -4761,15 +3739,16 @@ mDNSlocal void read_msg(request_state *req)
 #if !defined(USE_TCP_LOOPBACK)
 got_errfd:
 #endif
-            LogDebug("%3d: Result code socket %d created %08X %08X", req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0]);
+
 #if defined(_WIN32)
             if (ioctlsocket(req->errsd, FIONBIO, &opt) != 0)
 #else
             if (fcntl(req->errsd, F_SETFL, fcntl(req->errsd, F_GETFL, 0) | O_NONBLOCK) != 0)
 #endif
             {
-                LogMsg("%3d: ERROR: could not set control socket to non-blocking mode errno %d (%s)",
-                       req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
+                LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+                          "[R%u] ERROR: could not set control socket to non-blocking mode errno %d (" PUB_S ")",
+                          req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
                 req->ts = t_error;
                 return;
             }
@@ -4782,7 +3761,8 @@ got_errfd:
 
 rerror:
     if (dnssd_errno == dnssd_EWOULDBLOCK || dnssd_errno == dnssd_EINTR) return;
-    LogMsg("%3d: ERROR: read_msg errno %d (%s)", req->sd, dnssd_errno, dnssd_strerror(dnssd_errno));
+    LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_ERROR,
+              "[R%u] ERROR: read_msg errno %d (" PUB_S ")", req->request_id, dnssd_errno, dnssd_strerror(dnssd_errno));
     req->ts = t_error;
 }
 
@@ -4793,13 +3773,15 @@ mDNSlocal mStatus handle_client_request(request_state *req)
     {
             // These are all operations that have their own first-class request_state object
         case connection_request:
-            LogOperation("%3d: DNSServiceCreateConnection START PID[%d](%s)",
-                         req->sd, req->process_id, req->pid_name);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                   "[R%d] DNSServiceCreateConnection START PID[%d](" PUB_S ")",
+                   req->request_id, req->process_id, req->pid_name);
             req->terminate = connection_termination;
             break;
         case connection_delegate_request:
-            LogOperation("%3d: DNSServiceCreateDelegateConnection START PID[%d](%s)",
-                         req->sd, req->process_id, req->pid_name);
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+                   "[R%d] DNSServiceCreateDelegateConnection START PID[%d](" PRI_S ")",
+                   req->request_id, req->process_id, req->pid_name);
             req->terminate = connection_termination;
             handle_connection_delegate_request(req);
             break;
@@ -4811,7 +3793,6 @@ mDNSlocal mStatus handle_client_request(request_state *req)
         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 getpid_request:                     handle_getpid_request      (req);  break;
         case port_mapping_request:         err = handle_port_mapping_request(req);  break;
         case addrinfo_request:             err = handle_addrinfo_request    (req);  break;
         case send_bpf:                     /* Do nothing for send_bpf */            break;
@@ -4838,13 +3819,12 @@ mDNSlocal mStatus handle_client_request(request_state *req)
 // 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)
+mDNSlocal void request_callback(int fd, void *info)
 {
     mStatus err = 0;
     request_state *req = info;
     mDNSs32 min_size = sizeof(DNSServiceFlags);
     (void)fd; // Unused
-    (void)filter; // Unused
 
     for (;;)
     {
@@ -4879,7 +3859,6 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
             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 getpid_request:           min_size = 2;                                                                           break;
             case port_mapping_request:     min_size += sizeof(mDNSu32) + 4 /* udp/tcp */ + 4 /* int/ext port */    + 4 /* ttl */;  break;
             case addrinfo_request:         min_size += sizeof(mDNSu32) + 4 /* v4/v6 */   + 1 /* hostname */;                       break;
             case send_bpf:                 // Same as cancel_request below
@@ -4917,6 +3896,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
             newreq->msgbuf  = req->msgbuf;
             newreq->msgptr  = req->msgptr;
             newreq->msgend  = req->msgend;
+            newreq->request_id = mDNSStorage.next_request_id++; 
             // if the parent request is a delegate connection, copy the
             // relevant bits
             if (req->validUUID)
@@ -4960,8 +3940,6 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
             send_all(req->errsd, (const char *)&err_netorder, sizeof(err_netorder));
             if (req->errsd != req->sd)
             {
-                LogDebug("%3d: Result code socket %d closed  %08X %08X (%d)",
-                         req->sd, req->errsd, req->hdr.client_context.u32[1], req->hdr.client_context.u32[0], err);
                 dnssd_close(req->errsd);
                 req->errsd = req->sd;
                 // Also need to reset the parent's errsd, if this is a subordinate operation
@@ -4980,7 +3958,7 @@ mDNSlocal void request_callback(int fd, short filter, void *info)
     }
 }
 
-mDNSlocal void connect_callback(int fd, short filter, void *info)
+mDNSlocal void connect_callback(int fd, void *info)
 {
     dnssd_sockaddr_t cliaddr;
     dnssd_socklen_t len = (dnssd_socklen_t) sizeof(cliaddr);
@@ -4989,7 +3967,6 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
     unsigned long optval = 1;
 #endif
 
-    (void)filter; // Unused
     (void)info; // Unused
 
     if (!dnssd_SocketValid(sd))
@@ -5021,6 +3998,7 @@ mDNSlocal void connect_callback(int fd, short filter, void *info)
         request->ts    = t_morecoming;
         request->sd    = sd;
         request->errsd = sd;
+        request->request_id = mDNSStorage.next_request_id++;
         set_peer_pid(request);
 #if APPLE_OSX_mDNSResponder
         struct xucred x;
@@ -5079,24 +4057,29 @@ mDNSlocal mDNSBool uds_socket_setup(dnssd_sock_t skt)
     return mDNStrue;
 }
 
+#if MDNS_MALLOC_DEBUGGING
+mDNSlocal void udsserver_validatelists(void *context);
+#endif
+
 mDNSexport int udsserver_init(dnssd_sock_t skts[], mDNSu32 count)
 {
     dnssd_sockaddr_t laddr;
     int ret;
     mDNSu32 i = 0;
 
-    LogInfo("udsserver_init: %d %d", _DNS_SD_H, mDNSStorage.mDNS_plat);
-
-    // If a particular platform wants to opt out of having a PID file, define PID_FILE to be ""
-    if (PID_FILE[0])
+#ifndef NO_PID_FILE
+    FILE *fp = fopen(PID_FILE, "w");
+    if (fp != NULL)
     {
-        FILE *fp = fopen(PID_FILE, "w");
-        if (fp != NULL)
-        {
-            fprintf(fp, "%d\n", getpid());
-            fclose(fp);
-        }
+        fprintf(fp, "%d\n", getpid());
+        fclose(fp);
     }
+#endif
+
+#if MDNS_MALLOC_DEBUGGING
+       static mDNSListValidator validator;
+       mDNSPlatformAddListValidator(&validator, udsserver_validatelists, "udsserver_validatelists", NULL);
+#endif
 
     if (skts)
     {
@@ -5227,21 +4210,100 @@ mDNSexport int udsserver_exit(void)
 #endif
     }
 
-    if (PID_FILE[0]) unlink(PID_FILE);
+#ifndef NO_PID_FILE
+    unlink(PID_FILE);
+#endif
 
     return 0;
 }
 
-mDNSlocal void LogClientInfo(request_state *req)
+mDNSlocal void LogClientInfoToFD(int fd, request_state *req)
 {
-    char prefix[16];
-    if (req->primary)
-        mDNS_snprintf(prefix, sizeof(prefix), " -> ");
+    char reqIDStr[14];
+    char prefix[18];
+
+    mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
+
+    mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
+
+    if (!req->terminate)
+        LogToFD(fd, "%s No operation yet on this socket", prefix);
+    else if (req->terminate == connection_termination)
+    {
+        int num_records = 0, num_ops = 0;
+        const registered_record_entry *p;
+        request_state *r;
+        for (p = req->u.reg_recs; p; p=p->next) num_records++;
+        for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
+        LogToFD(fd, "%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
+                  prefix, num_records, num_records != 1 ? "s" : "", num_ops,     num_ops     != 1 ? "s" : "",
+                  req->process_id, req->pid_name);
+        for (p = req->u.reg_recs; p; p=p->next)
+            LogToFD(fd, " ->  DNSServiceRegisterRecord   0x%08X %2d %3d %s PID[%d](%s)",
+                      req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
+        for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfoToFD(fd, r);
+    }
+    else if (req->terminate == regservice_termination_callback)
+    {
+        service_instance *ptr;
+        for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
+            LogToFD(fd, "%-9s DNSServiceRegister         0x%08X %2d %##s %u/%u PID[%d](%s)",
+                      (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
+                      mDNSVal16(req->u.servicereg.port),
+                      SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
+    }
+    else if (req->terminate == browse_termination_callback)
+    {
+        browser_t *blist;
+        for (blist = req->u.browser.browsers; blist; blist = blist->next)
+            LogToFD(fd, "%-9s DNSServiceBrowse           0x%08X %2d %##s PID[%d](%s)",
+                      (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
+                      req->process_id, req->pid_name);
+    }
+    else if (req->terminate == resolve_termination_callback)
+        LogToFD(fd, "%s DNSServiceResolve          0x%08X %2d %##s PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
+    else if (req->terminate == queryrecord_termination_callback)
+        LogToFD(fd, "%s DNSServiceQueryRecord      0x%08X %2d %##s (%s) PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
+    else if (req->terminate == enum_termination_callback)
+        LogToFD(fd, "%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
+    else if (req->terminate == port_mapping_termination_callback)
+        LogToFD(fd, "%s DNSServiceNATPortMapping   0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
+                  prefix,
+                  req->flags,
+                  req->interfaceIndex,
+                  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),
+                  &req->u.pm.NATinfo.ExternalAddress,
+                  mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+                  req->u.pm.NATinfo.NATLease,
+                  req->u.pm.NATinfo.Lifetime,
+                  req->process_id, req->pid_name);
+    else if (req->terminate == addrinfo_termination_callback)
+        LogToFD(fd, "%s DNSServiceGetAddrInfo      0x%08X %2d %s%s %##s PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex,
+                  req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
+                  req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
+                  GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
     else
-        mDNS_snprintf(prefix, sizeof(prefix), "%3d:", req->sd);
+        LogToFD(fd, "%s Unrecognized operation %p", prefix, req->terminate);
+}
+
+mDNSlocal void LogClientInfo(request_state *req)
+{
+    char reqIDStr[14];
+    char prefix[18];
+
+    mDNS_snprintf(reqIDStr, sizeof(reqIDStr), "[R%u]", req->request_id);
+
+    mDNS_snprintf(prefix, sizeof(prefix), "%-6s %2s", reqIDStr, req->primary ? "->" : "");
 
     if (!req->terminate)
-        LogMsgNoIdent("%s No operation yet on this socket", prefix);
+    LogMsgNoIdent("%s No operation yet on this socket", prefix);
     else if (req->terminate == connection_termination)
     {
         int num_records = 0, num_ops = 0;
@@ -5250,63 +4312,61 @@ mDNSlocal void LogClientInfo(request_state *req)
         for (p = req->u.reg_recs; p; p=p->next) num_records++;
         for (r = req->next; r; r=r->next) if (r->primary == req) num_ops++;
         LogMsgNoIdent("%s DNSServiceCreateConnection: %d registered record%s, %d kDNSServiceFlagsShareConnection operation%s PID[%d](%s)",
-                       prefix, num_records, num_records != 1 ? "s" : "", num_ops,     num_ops     != 1 ? "s" : "",
-                       req->process_id, req->pid_name);
+                      prefix, num_records, num_records != 1 ? "s" : "", num_ops,     num_ops     != 1 ? "s" : "",
+                      req->process_id, req->pid_name);
         for (p = req->u.reg_recs; p; p=p->next)
-            LogMsgNoIdent(" ->  DNSServiceRegisterRecord   0x%08X %2d %3d %s PID[%d](%s)",
-                           req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
+        LogMsgNoIdent(" ->  DNSServiceRegisterRecord   0x%08X %2d %3d %s PID[%d](%s)",
+                      req->flags, req->interfaceIndex, p->key, ARDisplayString(&mDNSStorage, p->rr), req->process_id, req->pid_name);
         for (r = req->next; r; r=r->next) if (r->primary == req) LogClientInfo(r);
     }
     else if (req->terminate == regservice_termination_callback)
     {
         service_instance *ptr;
-        char anonstr[256];
         for (ptr = req->u.servicereg.instances; ptr; ptr = ptr->next)
-            LogMsgNoIdent("%s DNSServiceRegister         0x%08X %2d %##s%s %u/%u PID[%d](%s)",
-                           (ptr == req->u.servicereg.instances) ? prefix : "    ", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
-                           AnonDataToString(ptr->srs.AnonData, 0, anonstr, sizeof(anonstr)), mDNSVal16(req->u.servicereg.port),
-                           SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
+        LogMsgNoIdent("%-9s DNSServiceRegister         0x%08X %2d %##s %u/%u PID[%d](%s)",
+                      (ptr == req->u.servicereg.instances) ? prefix : "", req->flags, req->interfaceIndex, ptr->srs.RR_SRV.resrec.name->c,
+                      mDNSVal16(req->u.servicereg.port),
+                      SRS_PORT(&ptr->srs), req->process_id, req->pid_name);
     }
     else if (req->terminate == browse_termination_callback)
     {
         browser_t *blist;
-        char anonstr[256];
         for (blist = req->u.browser.browsers; blist; blist = blist->next)
-            LogMsgNoIdent("%s DNSServiceBrowse           0x%08X %2d %##s%s PID[%d](%s)",
-                           (blist == req->u.browser.browsers) ? prefix : "    ", req->flags, req->interfaceIndex, blist->q.qname.c,
-                           AnonDataToString(req->u.browser.AnonData, 0, anonstr, sizeof(anonstr)), req->process_id, req->pid_name);
+        LogMsgNoIdent("%-9s DNSServiceBrowse           0x%08X %2d %##s PID[%d](%s)",
+                      (blist == req->u.browser.browsers) ? prefix : "", req->flags, req->interfaceIndex, blist->q.qname.c,
+                      req->process_id, req->pid_name);
     }
     else if (req->terminate == resolve_termination_callback)
-        LogMsgNoIdent("%s DNSServiceResolve          0x%08X %2d %##s PID[%d](%s)",
-                       prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
+    LogMsgNoIdent("%s DNSServiceResolve          0x%08X %2d %##s PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex, req->u.resolve.qsrv.qname.c, req->process_id, req->pid_name);
     else if (req->terminate == queryrecord_termination_callback)
-        LogMsgNoIdent("%s DNSServiceQueryRecord      0x%08X %2d %##s (%s) PID[%d](%s)",
-                       prefix, req->flags, req->interfaceIndex, req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype), req->process_id, req->pid_name);
+    LogMsgNoIdent("%s DNSServiceQueryRecord      0x%08X %2d %##s (%s) PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex, QueryRecordClientRequestGetQName(&req->u.queryrecord), DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)), req->process_id, req->pid_name);
     else if (req->terminate == enum_termination_callback)
-        LogMsgNoIdent("%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
-                       prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
+    LogMsgNoIdent("%s DNSServiceEnumerateDomains 0x%08X %2d %##s PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex, req->u.enumeration.q_all.qname.c, req->process_id, req->pid_name);
     else if (req->terminate == port_mapping_termination_callback)
-        LogMsgNoIdent("%s DNSServiceNATPortMapping   0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
-                      prefix,
-                      req->flags,
-                      req->interfaceIndex,
-                      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),
-                      &req->u.pm.NATinfo.ExternalAddress,
-                      mDNSVal16(req->u.pm.NATinfo.ExternalPort),
-                      req->u.pm.NATinfo.NATLease,
-                      req->u.pm.NATinfo.Lifetime,
-                      req->process_id, req->pid_name);
+    LogMsgNoIdent("%s DNSServiceNATPortMapping   0x%08X %2d %s%s Int %5d Req %5d Ext %.4a:%5d Req TTL %5d Granted TTL %5d PID[%d](%s)",
+                  prefix,
+                  req->flags,
+                  req->interfaceIndex,
+                  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),
+                  &req->u.pm.NATinfo.ExternalAddress,
+                  mDNSVal16(req->u.pm.NATinfo.ExternalPort),
+                  req->u.pm.NATinfo.NATLease,
+                  req->u.pm.NATinfo.Lifetime,
+                  req->process_id, req->pid_name);
     else if (req->terminate == addrinfo_termination_callback)
-        LogMsgNoIdent("%s DNSServiceGetAddrInfo      0x%08X %2d %s%s %##s PID[%d](%s)",
-                      prefix, req->flags, req->interfaceIndex,
-                      req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
-                      req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
-                      req->u.addrinfo.q4.qname.c, req->process_id, req->pid_name);
+    LogMsgNoIdent("%s DNSServiceGetAddrInfo      0x%08X %2d %s%s %##s PID[%d](%s)",
+                  prefix, req->flags, req->interfaceIndex,
+                  req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
+                  req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
+                  GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name);
     else
-        LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
+    LogMsgNoIdent("%s Unrecognized operation %p", prefix, req->terminate);
 }
 
 mDNSlocal void GetMcastClients(request_state *req)
@@ -5355,12 +4415,12 @@ mDNSlocal void GetMcastClients(request_state *req)
     }
     else if (req->terminate == queryrecord_termination_callback)
     {
-        if ((mDNSOpaque16IsZero(req->u.queryrecord.q.TargetQID)) && (req->u.queryrecord.q.ThisQInterval > 0))
+        if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
             n_mquests++;
     }
     else if (req->terminate == addrinfo_termination_callback)
     {
-        if ((mDNSOpaque16IsZero(req->u.addrinfo.q4.TargetQID)) && (req->u.addrinfo.q4.ThisQInterval > 0))
+        if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
             n_mquests++;
     }
     else
@@ -5422,23 +4482,24 @@ mDNSlocal void LogMcastClientInfo(request_state *req)
     }
     else if (req->terminate == queryrecord_termination_callback)
     {
-        if ((mDNSOpaque16IsZero(req->u.queryrecord.q.TargetQID)) && (req->u.queryrecord.q.ThisQInterval > 0))
-            LogMcastNoIdent("Q: DNSServiceQueryRecord  %##s %s PID[%d](%s)", req->u.queryrecord.q.qname.c, DNSTypeName(req->u.queryrecord.q.qtype),
+        if (QueryRecordClientRequestIsMulticast(&req->u.queryrecord))
+        {
+            LogMcastNoIdent("Q: DNSServiceQueryRecord  %##s %s PID[%d](%s)",
+                          QueryRecordClientRequestGetQName(&req->u.queryrecord),
+                          DNSTypeName(QueryRecordClientRequestGetType(&req->u.queryrecord)),
                           req->process_id, req->pid_name, i_mcount++);
+        }
     }
     else if (req->terminate == addrinfo_termination_callback)
     {
-        if ((mDNSOpaque16IsZero(req->u.addrinfo.q4.TargetQID)) && (req->u.addrinfo.q4.ThisQInterval > 0))
+        if (GetAddrInfoClientRequestIsMulticast(&req->u.addrinfo))
+        {
             LogMcastNoIdent("Q: DNSServiceGetAddrInfo  %s%s %##s PID[%d](%s)",
-                          req->u.addrinfo.protocol & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
-                          req->u.addrinfo.protocol & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
-                          req->u.addrinfo.q4.qname.c, req->process_id, req->pid_name, i_mcount++);
-    }
-    else
-    {
-        return;
+                          req->u.addrinfo.protocols & kDNSServiceProtocol_IPv4 ? "v4" : "  ",
+                          req->u.addrinfo.protocols & kDNSServiceProtocol_IPv6 ? "v6" : "  ",
+                          GetAddrInfoClientRequestGetQName(&req->u.addrinfo), req->process_id, req->pid_name, i_mcount++);
+        }
     }
-
 }
 
 mDNSlocal char *RecordTypeName(mDNSu8 rtype)
@@ -5456,7 +4517,7 @@ mDNSlocal char *RecordTypeName(mDNSu8 rtype)
     }
 }
 
-mDNSlocal int LogEtcHosts(mDNS *const m)
+mDNSlocal int LogEtcHostsToFD(int fd, mDNS *const m)
 {
     mDNSBool showheader = mDNStrue;
     const AuthRecord *ar;
@@ -5473,29 +4534,29 @@ mDNSlocal int LogEtcHosts(mDNS *const m)
             for (ar = ag->members; ar; ar = ar->next)
             {
                 if (ar->RecordCallback != FreeEtcHosts) continue;
-                if (showheader) { showheader = mDNSfalse; LogMsgNoIdent("  State       Interface"); }
+                if (showheader) { showheader = mDNSfalse; LogToFD(fd, "  State       Interface"); }
 
                 // Print a maximum of 50 records
                 if (count++ >= 50) { truncated = mDNStrue; continue; }
                 if (ar->ARType == AuthRecordLocalOnly)
                 {
                     if (ar->resrec.InterfaceID == mDNSInterface_LocalOnly)
-                        LogMsgNoIdent(" %s   LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+                        LogToFD(fd, " %s   LO %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
                     else
                     {
                         mDNSu32 scopeid  = (mDNSu32)(uintptr_t)ar->resrec.InterfaceID;
-                        LogMsgNoIdent(" %s   %u  %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
+                        LogToFD(fd, " %s   %u  %s", RecordTypeName(ar->resrec.RecordType), scopeid, ARDisplayString(m, ar));
                     }
                 }
             }
     }
 
-    if (showheader) LogMsgNoIdent("<None>");
-    else if (truncated) LogMsgNoIdent("<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
+    if (showheader) LogToFD(fd, "<None>");
+    else if (truncated) LogToFD(fd, "<Truncated: to 50 records, Total records %d, Total Auth Groups %d, Auth Slots %d>", count, m->rrauth.rrauth_totalused, authslot);
     return count;
 }
 
-mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m)
+mDNSlocal void LogLocalOnlyAuthRecordsToFD(int fd, mDNS *const m)
 {
     mDNSBool showheader = mDNStrue;
     const AuthRecord *ar;
@@ -5508,62 +4569,52 @@ mDNSlocal void LogLocalOnlyAuthRecords(mDNS *const m)
             for (ar = ag->members; ar; ar = ar->next)
             {
                 if (ar->RecordCallback == FreeEtcHosts) continue;
-                if (showheader) { showheader = mDNSfalse; LogMsgNoIdent("  State       Interface"); }
+                if (showheader) { showheader = mDNSfalse; LogToFD(fd, "  State       Interface"); }
 
                 // Print a maximum of 400 records
                 if (ar->ARType == AuthRecordLocalOnly)
-                    LogMsgNoIdent(" %s   LO  %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+                    LogToFD(fd, " %s   LO  %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
                 else if (ar->ARType == AuthRecordP2P)
                 {
                     if (ar->resrec.InterfaceID == mDNSInterface_BLE)
-                        LogMsgNoIdent(" %s   BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+                        LogToFD(fd, " %s   BLE %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
                     else
-                        LogMsgNoIdent(" %s   PP  %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
+                        LogToFD(fd, " %s   PP  %s", RecordTypeName(ar->resrec.RecordType), ARDisplayString(m, ar));
                 }
             }
     }
 
-    if (showheader) LogMsgNoIdent("<None>");
-}
-
-mDNSlocal char *AnonInfoToString(AnonymousInfo *ai, char *anonstr, int anstrlen)
-{
-    anonstr[0] = 0;
-    if (ai && ai->AnonData)
-    {
-        return (AnonDataToString(ai->AnonData, ai->AnonDataLen, anonstr, anstrlen));
-    }
-    return anonstr;
+    if (showheader) LogToFD(fd, "<None>");
 }
 
-mDNSlocal void LogOneAuthRecord(const AuthRecord *ar, mDNSs32 now, const char *const ifname)
+mDNSlocal void LogOneAuthRecordToFD(int fd, const AuthRecord *ar, mDNSs32 now, const char *ifname)
 {
-    char anstr[256];
     if (AuthRecord_uDNS(ar))
     {
-        LogMsgNoIdent("%7d %7d %7d %-7s %4d %s %s",
-                      ar->ThisAPInterval / mDNSPlatformOneSecond,
-                      (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
-                      ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
-                      "-U-",
-                      ar->state,
-                      ar->AllowRemoteQuery ? "☠" : " ",
-                      ARDisplayString(&mDNSStorage, ar));
+        LogToFD(fd, "%7d %7d %7d %-7s %4d %s %s",
+                  ar->ThisAPInterval / mDNSPlatformOneSecond,
+                  (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond,
+                  ar->expire ? (ar->expire - now) / mDNSPlatformOneSecond : 0,
+                  "-U-",
+                  ar->state,
+                  ar->AllowRemoteQuery ? "☠" : " ",
+                  ARDisplayString(&mDNSStorage, ar));
     }
     else
     {
-        LogMsgNoIdent("%7d %7d %7d %-7s 0x%02X %s %s%s",
-                      ar->ThisAPInterval / mDNSPlatformOneSecond,
-                      ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
-                      ar->TimeExpire    ? (ar->TimeExpire                      - now) / mDNSPlatformOneSecond : 0,
-                      ifname ? ifname : "ALL",
-                      ar->resrec.RecordType,
-                      ar->AllowRemoteQuery ? "☠" : " ",
-                      ARDisplayString(&mDNSStorage, ar), AnonInfoToString(ar->resrec.AnonInfo, anstr, sizeof(anstr)));
+        LogToFD(fd, "%7d %7d %7d %-7s 0x%02X %s %s",
+                  ar->ThisAPInterval / mDNSPlatformOneSecond,
+                  ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
+                  ar->TimeExpire    ? (ar->TimeExpire                      - now) / mDNSPlatformOneSecond : 0,
+                  ifname ? ifname : "ALL",
+                  ar->resrec.RecordType,
+                  ar->AllowRemoteQuery ? "☠" : " ",
+                  ARDisplayString(&mDNSStorage, ar));
     }
 }
 
-mDNSlocal void LogAuthRecords(const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
+mDNSlocal void LogAuthRecordsToFD(int fd,
+                                    const mDNSs32 now, AuthRecord *ResourceRecords, int *proxy)
 {
     mDNSBool showheader = mDNStrue;
     const AuthRecord *ar;
@@ -5573,69 +4624,57 @@ mDNSlocal void LogAuthRecords(const mDNSs32 now, AuthRecord *ResourceRecords, in
         const char *const ifname = InterfaceNameForID(&mDNSStorage, ar->resrec.InterfaceID);
         if ((ar->WakeUp.HMAC.l[0] != 0) == (proxy != mDNSNULL))
         {
-            if (showheader) { showheader = mDNSfalse; LogMsgNoIdent("    Int    Next  Expire if     State"); }
+            if (showheader) { showheader = mDNSfalse; LogToFD(fd, "    Int    Next  Expire if     State"); }
             if (proxy) (*proxy)++;
             if (!mDNSPlatformMemSame(&owner, &ar->WakeUp, sizeof(owner)))
             {
                 owner = ar->WakeUp;
                 if (owner.password.l[0])
-                    LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
+                    LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a Password %.6a seq %d", &owner.HMAC, &owner.IMAC, &owner.password, owner.seq);
                 else if (!mDNSSameEthAddress(&owner.HMAC, &owner.IMAC))
-                    LogMsgNoIdent("Proxying for H-MAC %.6a I-MAC %.6a seq %d",               &owner.HMAC, &owner.IMAC,                  owner.seq);
+                    LogToFD(fd, "Proxying for H-MAC %.6a I-MAC %.6a seq %d",               &owner.HMAC, &owner.IMAC,                  owner.seq);
                 else
-                    LogMsgNoIdent("Proxying for %.6a seq %d",                                &owner.HMAC,                               owner.seq);
+                    LogToFD(fd, "Proxying for %.6a seq %d",                                &owner.HMAC,                               owner.seq);
             }
             if (AuthRecord_uDNS(ar))
             {
-                LogOneAuthRecord(ar, now, ifname);
+                LogOneAuthRecordToFD(fd, ar, now, ifname);
             }
             else if (ar->ARType == AuthRecordLocalOnly)
             {
-                LogMsgNoIdent("                             LO %s", ARDisplayString(&mDNSStorage, ar));
+                LogToFD(fd, "                             LO %s", ARDisplayString(&mDNSStorage, ar));
             }
             else if (ar->ARType == AuthRecordP2P)
             {
                 if (ar->resrec.InterfaceID == mDNSInterface_BLE)
-                    LogMsgNoIdent("                             BLE %s", ARDisplayString(&mDNSStorage, ar));
+                    LogToFD(fd, "                             BLE %s", ARDisplayString(&mDNSStorage, ar));
                 else
-                    LogMsgNoIdent("                             PP %s", ARDisplayString(&mDNSStorage, ar));
+                    LogToFD(fd, "                             PP %s", ARDisplayString(&mDNSStorage, ar));
             }
             else
             {
-                LogOneAuthRecord(ar, now, ifname);
-                if (ar->resrec.AnonInfo)
-                {
-                    ResourceRecord *nsec3 = ar->resrec.AnonInfo->nsec3RR;
-                    // We just print the values from the AuthRecord to keep it nicely aligned though
-                    // all we want here is the nsec3 information.
-                    LogMsgNoIdent("%7d %7d %7d %7s %s",
-                                  ar->ThisAPInterval / mDNSPlatformOneSecond,
-                                  ar->AnnounceCount ? (ar->LastAPTime + ar->ThisAPInterval - now) / mDNSPlatformOneSecond : 0,
-                                  ar->TimeExpire    ? (ar->TimeExpire                      - now) / mDNSPlatformOneSecond : 0,
-                                  ifname ? ifname : "ALL",
-                                  RRDisplayString(&mDNSStorage, nsec3));
-                }
+                LogOneAuthRecordToFD(fd, ar, now, ifname);
             }
         }
     }
-    if (showheader) LogMsgNoIdent("<None>");
+    if (showheader) LogToFD(fd, "<None>");
 }
 
-mDNSlocal void PrintOneCacheRecord(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintOneCacheRecordToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
 {
-    LogMsgNoIdent("%3d %s%8d %-7s%s %-6s%s",
-                  slot,
-                  cr->CRActiveQuestion ? "*" : " ",
-                  remain,
-                  ifname ? ifname : "-U-",
-                  (cr->resrec.RecordType == kDNSRecordTypePacketNegative)  ? "-" :
-                  (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
-                  DNSTypeName(cr->resrec.rrtype),
-                  CRDisplayString(&mDNSStorage, cr));
+    LogToFD(fd, "%3d %s%8d %-7s%s %-6s%s",
+              slot,
+              cr->CRActiveQuestion ? "*" : " ",
+              remain,
+              ifname ? ifname : "-U-",
+              (cr->resrec.RecordType == kDNSRecordTypePacketNegative)  ? "-" :
+              (cr->resrec.RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
+              DNSTypeName(cr->resrec.rrtype),
+              CRDisplayString(&mDNSStorage, cr));
     (*CacheUsed)++;
 }
 
-mDNSlocal void PrintCachedRecords(const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
+mDNSlocal void PrintCachedRecordsToFD(int fd, const CacheRecord *cr, mDNSu32 slot, const mDNSu32 remain, const char *ifname, mDNSu32 *CacheUsed)
 {
     CacheRecord *nsec;
     CacheRecord *soa;
@@ -5645,97 +4684,51 @@ mDNSlocal void PrintCachedRecords(const CacheRecord *cr, mDNSu32 slot, const mDN
     // their own lifetime. If the main cache record expires, they also expire.
     while (nsec)
     {
-        PrintOneCacheRecord(nsec, slot, remain, ifname, CacheUsed);
+        PrintOneCacheRecordToFD(fd, nsec, slot, remain, ifname, CacheUsed);
         nsec = nsec->next;
     }
     soa = cr->soa;
     if (soa)
     {
-        PrintOneCacheRecord(soa, slot, remain, ifname, CacheUsed);
+        PrintOneCacheRecordToFD(fd, soa, slot, remain, ifname, CacheUsed);
     }
-    if (cr->resrec.AnonInfo)
-    {
-        ResourceRecord *nsec3 = cr->resrec.AnonInfo->nsec3RR;
-        // Even though it is a resource record, we print the sameway
-        // as a cache record so that it aligns properly.
-        if (nsec3)
-        {
-            LogMsgNoIdent("%3d %s%8d %-7s%s %-6s%s",
-                          slot,
-                          " ",
-                          remain,
-                          ifname ? ifname : "-U-",
-                          (nsec3->RecordType == kDNSRecordTypePacketNegative)  ? "-" :
-                          (nsec3->RecordType & kDNSRecordTypePacketUniqueMask) ? " " : "+",
-                          DNSTypeName(nsec3->rrtype),
-                          RRDisplayString(&mDNSStorage, nsec3));
-        }
-    }
-}
-
-mDNSlocal char *AnonDataToString(const mDNSu8 *ad, int adlen, char *adstr, int adstrlen)
-{
-    adstr[0] = 0;
-    if (ad)
-    {
-        int len;
-        char *orig = adstr;
-
-        // If the caller is lazy to compute the length, we do it for them.
-        if (!adlen)
-            len = strlen((const char *)ad);
-        else
-            len = adlen;
-
-        // Print the anondata within brackets. Hence, we need space for two
-        // brackets and a NULL byte.
-        if (len > (adstrlen - 3))
-            len = adstrlen - 3;
-
-        *adstr++ = '(';
-        mDNSPlatformMemCopy(adstr, ad, len);
-        adstr[len] = ')';
-        adstr[len+1] = 0;
-        return orig;
-    }
-    return adstr;
 }
 
-mDNSexport void LogMDNSStatistics(mDNS *const m)
+mDNSexport void LogMDNSStatisticsToFD(int fd, mDNS *const m)
 {
-    LogMsgNoIdent("--- MDNS Statistics ---");
-
-    LogMsgNoIdent("Name Conflicts                 %u", m->mDNSStats.NameConflicts);
-    LogMsgNoIdent("KnownUnique Name Conflicts     %u", m->mDNSStats.KnownUniqueNameConflicts);
-    LogMsgNoIdent("Duplicate Query Suppressions   %u", m->mDNSStats.DupQuerySuppressions);
-    LogMsgNoIdent("KA Suppressions                %u", m->mDNSStats.KnownAnswerSuppressions);
-    LogMsgNoIdent("KA Multiple Packets            %u", m->mDNSStats.KnownAnswerMultiplePkts);
-    LogMsgNoIdent("Poof Cache Deletions           %u", m->mDNSStats.PoofCacheDeletions);
-    LogMsgNoIdent("--------------------------------");
-
-    LogMsgNoIdent("Multicast packets Sent         %u", m->MulticastPacketsSent);
-    LogMsgNoIdent("Multicast packets Received     %u", m->MPktNum);
-    LogMsgNoIdent("Remote Subnet packets          %u", m->RemoteSubnet);
-    LogMsgNoIdent("QU questions  received         %u", m->mDNSStats.UnicastBitInQueries);
-    LogMsgNoIdent("Normal multicast questions     %u", m->mDNSStats.NormalQueries);
-    LogMsgNoIdent("Answers for questions          %u", m->mDNSStats.MatchingAnswersForQueries);
-    LogMsgNoIdent("Unicast responses              %u", m->mDNSStats.UnicastResponses);
-    LogMsgNoIdent("Multicast responses            %u", m->mDNSStats.MulticastResponses);
-    LogMsgNoIdent("Unicast response Demotions     %u", m->mDNSStats.UnicastDemotedToMulticast);
-    LogMsgNoIdent("--------------------------------");
-
-    LogMsgNoIdent("Sleeps                         %u", m->mDNSStats.Sleeps);
-    LogMsgNoIdent("Wakeups                        %u", m->mDNSStats.Wakes);
-    LogMsgNoIdent("Interface UP events            %u", m->mDNSStats.InterfaceUp);
-    LogMsgNoIdent("Interface UP Flap events       %u", m->mDNSStats.InterfaceUpFlap);
-    LogMsgNoIdent("Interface Down events          %u", m->mDNSStats.InterfaceDown);
-    LogMsgNoIdent("Interface DownFlap events      %u", m->mDNSStats.InterfaceDownFlap);
-    LogMsgNoIdent("Cache refresh queries          %u", m->mDNSStats.CacheRefreshQueries);
-    LogMsgNoIdent("Cache refreshed                %u", m->mDNSStats.CacheRefreshed);
-    LogMsgNoIdent("Wakeup on Resolves             %u", m->mDNSStats.WakeOnResolves);
+    LogToFD(fd, "--- MDNS Statistics ---");
+
+    LogToFD(fd, "Name Conflicts                 %u", m->mDNSStats.NameConflicts);
+    LogToFD(fd, "KnownUnique Name Conflicts     %u", m->mDNSStats.KnownUniqueNameConflicts);
+    LogToFD(fd, "Duplicate Query Suppressions   %u", m->mDNSStats.DupQuerySuppressions);
+    LogToFD(fd, "KA Suppressions                %u", m->mDNSStats.KnownAnswerSuppressions);
+    LogToFD(fd, "KA Multiple Packets            %u", m->mDNSStats.KnownAnswerMultiplePkts);
+    LogToFD(fd, "Poof Cache Deletions           %u", m->mDNSStats.PoofCacheDeletions);
+    LogToFD(fd, "--------------------------------");
+
+    LogToFD(fd, "Multicast packets Sent         %u", m->MulticastPacketsSent);
+    LogToFD(fd, "Multicast packets Received     %u", m->MPktNum);
+    LogToFD(fd, "Remote Subnet packets          %u", m->RemoteSubnet);
+    LogToFD(fd, "QU questions  received         %u", m->mDNSStats.UnicastBitInQueries);
+    LogToFD(fd, "Normal multicast questions     %u", m->mDNSStats.NormalQueries);
+    LogToFD(fd, "Answers for questions          %u", m->mDNSStats.MatchingAnswersForQueries);
+    LogToFD(fd, "Unicast responses              %u", m->mDNSStats.UnicastResponses);
+    LogToFD(fd, "Multicast responses            %u", m->mDNSStats.MulticastResponses);
+    LogToFD(fd, "Unicast response Demotions     %u", m->mDNSStats.UnicastDemotedToMulticast);
+    LogToFD(fd, "--------------------------------");
+
+    LogToFD(fd, "Sleeps                         %u", m->mDNSStats.Sleeps);
+    LogToFD(fd, "Wakeups                        %u", m->mDNSStats.Wakes);
+    LogToFD(fd, "Interface UP events            %u", m->mDNSStats.InterfaceUp);
+    LogToFD(fd, "Interface UP Flap events       %u", m->mDNSStats.InterfaceUpFlap);
+    LogToFD(fd, "Interface Down events          %u", m->mDNSStats.InterfaceDown);
+    LogToFD(fd, "Interface DownFlap events      %u", m->mDNSStats.InterfaceDownFlap);
+    LogToFD(fd, "Cache refresh queries          %u", m->mDNSStats.CacheRefreshQueries);
+    LogToFD(fd, "Cache refreshed                %u", m->mDNSStats.CacheRefreshed);
+    LogToFD(fd, "Wakeup on Resolves             %u", m->mDNSStats.WakeOnResolves);
 }
 
-mDNSexport void udsserver_info()
+mDNSexport void udsserver_info_dump_to_fd(int fd)
 {
     mDNS *const m = &mDNSStorage;
     const mDNSs32 now = mDNS_TimeNow(m);
@@ -5750,10 +4743,8 @@ mDNSexport void udsserver_info()
     const DNameListElem *d;
     const SearchListElem *s;
 
-    LogMsgNoIdent("Timenow 0x%08lX (%d)", (mDNSu32)now, now);
-
-    LogMsgNoIdent("------------ Cache -------------");
-    LogMsgNoIdent("Slt Q     TTL if     U Type rdlen");
+    LogToFD(fd, "------------ Cache -------------");
+    LogToFD(fd, "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)
@@ -5765,50 +4756,49 @@ mDNSexport void udsserver_info()
                 const char *ifname;
                 mDNSInterfaceID InterfaceID = cr->resrec.InterfaceID;
                 mDNSu32 *const countPtr = InterfaceID ? &mcastRecordCount : &ucastRecordCount;
-                if (!InterfaceID && cr->resrec.rDNSServer && (cr->resrec.rDNSServer->scopeType != kScopeNone))
+                if (!InterfaceID && cr->resrec.rDNSServer && cr->resrec.rDNSServer->scopeType)
                     InterfaceID = cr->resrec.rDNSServer->interface;
                 ifname = InterfaceNameForID(m, InterfaceID);
                 if (cr->CRActiveQuestion) CacheActive++;
-                PrintOneCacheRecord(cr, slot, remain, ifname, countPtr);
-                PrintCachedRecords(cr, slot, remain, ifname, countPtr);
+                PrintOneCacheRecordToFD(fd, cr, slot, remain, ifname, countPtr);
+                PrintCachedRecordsToFD(fd, cr, slot, remain, ifname, countPtr);
             }
         }
     }
 
     CacheUsed = groupCount + mcastRecordCount + ucastRecordCount;
     if (m->rrcache_totalused != CacheUsed)
-        LogMsgNoIdent("Cache use mismatch: rrcache_totalused is %lu, true count %lu", m->rrcache_totalused, CacheUsed);
+        LogToFD(fd, "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 size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
-        m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
+        LogToFD(fd, "Cache use mismatch: rrcache_active is %lu, true count %lu", m->rrcache_active, CacheActive);
+    LogToFD(fd, "Cache size %u entities; %u in use (%u group, %u multicast, %u unicast); %u referenced by active questions",
+              m->rrcache_size, CacheUsed, groupCount, mcastRecordCount, ucastRecordCount, CacheActive);
 
-    LogMsgNoIdent("--------- Auth Records ---------");
-    LogAuthRecords(now, m->ResourceRecords, mDNSNULL);
+    LogToFD(fd, "--------- Auth Records ---------");
+    LogAuthRecordsToFD(fd, now, m->ResourceRecords, mDNSNULL);
 
-    LogMsgNoIdent("--------- LocalOnly, P2P Auth Records ---------");
-    LogLocalOnlyAuthRecords(m);
+    LogToFD(fd, "--------- LocalOnly, P2P Auth Records ---------");
+    LogLocalOnlyAuthRecordsToFD(fd, m);
 
-    LogMsgNoIdent("--------- /etc/hosts ---------");
-    LogEtcHosts(m);
+    LogToFD(fd, "--------- /etc/hosts ---------");
+    LogEtcHostsToFD(fd, m);
 
-    LogMsgNoIdent("------ Duplicate Records -------");
-    LogAuthRecords(now, m->DuplicateRecords, mDNSNULL);
+    LogToFD(fd, "------ Duplicate Records -------");
+    LogAuthRecordsToFD(fd, now, m->DuplicateRecords, mDNSNULL);
 
-    LogMsgNoIdent("----- Auth Records Proxied -----");
-    LogAuthRecords(now, m->ResourceRecords, &ProxyA);
+    LogToFD(fd, "----- Auth Records Proxied -----");
+    LogAuthRecordsToFD(fd, now, m->ResourceRecords, &ProxyA);
 
-    LogMsgNoIdent("-- Duplicate Records Proxied ---");
-    LogAuthRecords(now, m->DuplicateRecords, &ProxyD);
+    LogToFD(fd, "-- Duplicate Records Proxied ---");
+    LogAuthRecordsToFD(fd, now, m->DuplicateRecords, &ProxyD);
 
-    LogMsgNoIdent("---------- Questions -----------");
-    if (!m->Questions) LogMsgNoIdent("<None>");
+    LogToFD(fd, "---------- Questions -----------");
+    if (!m->Questions) LogToFD(fd, "<None>");
     else
     {
-        char anonstr[256];
         CacheUsed = 0;
         CacheActive = 0;
-        LogMsgNoIdent("   Int  Next if     T  NumAns VDNS    Qptr     DupOf    SU SQ Type Name");
+        LogToFD(fd, "   Int  Next if     T NumAns VDNS                               Qptr               DupOf              SU SQ Type Name");
         for (q = m->Questions; q; q=q->next)
         {
             mDNSs32 i = q->ThisQInterval / mDNSPlatformOneSecond;
@@ -5816,29 +4806,29 @@ mDNSexport void udsserver_info()
             char *ifname = InterfaceNameForID(m, q->InterfaceID);
             CacheUsed++;
             if (q->ThisQInterval) CacheActive++;
-            LogMsgNoIdent("%6d%6d %-7s%s%s %5d 0x%x%x%x%x 0x%p 0x%p %1d %2d %-5s%##s%s%s",
-                          i, n,
-                          ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
-                          mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
-                          PrivateQuery(q)    ? "P" : q->ValidationRequired ? "V" : q->ValidatingResponse ? "R" : " ",
-                          q->CurrentAnswers, q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1],
-                          q->validDNSServers.l[0], q, q->DuplicateOf,
-                          q->SuppressUnusable, q->SuppressQuery, DNSTypeName(q->qtype), q->qname.c,
-                          AnonInfoToString(q->AnonInfo, anonstr, sizeof(anonstr)),
-                          q->DuplicateOf ? " (dup)" : "");
-        }
-        LogMsgNoIdent("%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
-    }
-
-    LogMsgNoIdent("----- LocalOnly, P2P Questions -----");
-    if (!m->LocalOnlyQuestions) LogMsgNoIdent("<None>");
+            LogToFD(fd, "%6d%6d %-7s%s%s %5d 0x%08x%08x%08x%08x 0x%p 0x%p %1d %2d  %-5s%##s%s",
+                      i, n,
+                      ifname ? ifname : mDNSOpaque16IsZero(q->TargetQID) ? "" : "-U-",
+                      mDNSOpaque16IsZero(q->TargetQID) ? (q->LongLived ? "l" : " ") : (q->LongLived ? "L" : "O"),
+                      q->ValidationRequired ? "V" : q->ValidatingResponse ? "R" : " ",
+                      q->CurrentAnswers,
+                      q->validDNSServers.l[3], q->validDNSServers.l[2], q->validDNSServers.l[1], q->validDNSServers.l[0],
+                      q, q->DuplicateOf,
+                      q->SuppressUnusable, q->Suppressed, DNSTypeName(q->qtype), q->qname.c,
+                      q->DuplicateOf ? " (dup)" : "");
+        }
+        LogToFD(fd, "%lu question%s; %lu active", CacheUsed, CacheUsed > 1 ? "s" : "", CacheActive);
+    }
+
+    LogToFD(fd, "----- LocalOnly, P2P Questions -----");
+    if (!m->LocalOnlyQuestions) LogToFD(fd, "<None>");
     else for (q = m->LocalOnlyQuestions; q; q=q->next)
-            LogMsgNoIdent("                 %3s   %5d  %-6s%##s%s",
-                          q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P",
-                          q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
+        LogToFD(fd, "                 %3s   %5d  %-6s%##s%s",
+                  q->InterfaceID == mDNSInterface_LocalOnly ? "LO ": q->InterfaceID == mDNSInterface_BLE ? "BLE": "P2P",
+                  q->CurrentAnswers, DNSTypeName(q->qtype), q->qname.c, q->DuplicateOf ? " (dup)" : "");
 
-    LogMsgNoIdent("---- Active UDS Client Requests ----");
-    if (!all_requests) LogMsgNoIdent("<None>");
+    LogToFD(fd, "---- Active UDS Client Requests ----");
+    if (!all_requests) LogToFD(fd, "<None>");
     else
     {
         request_state *req, *r;
@@ -5847,109 +4837,96 @@ mDNSexport void udsserver_info()
             if (req->primary)   // If this is a subbordinate operation, check that the parent is in the list
             {
                 for (r = all_requests; r && r != req; r=r->next) if (r == req->primary) goto foundparent;
-                LogMsgNoIdent("%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
+                LogToFD(fd, "%3d: Orhpan operation %p; parent %p not found in request list", req->sd);
             }
             // For non-subbordinate operations, and subbordinate operations that have lost their parent, write out their info
-            LogClientInfo(req);
-foundparent:;
+            LogClientInfoToFD(fd, req);
+        foundparent:;
         }
     }
-    
-    LogMsgNoIdent("-------- NAT Traversals --------");
-    LogMsgNoIdent("ExtAddress %.4a Retry %d Interval %d",
-                  &m->ExtAddress,
-                  m->retryGetAddr ? (m->retryGetAddr - now) / mDNSPlatformOneSecond : 0,
-                  m->retryIntervalGetAddr / mDNSPlatformOneSecond);
+
+    LogToFD(fd, "-------- NAT Traversals --------");
+    LogToFD(fd, "ExtAddress %.4a Retry %d Interval %d",
+              &m->ExtAddress,
+              m->retryGetAddr ? (m->retryGetAddr - now) / mDNSPlatformOneSecond : 0,
+              m->retryIntervalGetAddr / mDNSPlatformOneSecond);
     if (m->NATTraversals)
     {
         const NATTraversalInfo *nat;
         for (nat = m->NATTraversals; nat; nat=nat->next)
         {
-            LogMsgNoIdent("%p %s Int %5d %s Err %d Retry %5d Interval %5d Expire %5d Req %.4a:%d Ext %.4a:%d",
-                          nat,
-                          nat->Protocol ? (nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP") : "ADD",
-                          mDNSVal16(nat->IntPort),
-                          (nat->lastSuccessfulProtocol == NATTProtocolNone    ? "None    " :
-                           nat->lastSuccessfulProtocol == NATTProtocolNATPMP  ? "NAT-PMP " :
-                           nat->lastSuccessfulProtocol == NATTProtocolUPNPIGD ? "UPnP/IGD" :
-                           nat->lastSuccessfulProtocol == NATTProtocolPCP     ? "PCP     " :
-                           /* else */                                           "Unknown " ),
-                          nat->Result,
-                          nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
-                          nat->retryInterval / mDNSPlatformOneSecond,
-                          nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
-                          &nat->NewAddress, mDNSVal16(nat->RequestedPort),
-                          &nat->ExternalAddress, mDNSVal16(nat->ExternalPort));
-        }
-    }
-
-    LogMsgNoIdent("--------- AuthInfoList ---------");
-    if (!m->AuthInfoList) LogMsgNoIdent("<None>");
+            LogToFD(fd, "%p %s Int %5d %s Err %d Retry %5d Interval %5d Expire %5d Req %.4a:%d Ext %.4a:%d",
+                      nat,
+                      nat->Protocol ? (nat->Protocol == NATOp_MapTCP ? "TCP" : "UDP") : "ADD",
+                      mDNSVal16(nat->IntPort),
+                      (nat->lastSuccessfulProtocol == NATTProtocolNone    ? "None    " :
+                       nat->lastSuccessfulProtocol == NATTProtocolNATPMP  ? "NAT-PMP " :
+                       nat->lastSuccessfulProtocol == NATTProtocolUPNPIGD ? "UPnP/IGD" :
+                       nat->lastSuccessfulProtocol == NATTProtocolPCP     ? "PCP     " :
+                       /* else */                                           "Unknown " ),
+                      nat->Result,
+                      nat->retryPortMap ? (nat->retryPortMap - now) / mDNSPlatformOneSecond : 0,
+                      nat->retryInterval / mDNSPlatformOneSecond,
+                      nat->ExpiryTime ? (nat->ExpiryTime - now) / mDNSPlatformOneSecond : 0,
+                      &nat->NewAddress, mDNSVal16(nat->RequestedPort),
+                      &nat->ExternalAddress, mDNSVal16(nat->ExternalPort));
+        }
+    }
+
+    LogToFD(fd, "--------- AuthInfoList ---------");
+    if (!m->AuthInfoList) LogToFD(fd, "<None>");
     else
     {
         const DomainAuthInfo *a;
         for (a = m->AuthInfoList; a; a = a->next)
         {
-            LogMsgNoIdent("%##s %##s %##s %d %d %.16a%s",
-                          a->domain.c, a->keyname.c,
-                          a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]),
-                          (a->deltime ? (a->deltime - now) : 0),
-                          &a->AutoTunnelInnerAddress, a->AutoTunnel ? " AutoTunnel" : "");
+            LogToFD(fd, "%##s %##s %##s %d %d",
+                      a->domain.c, a->keyname.c,
+                      a->hostname.c, (a->port.b[0] << 8 | a->port.b[1]),
+                      (a->deltime ? (a->deltime - now) : 0));
         }
     }
 
-    #if APPLE_OSX_mDNSResponder
-    LogMsgNoIdent("--------- TunnelClients --------");
-    if (!m->TunnelClients) LogMsgNoIdent("<None>");
-    else
-    {
-        const ClientTunnel *c;
-        for (c = m->TunnelClients; c; c = c->next)
-            LogMsgNoIdent("%##s local %.16a %.4a %.16a remote %.16a %.4a %5d %.16a interval %d",
-                          c->dstname.c, &c->loc_inner, &c->loc_outer, &c->loc_outer6, &c->rmt_inner, &c->rmt_outer, mDNSVal16(c->rmt_outer_port), &c->rmt_outer6, c->q.ThisQInterval);
-    }
-    #endif // APPLE_OSX_mDNSResponder
+    LogToFD(fd, "---------- Misc State ----------");
 
-    LogMsgNoIdent("---------- Misc State ----------");
+    LogToFD(fd, "PrimaryMAC:   %.6a", &m->PrimaryMAC);
 
-    LogMsgNoIdent("PrimaryMAC:   %.6a", &m->PrimaryMAC);
+    LogToFD(fd, "m->SleepState %d (%s) seq %d",
+              m->SleepState,
+              m->SleepState == SleepState_Awake        ? "Awake"        :
+              m->SleepState == SleepState_Transferring ? "Transferring" :
+              m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?",
+              m->SleepSeqNum);
 
-    LogMsgNoIdent("m->SleepState %d (%s) seq %d",
-                  m->SleepState,
-                  m->SleepState == SleepState_Awake        ? "Awake"        :
-                  m->SleepState == SleepState_Transferring ? "Transferring" :
-                  m->SleepState == SleepState_Sleeping     ? "Sleeping"     : "?",
-                  m->SleepSeqNum);
-
-    if (!m->SPSSocket) LogMsgNoIdent("Not offering Sleep Proxy Service");
+    if (!m->SPSSocket) LogToFD(fd, "Not offering Sleep Proxy Service");
 #ifndef SPC_DISABLED
-    else LogMsgNoIdent("Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
+    else LogToFD(fd, "Offering Sleep Proxy Service: %#s", m->SPSRecords.RR_SRV.resrec.name->c);
 #endif
-    if (m->ProxyRecords == ProxyA + ProxyD) LogMsgNoIdent("ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
-    else LogMsgNoIdent("ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
+    if (m->ProxyRecords == ProxyA + ProxyD) LogToFD(fd, "ProxyRecords: %d + %d = %d", ProxyA, ProxyD, ProxyA + ProxyD);
+    else LogToFD(fd, "ProxyRecords: MISMATCH %d + %d = %d ≠ %d", ProxyA, ProxyD, ProxyA + ProxyD, m->ProxyRecords);
 
-    LogMsgNoIdent("------ Auto Browse Domains -----");
-    if (!AutoBrowseDomains) LogMsgNoIdent("<None>");
-    else for (d=AutoBrowseDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+    LogToFD(fd, "------ Auto Browse Domains -----");
+    if (!AutoBrowseDomains) LogToFD(fd, "<None>");
+    else for (d=AutoBrowseDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
 
-    LogMsgNoIdent("--- Auto Registration Domains --");
-    if (!AutoRegistrationDomains) LogMsgNoIdent("<None>");
-    else for (d=AutoRegistrationDomains; d; d=d->next) LogMsgNoIdent("%##s", d->name.c);
+    LogToFD(fd, "--- Auto Registration Domains --");
+    if (!AutoRegistrationDomains) LogToFD(fd, "<None>");
+    else for (d=AutoRegistrationDomains; d; d=d->next) LogToFD(fd, "%##s", d->name.c);
 
-    LogMsgNoIdent("--- Search Domains --");
-    if (!SearchList) LogMsgNoIdent("<None>");
+    LogToFD(fd, "--- Search Domains --");
+    if (!SearchList) LogToFD(fd, "<None>");
     else
     {
         for (s=SearchList; s; s=s->next)
         {
             char *ifname = InterfaceNameForID(m, s->InterfaceID);
-            LogMsgNoIdent("%##s %s", s->domain.c, ifname ? ifname : "");
+            LogToFD(fd, "%##s %s", s->domain.c, ifname ? ifname : "");
         }
     }
-    LogInfo("--- Trust Anchors ---");
+    LogToFD(fd, "--- Trust Anchors ---");
     if (!m->TrustAnchors)
     {
-        LogInfo("<None>");
+        LogToFD(fd, "<None>");
     }
     else
     {
@@ -5961,117 +4938,121 @@ foundparent:;
         {
             mDNSPlatformFormatTime((unsigned long)ta->validFrom, fromTimeBuf, sizeof(fromTimeBuf));
             mDNSPlatformFormatTime((unsigned long)ta->validUntil, untilTimeBuf, sizeof(untilTimeBuf));
-            LogInfo("%##s %d %d %d %d %s %s", ta->zone.c, ta->rds.keyTag,
-                ta->rds.alg, ta->rds.digestType, ta->digestLen, fromTimeBuf, untilTimeBuf);
+            LogToFD(fd, "%##s %d %d %d %d %s %s", ta->zone.c, ta->rds.keyTag,
+                      ta->rds.alg, ta->rds.digestType, ta->digestLen, fromTimeBuf, untilTimeBuf);
         }
     }
 
-    LogInfo("--- DNSSEC Statistics ---");
+    LogToFD(fd, "--- DNSSEC Statistics ---");
 
-    LogMsgNoIdent("Unicast Cache size              %u", m->rrcache_totalused_unicast);
-    LogInfo("DNSSEC  Cache size              %u", m->DNSSECStats.TotalMemUsed);
+    LogToFD(fd, "Unicast Cache size              %u", m->rrcache_totalused_unicast);
+    LogToFD(fd, "DNSSEC  Cache size              %u", m->DNSSECStats.TotalMemUsed);
     if (m->rrcache_totalused_unicast)
-        LogInfo("DNSSEC  usage percentage        %u", ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
-    LogInfo("DNSSEC  Extra Packets (0 to 2)  %u", m->DNSSECStats.ExtraPackets0);
-    LogInfo("DNSSEC  Extra Packets (3 to 6)  %u", m->DNSSECStats.ExtraPackets3);
-    LogInfo("DNSSEC  Extra Packets (7 to 9)  %u", m->DNSSECStats.ExtraPackets7);
-    LogInfo("DNSSEC  Extra Packets ( >= 10)  %u", m->DNSSECStats.ExtraPackets10);
-
-    LogInfo("DNSSEC  Latency (0 to 4ms)      %u", m->DNSSECStats.Latency0);
-    LogInfo("DNSSEC  Latency (4 to 9ms)      %u", m->DNSSECStats.Latency5);
-    LogInfo("DNSSEC  Latency (10 to 19ms)    %u", m->DNSSECStats.Latency10);
-    LogInfo("DNSSEC  Latency (20 to 49ms)    %u", m->DNSSECStats.Latency20);
-    LogInfo("DNSSEC  Latency (50 to 99ms)    %u", m->DNSSECStats.Latency50);
-    LogInfo("DNSSEC  Latency (   >=100ms)    %u", m->DNSSECStats.Latency100);
-
-    LogInfo("DNSSEC  Secure Status           %u", m->DNSSECStats.SecureStatus);
-    LogInfo("DNSSEC  Insecure Status         %u", m->DNSSECStats.InsecureStatus);
-    LogInfo("DNSSEC  Indeterminate Status    %u", m->DNSSECStats.IndeterminateStatus);
-    LogInfo("DNSSEC  Bogus Status            %u", m->DNSSECStats.BogusStatus);
-    LogInfo("DNSSEC  NoResponse Status       %u", m->DNSSECStats.NoResponseStatus);
-    LogInfo("DNSSEC  Probes sent             %u", m->DNSSECStats.NumProbesSent);
-    LogInfo("DNSSEC  Msg Size (<=1024)       %u", m->DNSSECStats.MsgSize0);
-    LogInfo("DNSSEC  Msg Size (<=2048)       %u", m->DNSSECStats.MsgSize1);
-    LogInfo("DNSSEC  Msg Size (> 2048)       %u", m->DNSSECStats.MsgSize2);
-
-    LogMDNSStatistics(m);
-
-    LogMsgNoIdent("---- Task Scheduling Timers ----");
-
-#if BONJOUR_ON_DEMAND
-    LogMsgNoIdent("BonjourEnabled %d", m->BonjourEnabled);
-#endif // BONJOUR_ON_DEMAND
+        LogToFD(fd, "DNSSEC  usage percentage        %u", ((unsigned long)(m->DNSSECStats.TotalMemUsed * 100))/m->rrcache_totalused_unicast);
+    LogToFD(fd, "DNSSEC  Extra Packets (0 to 2)  %u", m->DNSSECStats.ExtraPackets0);
+    LogToFD(fd, "DNSSEC  Extra Packets (3 to 6)  %u", m->DNSSECStats.ExtraPackets3);
+    LogToFD(fd, "DNSSEC  Extra Packets (7 to 9)  %u", m->DNSSECStats.ExtraPackets7);
+    LogToFD(fd, "DNSSEC  Extra Packets ( >= 10)  %u", m->DNSSECStats.ExtraPackets10);
+
+    LogToFD(fd, "DNSSEC  Latency (0 to 4ms)      %u", m->DNSSECStats.Latency0);
+    LogToFD(fd, "DNSSEC  Latency (4 to 9ms)      %u", m->DNSSECStats.Latency5);
+    LogToFD(fd, "DNSSEC  Latency (10 to 19ms)    %u", m->DNSSECStats.Latency10);
+    LogToFD(fd, "DNSSEC  Latency (20 to 49ms)    %u", m->DNSSECStats.Latency20);
+    LogToFD(fd, "DNSSEC  Latency (50 to 99ms)    %u", m->DNSSECStats.Latency50);
+    LogToFD(fd, "DNSSEC  Latency (   >=100ms)    %u", m->DNSSECStats.Latency100);
+
+    LogToFD(fd, "DNSSEC  Secure Status           %u", m->DNSSECStats.SecureStatus);
+    LogToFD(fd, "DNSSEC  Insecure Status         %u", m->DNSSECStats.InsecureStatus);
+    LogToFD(fd, "DNSSEC  Indeterminate Status    %u", m->DNSSECStats.IndeterminateStatus);
+    LogToFD(fd, "DNSSEC  Bogus Status            %u", m->DNSSECStats.BogusStatus);
+    LogToFD(fd, "DNSSEC  NoResponse Status       %u", m->DNSSECStats.NoResponseStatus);
+    LogToFD(fd, "DNSSEC  Probes sent             %u", m->DNSSECStats.NumProbesSent);
+    LogToFD(fd, "DNSSEC  Msg Size (<=1024)       %u", m->DNSSECStats.MsgSize0);
+    LogToFD(fd, "DNSSEC  Msg Size (<=2048)       %u", m->DNSSECStats.MsgSize1);
+    LogToFD(fd, "DNSSEC  Msg Size (> 2048)       %u", m->DNSSECStats.MsgSize2);
+
+    LogMDNSStatisticsToFD(fd, m);
+
+    LogToFD(fd, "---- Task Scheduling Timers ----");
+
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+    LogToFD(fd, "BonjourEnabled %d", m->BonjourEnabled);
+#endif
 
 #if APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
-    LogMsgNoIdent("EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
-    LogMsgNoIdent("DefaultToBLETriggered %d", DefaultToBLETriggered);
+    LogToFD(fd, "EnableBLEBasedDiscovery %d", EnableBLEBasedDiscovery);
+    LogToFD(fd, "DefaultToBLETriggered %d", DefaultToBLETriggered);
 #endif // APPLE_OSX_mDNSResponder && ENABLE_BLE_TRIGGERED_BONJOUR
 
     if (!m->NewQuestions)
-        LogMsgNoIdent("NewQuestion <NONE>");
+        LogToFD(fd, "NewQuestion <NONE>");
     else
-        LogMsgNoIdent("NewQuestion DelayAnswering %d %d %##s (%s)",
-                      m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
-                      m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
+        LogToFD(fd, "NewQuestion DelayAnswering %d %d %##s (%s)",
+                  m->NewQuestions->DelayAnswering, m->NewQuestions->DelayAnswering-now,
+                  m->NewQuestions->qname.c, DNSTypeName(m->NewQuestions->qtype));
 
     if (!m->NewLocalOnlyQuestions)
-        LogMsgNoIdent("NewLocalOnlyQuestions <NONE>");
+        LogToFD(fd, "NewLocalOnlyQuestions <NONE>");
     else
-        LogMsgNoIdent("NewLocalOnlyQuestions %##s (%s)",
-                      m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
+        LogToFD(fd, "NewLocalOnlyQuestions %##s (%s)",
+                  m->NewLocalOnlyQuestions->qname.c, DNSTypeName(m->NewLocalOnlyQuestions->qtype));
 
     if (!m->NewLocalRecords)
-        LogMsgNoIdent("NewLocalRecords <NONE>");
+        LogToFD(fd, "NewLocalRecords <NONE>");
     else
-        LogMsgNoIdent("NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
-
-    LogMsgNoIdent("SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
-    LogMsgNoIdent("LocalRemoveEvents%s",   m->LocalRemoveEvents   ? "" : " <NONE>");
-    LogMsgNoIdent("m->AutoTunnelRelayAddr %.16a", &m->AutoTunnelRelayAddr);
-    LogMsgNoIdent("m->WABBrowseQueriesCount %d", m->WABBrowseQueriesCount);
-    LogMsgNoIdent("m->WABLBrowseQueriesCount %d", m->WABLBrowseQueriesCount);
-    LogMsgNoIdent("m->WABRegQueriesCount %d", m->WABRegQueriesCount);
-    LogMsgNoIdent("m->AutoTargetServices %d", m->AutoTargetServices);
+        LogToFD(fd, "NewLocalRecords %02X %s", m->NewLocalRecords->resrec.RecordType, ARDisplayString(m, m->NewLocalRecords));
+
+    LogToFD(fd, "SPSProxyListChanged%s", m->SPSProxyListChanged ? "" : " <NONE>");
+    LogToFD(fd, "LocalRemoveEvents%s",   m->LocalRemoveEvents   ? "" : " <NONE>");
+    LogToFD(fd, "m->WABBrowseQueriesCount %d", m->WABBrowseQueriesCount);
+    LogToFD(fd, "m->WABLBrowseQueriesCount %d", m->WABLBrowseQueriesCount);
+    LogToFD(fd, "m->WABRegQueriesCount %d", m->WABRegQueriesCount);
+    LogToFD(fd, "m->AutoTargetServices %u", m->AutoTargetServices);
+#if MDNSRESPONDER_SUPPORTS(APPLE, RANDOM_AWDL_HOSTNAME)
+    LogToFD(fd, "m->AutoTargetAWDLIncludedCount %u", m->AutoTargetAWDLIncludedCount);
+    LogToFD(fd, "m->AutoTargetAWDLOnlyCount     %u", m->AutoTargetAWDLOnlyCount);
+#endif
 
-    LogMsgNoIdent("                         ABS (hex)  ABS (dec)  REL (hex)  REL (dec)");
-    LogMsgNoIdent("m->timenow               %08X %11d", now, now);
-    LogMsgNoIdent("m->timenow_adjust        %08X %11d", m->timenow_adjust, m->timenow_adjust);
-    LogTimer("m->NextScheduledEvent   ", m->NextScheduledEvent);
+    LogToFD(fd, "                         ABS (hex)  ABS (dec)  REL (hex)  REL (dec)");
+    LogToFD(fd, "m->timenow               %08X %11d", now, now);
+    LogToFD(fd, "m->timenow_adjust        %08X %11d", m->timenow_adjust, m->timenow_adjust);
+    LogTimerToFD(fd, "m->NextScheduledEvent   ", m->NextScheduledEvent);
 
 #ifndef UNICAST_DISABLED
-    LogTimer("m->NextuDNSEvent        ", m->NextuDNSEvent);
-    LogTimer("m->NextSRVUpdate        ", m->NextSRVUpdate);
-    LogTimer("m->NextScheduledNATOp   ", m->NextScheduledNATOp);
-    LogTimer("m->retryGetAddr         ", m->retryGetAddr);
+    LogTimerToFD(fd, "m->NextuDNSEvent        ", m->NextuDNSEvent);
+    LogTimerToFD(fd, "m->NextSRVUpdate        ", m->NextSRVUpdate);
+    LogTimerToFD(fd, "m->NextScheduledNATOp   ", m->NextScheduledNATOp);
+    LogTimerToFD(fd, "m->retryGetAddr         ", m->retryGetAddr);
 #endif
 
-    LogTimer("m->NextCacheCheck       ", m->NextCacheCheck);
-    LogTimer("m->NextScheduledSPS     ", m->NextScheduledSPS);
-    LogTimer("m->NextScheduledKA      ", m->NextScheduledKA);
+    LogTimerToFD(fd, "m->NextCacheCheck       ", m->NextCacheCheck);
+    LogTimerToFD(fd, "m->NextScheduledSPS     ", m->NextScheduledSPS);
+    LogTimerToFD(fd, "m->NextScheduledKA      ", m->NextScheduledKA);
 
-#if BONJOUR_ON_DEMAND
-    LogTimer("m->NextBonjourDisableTime ", m->NextBonjourDisableTime);
-#endif // BONJOUR_ON_DEMAND
+#if MDNSRESPONDER_SUPPORTS(APPLE, BONJOUR_ON_DEMAND)
+    LogTimerToFD(fd, "m->NextBonjourDisableTime ", m->NextBonjourDisableTime);
+#endif
 
-    LogTimer("m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
-    LogTimer("m->DelaySleep           ", m->DelaySleep);
+    LogTimerToFD(fd, "m->NextScheduledSPRetry ", m->NextScheduledSPRetry);
+    LogTimerToFD(fd, "m->DelaySleep           ", m->DelaySleep);
 
-    LogTimer("m->NextScheduledQuery   ", m->NextScheduledQuery);
-    LogTimer("m->NextScheduledProbe   ", m->NextScheduledProbe);
-    LogTimer("m->NextScheduledResponse", m->NextScheduledResponse);
+    LogTimerToFD(fd, "m->NextScheduledQuery   ", m->NextScheduledQuery);
+    LogTimerToFD(fd, "m->NextScheduledProbe   ", m->NextScheduledProbe);
+    LogTimerToFD(fd, "m->NextScheduledResponse", m->NextScheduledResponse);
 
-    LogTimer("m->SuppressSending      ", m->SuppressSending);
-    LogTimer("m->SuppressProbes       ", m->SuppressProbes);
-    LogTimer("m->ProbeFailTime        ", m->ProbeFailTime);
-    LogTimer("m->DelaySleep           ", m->DelaySleep);
-    LogTimer("m->SleepLimit           ", m->SleepLimit);
-    LogTimer("m->NextScheduledStopTime ", m->NextScheduledStopTime);
+    LogTimerToFD(fd, "m->SuppressSending      ", m->SuppressSending);
+    LogTimerToFD(fd, "m->SuppressProbes       ", m->SuppressProbes);
+    LogTimerToFD(fd, "m->ProbeFailTime        ", m->ProbeFailTime);
+    LogTimerToFD(fd, "m->DelaySleep           ", m->DelaySleep);
+    LogTimerToFD(fd, "m->SleepLimit           ", m->SleepLimit);
+    LogTimerToFD(fd, "m->NextScheduledStopTime ", m->NextScheduledStopTime);
 }
 
-#if APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
-mDNSexport void uds_validatelists(void)
+#if MDNS_MALLOC_DEBUGGING
+mDNSlocal void udsserver_validatelists(void *context)
 {
     const request_state *req, *p;
+       (void)context; // unused
     for (req = all_requests; req; req=req->next)
     {
         if (req->next == (request_state *)~0 || (req->sd < 0 && req->sd != -2))
@@ -6136,7 +5117,7 @@ mDNSexport void uds_validatelists(void)
         if (d->next == (DNameListElem *)~0 || d->name.c[0] > 63)
             LogMemCorruption("AutoRegistrationDomains: %p is garbage (%d)", d, d->name.c[0]);
 }
-#endif // APPLE_OSX_mDNSResponder && MACOSX_MDNS_MALLOC_DEBUGGING
+#endif // MDNS_MALLOC_DEBUGGING
 
 mDNSlocal int send_msg(request_state *const req)
 {
@@ -6221,6 +5202,8 @@ mDNSexport mDNSs32 udsserver_idle(mDNSs32 nextevent)
             if (nextevent - now > mDNSPlatformOneSecond)
                 nextevent = now + mDNSPlatformOneSecond;
 
+            LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_INFO,
+               "[R%u] Could not send all replies. Will try again in %d ticks.", r->request_id, nextevent - now);
             if (mDNSStorage.SleepState != SleepState_Awake)
                 r->time_blocked = 0;
             else if (!r->time_blocked)
index dc7d9ac26beac939ab461e5c291b97dff2460174..99ec9040102c939de5c9eb2067444f01b40daed8 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 4 -*-
  *
- * Copyright (c) 2002-2013 Apple Inc. All rights reserved.
+ * Copyright (c) 2002-2018 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.
@@ -20,6 +20,7 @@
 
 #include "mDNSEmbeddedAPI.h"
 #include "dnssd_ipc.h"
+#include "ClientRequests.h"
 
 /* Client request: */
 
@@ -98,6 +99,7 @@ struct request_state
        mDNSBool validUUID;
        dnssd_sock_t errsd;
        mDNSu32 uid;
+    mDNSu32 request_id;
        void * platform_data;
 
        // Note: On a shared connection these fields in the primary structure, including hdr, are re-used
@@ -130,7 +132,6 @@ struct request_state
                        mDNSBool ForceMCast;
                        domainname regtype;
                        browser_t *browsers;
-                       const mDNSu8 *AnonData;
                } browser;
                struct
                {
@@ -147,22 +148,9 @@ struct request_state
                        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;
-                       mDNSBool AnonData;
                        service_instance *instances;
                } servicereg;
                struct
-               {
-                       mDNSInterfaceID interface_id;
-                       mDNSu32 flags;
-                       mDNSu32 protocol;
-                       DNSQuestion q4;
-                       DNSQuestion *q42;
-                       DNSQuestion q6;
-                       DNSQuestion *q62;
-                       mDNSu8 v4ans;
-                       mDNSu8 v6ans;
-               } addrinfo;
-               struct
                {
                        mDNSIPPort ReqExt;              // External port we originally requested, for logging purposes
                        NATTraversalInfo NATinfo;
@@ -175,12 +163,6 @@ struct request_state
                        DNSQuestion q_autoall;
                } enumeration;
                struct
-               {
-                       DNSQuestion q;
-                       DNSQuestion *q2;
-                       mDNSu8 ans;
-               } queryrecord;
-               struct
                {
                        DNSQuestion qtxt;
                        DNSQuestion qsrv;
@@ -189,6 +171,8 @@ struct request_state
                        mDNSs32 ReportTime;
                        mDNSBool external_advertise;
                } resolve;
+        GetAddrInfoClientRequest addrinfo;
+        QueryRecordClientRequest queryrecord;
        } u;
 };
 
@@ -213,11 +197,11 @@ typedef struct reply_state
 
 #define SRS_PORT(S) mDNSVal16((S)->RR_SRV.resrec.rdata->u.srv.port)
 
-#define LogTimer(MSG,T) LogMsgNoIdent( MSG " %08X %11d  %08X %11d", (T), (T), (T)-now, (T)-now)
+#define LogTimerToFD(FILE_DESCRIPTOR, MSG, T) LogToFD((FILE_DESCRIPTOR), MSG " %08X %11d  %08X %11d", (T), (T), (T)-now, (T)-now)
 
 extern int udsserver_init(dnssd_sock_t skts[], mDNSu32 count);
 extern mDNSs32 udsserver_idle(mDNSs32 nextevent);
-extern void udsserver_info(void);  // print out info about current state
+extern void udsserver_info_dump_to_fd(int fd);
 extern void udsserver_handle_configchange(mDNS *const m);
 extern int udsserver_exit(void);    // should be called prior to app exit
 extern void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog);
@@ -228,7 +212,7 @@ extern void LogMcastStateInfo(mDNSBool mflag, mDNSBool start, mDNSBool mstatelog
 
 /* Routines that uds_daemon expects to link against: */
 
-typedef void (*udsEventCallback)(int fd, short filter, void *context);
+typedef void (*udsEventCallback)(int fd, void *context);
 extern mStatus udsSupportAddFDToEventLoop(dnssd_sock_t fd, udsEventCallback callback, void *context, void **platform_data);
 extern int     udsSupportReadFD(dnssd_sock_t fd, char* buf, int len, int flags, void *platform_data);
 extern mStatus udsSupportRemoveFDFromEventLoop(dnssd_sock_t fd, void *platform_data); // Note: This also CLOSES the file descriptor as well
@@ -241,36 +225,10 @@ extern mDNS mDNSStorage;
 extern DNameListElem *AutoRegistrationDomains;
 extern DNameListElem *AutoBrowseDomains;
 
-extern mDNSs32 ChopSubTypes(char *regtype, char **AnonData);
-extern AuthRecord *AllocateSubTypes(mDNSs32 NumSubTypes, char *p, char **AnonData);
 extern int CountExistingRegistrations(domainname *srv, mDNSIPPort port);
-extern mDNSBool callExternalHelpers(mDNSInterfaceID InterfaceID, const domainname *const domain, DNSServiceFlags flags);
 extern void FreeExtraRR(mDNS *const m, AuthRecord *const rr, mStatus result);
 extern int CountPeerRegistrations(ServiceRecordSet *const srs);
 
-#if APPLE_OSX_mDNSResponder
-
-// D2D interface support
-extern void external_start_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void external_stop_browsing_for_service(mDNSInterfaceID InterfaceID, const domainname *const type, DNS_TypeValues qtype, DNSServiceFlags flags);
-extern void external_start_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void external_stop_advertising_service(const ResourceRecord *const resourceRecord, DNSServiceFlags flags);
-extern void external_start_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
-extern void external_stop_resolving_service(mDNSInterfaceID InterfaceID, const domainname *const fqdn, DNSServiceFlags flags);
-extern void external_connection_release(const domainname *instance);
-
-#else   // APPLE_OSX_mDNSResponder
-
-#define external_start_browsing_for_service(A,B,C,D) (void)(A)
-#define external_stop_browsing_for_service(A,B,C,D)  (void)(A)
-#define external_start_advertising_service(A,B)      (void)(A)
-#define external_stop_advertising_service(A,B)       do { (void)(A); (void)(B); } while (0)
-#define external_start_resolving_service(A,B,C)      (void)(A)
-#define external_stop_resolving_service(A,B,C)       (void)(A)
-#define external_connection_release(A)               (void)(A)
-
-#endif // APPLE_OSX_mDNSResponder
-
 extern const char mDNSResponderVersionString_SCCS[];
 #define mDNSResponderVersionString (mDNSResponderVersionString_SCCS+5)
 
diff --git a/mDNSVxWorks/README.txt b/mDNSVxWorks/README.txt
deleted file mode 100644 (file)
index f0ea01e..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-These are the platform support files for running mDNSCore on VxWorks.
-
-Please note, most of the developers working on the mDNSResponder code do
-not have access to a VxWorks development environment, so they are not able
-to personally verify that the VxWorks compiles and runs successfully after
-every single change to the mDNSCore code. We do try to take care not to
-make careless changes that would break the VxWorks build, but if you do
-find that something is broken, let us know and we'll fix it.
diff --git a/mDNSVxWorks/mDNSVxWorks.c b/mDNSVxWorks/mDNSVxWorks.c
deleted file mode 100644 (file)
index 2e9ca1b..0000000
+++ /dev/null
@@ -1,2147 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2005 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.
- */
-
-#if 0
-#pragma mark == Configuration ==
-#endif
-
-//===========================================================================================================================
-//     Configuration
-//===========================================================================================================================
-
-#define DEBUG_NAME                          "[mDNS] "
-#define MDNS_AAAA_OVER_IPV4                 1   // 1=Send AAAA & A records over IPv4 & IPv6, 0=Send AAAA over IPv6, A over IPv4.
-#define MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6     1   // 1=Don't use IPv6 socket if non-link-local IPv4 available on same interface.
-#define MDNS_ENABLE_PPP                     0   // 1=Enable Unicast DNS over PPP interfaces. 0=Don't enable it.
-#define MDNS_DEBUG_PACKETS                  1   // 1=Enable debug output for packet send/recv if debug level high enough.
-#define MDNS_DEBUG_SHOW                     1   // 1=Enable console show routines.
-#define DEBUG_USE_DEFAULT_CATEGORY          1   // Set up to use the default category (see DebugServices.h for details).
-
-#include    <stdarg.h>
-#include    <stddef.h>
-#include    <stdio.h>
-#include    <stdlib.h>
-#include    <string.h>
-#include    <time.h>
-
-#include    "vxWorks.h"
-#include    "config.h"
-
-#include    <sys/types.h>
-
-#include    <arpa/inet.h>
-#include    <net/if.h>
-#include    <net/if_dl.h>
-#include    <net/if_types.h>
-#include    <net/ifaddrs.h>
-#include    <netinet6/in6_var.h>
-#include    <netinet/if_ether.h>
-#include    <netinet/in.h>
-#include    <netinet/ip.h>
-#include    <sys/ioctl.h>
-#include    <sys/socket.h>
-#include    <unistd.h>
-
-#include    "ifLib.h"
-#include    "inetLib.h"
-#include    "pipeDrv.h"
-#include    "selectLib.h"
-#include    "semLib.h"
-#include    "sockLib.h"
-#include    "sysLib.h"
-#include    "taskLib.h"
-#include    "tickLib.h"
-
-#include    "CommonServices.h"
-#include    "DebugServices.h"
-#include    "DNSCommon.h"
-#include    "mDNSEmbeddedAPI.h"
-
-#include    "mDNSVxWorks.h"
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-typedef uint8_t MDNSPipeCommandCode;
-
-#define kMDNSPipeCommandCodeInvalid         0
-#define kMDNSPipeCommandCodeReschedule      1
-#define kMDNSPipeCommandCodeReconfigure     2
-#define kMDNSPipeCommandCodeQuit            3
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-#if ( DEBUG )
-mDNSlocal void  DebugMsg( DebugLevel inLevel, const char *inFormat, ... );
-
-    #define dmsg( LEVEL, ARGS... )  DebugMsg( LEVEL, ## ARGS )
-#else
-    #define dmsg( LEVEL, ARGS... )
-#endif
-
-#if ( DEBUG && MDNS_DEBUG_PACKETS )
-    #define dpkt( LEVEL, ARGS... )  DebugMsg( LEVEL, ## ARGS )
-#else
-    #define dpkt( LEVEL, ARGS... )
-#endif
-
-#define ForgetSem( X )      do { if( *( X ) ) { semDelete( ( *X ) ); *( X ) = 0; } } while( 0 )
-#define ForgetSocket( X )   do { if( IsValidSocket( *( X ) ) ) { close_compat( *( X ) ); *( X ) = kInvalidSocketRef; } } while( 0 )
-
-// Interfaces
-
-mDNSlocal mStatus   UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC );
-mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC );
-mDNSlocal int   SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC );
-mDNSlocal void  MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC );
-mDNSlocal int   ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing );
-mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID );
-mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex );
-mDNSlocal mStatus   SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS );
-mDNSlocal mStatus   SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP );
-
-// Commands
-
-mDNSlocal mStatus   SetupCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus   TearDownCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus   SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode );
-mDNSlocal mStatus   ProcessCommand( mDNS * const inMDNS );
-
-// Threads
-
-mDNSlocal void      Task( mDNS *inMDNS );
-mDNSlocal mStatus   TaskInit( mDNS *inMDNS );
-mDNSlocal void      TaskTerm( mDNS *inMDNS );
-mDNSlocal void      TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout );
-mDNSlocal void      TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock );
-mDNSlocal ssize_t
-mDNSRecvMsg(
-    SocketRef inSock,
-    void *      inBuffer,
-    size_t inBufferSize,
-    void *      outFrom,
-    size_t inFromSize,
-    size_t *    outFromSize,
-    mDNSAddr *  outDstAddr,
-    uint32_t *  outIndex );
-
-// DNSServices compatibility. When all clients move to DNS-SD, this section can be removed.
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-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 );
-
-#ifdef  __cplusplus
-}
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-debug_log_new_default_category( mdns );
-
-mDNSexport mDNSs32 mDNSPlatformOneSecond;
-mDNSlocal mDNSs32 gMDNSTicksToMicro       = 0;
-mDNSlocal mDNS *                    gMDNSPtr                = NULL;
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSlocal mDNSBool gMDNSDeferIPv4          = mDNSfalse;
-#if ( DEBUG )
-DebugLevel gMDNSDebugOverrideLevel = kDebugLevelMax;
-#endif
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     mDNSReconfigure
-//===========================================================================================================================
-
-void    mDNSReconfigure( void )
-{
-    if( gMDNSPtr ) SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure );
-}
-
-//===========================================================================================================================
-//     mDNSDeferIPv4
-//===========================================================================================================================
-
-void    mDNSDeferIPv4( mDNSBool inDefer )
-{
-    gMDNSDeferIPv4 = inDefer;
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     mDNSPlatformInit
-//===========================================================================================================================
-
-mStatus mDNSPlatformInit( mDNS * const inMDNS )
-{
-    mStatus err;
-    int id;
-
-    mDNSPlatformOneSecond   = sysClkRateGet();
-    gMDNSTicksToMicro       = ( 1000000L / mDNSPlatformOneSecond );
-
-    // Do minimal initialization to get the task started and so we can cleanup safely if an error occurs.
-
-    mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
-    if( !inMDNS->p ) inMDNS->p  = &gMDNSPlatformSupport;
-    inMDNS->p->unicastSS.info   = NULL;
-    inMDNS->p->unicastSS.sockV4 = kInvalidSocketRef;
-    inMDNS->p->unicastSS.sockV6 = kInvalidSocketRef;
-    inMDNS->p->initErr          = mStatus_NotInitializedErr;
-    inMDNS->p->commandPipe      = ERROR;
-    inMDNS->p->taskID           = ERROR;
-
-    inMDNS->p->lock = semMCreate( SEM_Q_FIFO );
-    require_action( inMDNS->p->lock, exit, err = mStatus_NoMemoryErr );
-
-    inMDNS->p->initEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
-    require_action( inMDNS->p->initEvent, exit, err = mStatus_NoMemoryErr );
-
-    inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
-    require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
-
-    // Start the task and wait for it to initialize. The task does the full initialization from its own context
-    // to avoid potential issues with stack space and APIs that key off the current task (e.g. watchdog timers).
-    // We wait here until the init is complete because it needs to be ready to use as soon as this function returns.
-
-    id = taskSpawn( "tMDNS", 102, 0, 16384, (FUNCPTR) Task, (int) inMDNS, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
-    err = translate_errno( id != ERROR, errno_compat(), mStatus_NoMemoryErr );
-    require_noerr( err, exit );
-
-    err = semTake( inMDNS->p->initEvent, WAIT_FOREVER );
-    if( err == OK ) err = inMDNS->p->initErr;
-    require_noerr( err, exit );
-
-    gMDNSPtr = inMDNS;
-    mDNSCoreInitComplete( inMDNS, err );
-
-exit:
-    if( err ) mDNSPlatformClose( inMDNS );
-    return( err );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformClose
-//===========================================================================================================================
-
-void    mDNSPlatformClose( mDNS * const inMDNS )
-{
-    mStatus err;
-
-    check( inMDNS );
-
-    gMDNSPtr = NULL;
-
-    // Signal the task to quit and wait for it to signal back that it exited. Timeout in 10 seconds to handle a hung thread.
-
-    if( inMDNS->p->taskID != ERROR )
-    {
-        SendCommand( inMDNS, kMDNSPipeCommandCodeQuit );
-        if( inMDNS->p->quitEvent )
-        {
-            err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 );
-            check_noerr( err );
-        }
-        inMDNS->p->taskID = ERROR;
-    }
-
-    // Clean up resources set up in mDNSPlatformInit. All other resources should have been cleaned up already by TaskTerm.
-
-    ForgetSem( &inMDNS->p->quitEvent );
-    ForgetSem( &inMDNS->p->initEvent );
-    ForgetSem( &inMDNS->p->lock );
-
-    dmsg( kDebugLevelNotice, DEBUG_NAME "CLOSED\n" );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mStatus
-mDNSPlatformSendUDP(
-    const mDNS * const inMDNS,
-    const void * const inMsg,
-    const mDNSu8 * const inEnd,
-    mDNSInterfaceID inInterfaceID,
-    const mDNSAddr *            inDstIP,
-    mDNSIPPort inDstPort )
-{
-    mStatus err;
-    NetworkInterfaceInfoVxWorks *       info;
-    SocketRef sock;
-    struct sockaddr_storage to;
-    int n;
-
-    // Set up the sockaddr to sent to and the socket to send on.
-
-    info = (NetworkInterfaceInfoVxWorks *) inInterfaceID;
-    if( inDstIP->type == mDNSAddrType_IPv4 )
-    {
-        struct sockaddr_in *        sa4;
-
-        sa4 = (struct sockaddr_in *) &to;
-        sa4->sin_len            = sizeof( *sa4 );
-        sa4->sin_family         = AF_INET;
-        sa4->sin_port           = inDstPort.NotAnInteger;
-        sa4->sin_addr.s_addr    = inDstIP->ip.v4.NotAnInteger;
-        sock = info ? info->ss.sockV4 : inMDNS->p->unicastSS.sockV4;
-    }
-    else if( inDstIP->type == mDNSAddrType_IPv6 )
-    {
-        struct sockaddr_in6 *       sa6;
-
-        sa6 = (struct sockaddr_in6 *) &to;
-        sa6->sin6_len       = sizeof( *sa6 );
-        sa6->sin6_family    = AF_INET6;
-        sa6->sin6_port      = inDstPort.NotAnInteger;
-        sa6->sin6_flowinfo  = 0;
-        sa6->sin6_addr      = *( (struct in6_addr *) &inDstIP->ip.v6 );
-        sa6->sin6_scope_id  = info ? info->scopeID : 0;
-        sock = info ? info->ss.sockV6 : inMDNS->p->unicastSS.sockV6;
-    }
-    else
-    {
-        dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! destination is not an IPv4 or IPv6 address\n", __ROUTINE__ );
-        err = mStatus_BadParamErr;
-        goto exit;
-    }
-
-    // Send the packet if we've got a valid socket of this type. Note: mDNSCore may ask us to send an IPv4 packet and then
-    // an IPv6 multicast packet. If we don't have the corresponding type of socket available, quietly return an error.
-
-    n = (int)( (mDNSu8 *) inEnd - (mDNSu8 *) inMsg );
-    if( !IsValidSocket( sock ) )
-    {
-        dpkt( kDebugLevelChatty - 1,
-              DEBUG_NAME "DROP: %4d bytes,                                                     DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
-              n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info );
-        err = mStatus_Invalid;
-        goto exit;
-    }
-
-    dpkt( kDebugLevelChatty,
-          DEBUG_NAME "SEND %4d bytes,                                                      DST=[%#39a]:%5hu, IF=%8s(%u) %#p\n",
-          n, inDstIP, mDNSVal16( inDstPort ), info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, info );
-
-    n = sendto( sock, (mDNSu8 *) inMsg, n, 0, (struct sockaddr *) &to, to.ss_len );
-    if( n < 0 )
-    {
-        // Don't warn about ARP failures or no route to host for unicast destinations.
-
-        err = errno_compat();
-        if( ( ( err == EHOSTDOWN ) || ( err == ENETDOWN ) || ( err == EHOSTUNREACH ) ) && !mDNSAddressIsAllDNSLinkGroup( inDstIP ) )
-        {
-            goto exit;
-        }
-
-        dmsg( kDebugLevelError, "%s: ERROR! sendto failed on %8s(%u) to %#a:%d, sock %d, err %d, time %u\n",
-              __ROUTINE__, info ? info->ifinfo.ifname : "unicast", info ? info->scopeID : 0, inDstIP, mDNSVal16( inDstPort ),
-              sock, err, (unsigned int) inMDNS->timenow );
-        if( err == 0 ) err = mStatus_UnknownErr;
-        goto exit;
-    }
-    err = mStatus_NoError;
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     Connection-oriented (TCP) functions
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                          TCPConnectionCallback callback, void *context, int *descriptor)
-{
-    (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)
-{
-    (void)sd;           // Unused
-}
-
-mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
-{
-    (void)sd;           // Unused
-    (void)buf;          // Unused
-    (void)buflen;       // Unused
-    return(0);
-}
-
-mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
-{
-    (void)sd;           // Unused
-    (void)msg;          // Unused
-    (void)len;          // Unused
-    return(0);
-}
-
-//===========================================================================================================================
-//     mDNSPlatformLock
-//===========================================================================================================================
-
-void    mDNSPlatformLock( const mDNS * const inMDNS )
-{
-    check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
-
-#if ( DEBUG )
-    if( semTake( inMDNS->p->lock, 60 * sysClkRateGet() ) != OK )
-    {
-        dmsg( kDebugLevelTragic, "\n### DEADLOCK DETECTED ### (sem=%#p, task=%#p)\n\n", inMDNS->p->lock, taskIdSelf() );
-        debug_stack_trace();            // 1) Print Stack Trace.
-        semShow( inMDNS->p->lock, 1 );  // 2) Print semaphore info, including which tasks are pending on it.
-        taskSuspend( 0 );               // 3) Suspend task. Can be resumed from the console for debugging.
-    }
-#else
-    semTake( inMDNS->p->lock, WAIT_FOREVER );
-#endif
-}
-
-//===========================================================================================================================
-//     mDNSPlatformUnlock
-//===========================================================================================================================
-
-void    mDNSPlatformUnlock( const mDNS * const inMDNS )
-{
-    check_string( inMDNS->p && ( inMDNS->p->taskID != ERROR ), "mDNS task not started" );
-
-    // Wake up the mDNS task to handle any work initiated by an API call and to calculate the next event time.
-    // We only need to wake up if we're not already inside the task. This avoids filling up the command queue.
-
-    if( taskIdSelf() != inMDNS->p->taskID )
-    {
-        SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule );
-    }
-    semGive( inMDNS->p->lock );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformStrLen
-//===========================================================================================================================
-
-mDNSu32 mDNSPlatformStrLen( const void *inSrc )
-{
-    check( inSrc );
-
-    return( (mDNSu32) strlen( (const char *) inSrc ) );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformStrCopy
-//===========================================================================================================================
-
-void    mDNSPlatformStrCopy( void *inDst, const void *inSrc )
-{
-    check( inSrc );
-    check( inDst );
-
-    strcpy( (char *) inDst, (const char*) inSrc );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemCopy
-//===========================================================================================================================
-
-void    mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-    check( inSrc );
-    check( inDst );
-
-    memcpy( inDst, inSrc, inSize );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemSame
-//===========================================================================================================================
-
-mDNSBool    mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-    check( inSrc );
-    check( inDst );
-
-    return( memcmp( inSrc, inDst, inSize ) == 0 );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemZero
-//===========================================================================================================================
-
-void    mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
-{
-    check( inDst );
-
-    memset( inDst, 0, inSize );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemAllocate
-//===========================================================================================================================
-
-mDNSexport void *   mDNSPlatformMemAllocate( mDNSu32 inSize )
-{
-    void *      mem;
-
-    check( inSize > 0 );
-
-    mem = malloc( inSize );
-    check( mem );
-
-    return( mem );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemFree
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemFree( void *inMem )
-{
-    check( inMem );
-    if( inMem ) free( inMem );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformRandomSeed
-//===========================================================================================================================
-
-mDNSexport mDNSu32  mDNSPlatformRandomSeed( void )
-{
-    return( tickGet() );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTimeInit
-//===========================================================================================================================
-
-mDNSexport mStatus  mDNSPlatformTimeInit( void )
-{
-    // No special setup is required on VxWorks -- we just use tickGet().
-
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformRawTime
-//===========================================================================================================================
-
-mDNSs32 mDNSPlatformRawTime( void )
-{
-    return( (mDNSs32) tickGet() );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformUTC
-//===========================================================================================================================
-
-mDNSexport mDNSs32  mDNSPlatformUTC( void )
-{
-    return( (mDNSs32) time( NULL ) );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceIDfromInterfaceIndex
-//===========================================================================================================================
-
-mDNSexport mDNSInterfaceID  mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS *const inMDNS, mDNSu32 inIndex )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-
-    if( inIndex == (mDNSu32) -1 ) return( mDNSInterface_LocalOnly );
-    if( inIndex != 0 )
-    {
-        for( i = inMDNS->p->interfaceList; i; i = i->next )
-        {
-            // Don't get tricked by inactive interfaces with no InterfaceID set.
-
-            if( i->ifinfo.InterfaceID && ( i->scopeID == inIndex ) ) return( i->ifinfo.InterfaceID );
-        }
-    }
-    return( NULL );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceIndexfromInterfaceID
-//===========================================================================================================================
-
-mDNSexport mDNSu32  mDNSPlatformInterfaceIndexfromInterfaceID( mDNS *const inMDNS, mDNSInterfaceID inID )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-
-    if( inID == mDNSInterface_LocalOnly ) return( (mDNSu32) -1 );
-    if( inID )
-    {
-        // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
-
-        for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
-        if( i ) return( i->scopeID );
-    }
-    return( 0 );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceNameToID
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        // Don't get tricked by inactive interfaces with no InterfaceID set.
-
-        if( i->ifinfo.InterfaceID && ( strcmp( i->ifinfo.ifname, inName ) == 0 ) )
-        {
-            *outID = (mDNSInterfaceID) i;
-            return( mStatus_NoError );
-        }
-    }
-    return( mStatus_NoSuchNameErr );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceIDToInfo
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-
-    // Don't use i->ifinfo.InterfaceID here, because we DO want to find inactive interfaces.
-
-    for( i = inMDNS->p->interfaceList; i && ( (mDNSInterfaceID) i != inID ); i = i->next ) {}
-    if( !i ) return( mStatus_NoSuchNameErr );
-
-    outInfo->name   = i->ifinfo.ifname;
-    outInfo->ip     = i->ifinfo.ip;
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     debugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS > 0 )
-mDNSexport void debugf_( const char *inFormat, ... )
-{
-    char buffer[ 512 ];
-    va_list args;
-
-    va_start( args, inFormat );
-    mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-    va_end( args );
-
-    dlog( kDebugLevelInfo, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-//     verbosedebugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS > 1 )
-mDNSexport void verbosedebugf_( const char *inFormat, ... )
-{
-    char buffer[ 512 ];
-    va_list args;
-
-    va_start( args, inFormat );
-    mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-    va_end( args );
-
-    dlog( kDebugLevelVerbose, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-//     LogMsg
-//===========================================================================================================================
-
-mDNSexport void LogMsg( const char *inFormat, ... )
-{
-#if ( DEBUG )
-    char buffer[ 512 ];
-    va_list args;
-
-    va_start( args, inFormat );
-    mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-    va_end( args );
-
-    dlog( kDebugLevelWarning, "%s\n", buffer );
-#else
-    DEBUG_UNUSED( inFormat );
-#endif
-}
-
-#if ( DEBUG )
-//===========================================================================================================================
-//     DebugMsg
-//===========================================================================================================================
-
-mDNSlocal void  DebugMsg( DebugLevel inLevel, const char *inFormat, ... )
-{
-    char buffer[ 512 ];
-    va_list args;
-
-    va_start( args, inFormat );
-    mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-    va_end( args );
-
-    if( inLevel >= gMDNSDebugOverrideLevel ) inLevel = kDebugLevelMax;
-    dlog( inLevel, "%s", buffer );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Interfaces ==
-#endif
-
-//===========================================================================================================================
-//     UpdateInterfaceList
-//===========================================================================================================================
-
-#if ( MDNS_ENABLE_PPP )
-
-// Note: This includes PPP dial-in interfaces (pppXYZ), but not PPP dial-out interface (pppdXYZ).
-
-    #define IsCompatibleInterface( IFA )                                                                        \
-    ( ( ( IFA )->ifa_flags & IFF_UP )                                                                   &&  \
-      ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) )   &&  \
-      ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) )   &&  \
-      ( !( ( IFA )->ifa_flags & IFF_POINTOPOINT ) || ( strncmp( ( IFA )->ifa_name, "pppd", 4 ) != 0 ) ) )
-#else
-    #define IsCompatibleInterface( IFA )                                                                                \
-    ( ( ( ( IFA )->ifa_flags & ( IFF_UP | IFF_MULTICAST | IFF_POINTOPOINT ) ) == ( IFF_UP | IFF_MULTICAST ) )   &&  \
-      ( ( ( IFA )->ifa_addr->sa_family == AF_INET ) || ( ( IFA )->ifa_addr->sa_family == AF_INET6 ) )           &&  \
-      ( ( IFA )->ifa_netmask && ( ( IFA )->ifa_addr->sa_family == ( IFA )->ifa_netmask->sa_family ) ) )
-#endif
-
-#define IsLinkLocalSockAddr( 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_LINKLOCAL( &( (const struct sockaddr_in6 *)( SA ) )->sin6_addr ) )
-
-#define FamilyToString( X )                 \
-    ( ( ( X ) == AF_INET )  ? "AF_INET"  :  \
-      ( ( ( X ) == AF_INET6 ) ? "AF_INET6" :  \
-        ( ( ( X ) == AF_LINK )  ? "AF_LINK"  :  \
-        "UNKNOWN" ) ) )
-
-mDNSlocal mStatus   UpdateInterfaceList( mDNS *const inMDNS, mDNSs32 inUTC )
-{
-    mStatus err;
-    struct ifaddrs *                    ifaList;
-    struct ifaddrs *                    ifa;
-    int family;
-    mDNSBool foundV4;
-    mDNSBool foundV6;
-    struct ifaddrs *                    loopbackV4;
-    struct ifaddrs *                    loopbackV6;
-    mDNSEthAddr primaryMAC;
-    SocketRef infoSock;
-    char defaultName[ 64 ];
-    NetworkInterfaceInfoVxWorks *       i;
-    domainlabel nicelabel;
-    domainlabel hostlabel;
-    domainlabel tmp;
-
-    ifaList     = NULL;
-    foundV4     = mDNSfalse;
-    foundV6     = mDNSfalse;
-    loopbackV4  = NULL;
-    loopbackV6  = NULL;
-    primaryMAC  = zeroEthAddr;
-
-    // Set up an IPv6 socket so we can check the state of interfaces using SIOCGIFAFLAG_IN6.
-
-    infoSock = socket( AF_INET6, SOCK_DGRAM, 0 );
-    check_translated_errno( IsValidSocket( infoSock ), errno_compat(), kUnknownErr );
-
-    // Run through the entire list of interfaces.
-
-    err = getifaddrs( &ifaList );
-    check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
-    for( ifa = ifaList; ifa; ifa = ifa->ifa_next )
-    {
-        int flags;
-
-        family = ifa->ifa_addr->sa_family;
-        dmsg( kDebugLevelVerbose, DEBUG_NAME "%s: %8s(%d), Flags 0x%08X, Family %8s(%2d)\n", __ROUTINE__,
-              ifa->ifa_name, if_nametoindex( ifa->ifa_name ), ifa->ifa_flags, FamilyToString( family ), family );
-
-        // Save off the MAC address of the first Ethernet-ish interface.
-
-        if( family == AF_LINK )
-        {
-            struct sockaddr_dl *        sdl;
-
-            sdl = (struct sockaddr_dl *) ifa->ifa_addr;
-            if( ( sdl->sdl_type == IFT_ETHER ) && ( sdl->sdl_alen == sizeof( primaryMAC ) &&
-                                                    mDNSSameEthAddress( &primaryMAC, &zeroEthAddr ) ) )
-            {
-                memcpy( primaryMAC.b, sdl->sdl_data + sdl->sdl_nlen, 6 );
-            }
-        }
-
-        if( !IsCompatibleInterface( ifa ) ) continue;
-
-        // If this is a link-local address and there's a non-link-local address on this interface, skip this alias.
-
-        if( IsLinkLocalSockAddr( ifa->ifa_addr ) )
-        {
-            struct ifaddrs *        ifaLL;
-
-            for( ifaLL = ifaList; ifaLL; ifaLL = ifaLL->ifa_next )
-            {
-                if( ifaLL->ifa_addr->sa_family != family ) continue;
-                if( !IsCompatibleInterface( ifaLL ) ) continue;
-                if( strcmp( ifaLL->ifa_name, ifa->ifa_name ) != 0 ) continue;
-                if( !IsLinkLocalSockAddr( ifaLL->ifa_addr ) ) break;
-            }
-            if( ifaLL )
-            {
-                dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %8s(%d) skipping link-local alias\n", __ROUTINE__,
-                      ifa->ifa_name, if_nametoindex( ifa->ifa_name ) );
-                continue;
-            }
-        }
-
-        // If this is an IPv6 interface, perform additional checks to make sure it is really ready for use.
-        // If this is a loopback interface, save it off since we may add it later if there are no other interfaces.
-        // Otherwise, add the interface to the list.
-
-        flags = 0;
-        if( ( family == AF_INET6 ) && IsValidSocket( infoSock ) )
-        {
-            struct sockaddr_in6 *       sa6;
-            struct in6_ifreq ifr6;
-
-            sa6 = (struct sockaddr_in6 *) ifa->ifa_addr;
-            mDNSPlatformMemZero( &ifr6, sizeof( ifr6 ) );
-            strcpy( ifr6.ifr_name, ifa->ifa_name );
-            ifr6.ifr_addr = *sa6;
-            if( ioctl( infoSock, SIOCGIFAFLAG_IN6, (int) &ifr6 ) != -1 )
-            {
-                flags = ifr6.ifr_ifru.ifru_flags6;
-            }
-        }
-
-        // HACK: This excludes interfaces with IN6_IFF_DUPLICATED set instead of using IN6_IFF_NOTREADY (which is
-        // HACK: IN6_IFF_TENTATIVE | IN6_IFF_DUPLICATED) because we currently do not get a notification when an
-        // HACK: interface goes from the tentative state to the fully ready state. So as a short-term workaround,
-        // HACK: this allows tentative interfaces to be registered. We should revisit if we get notification hooks.
-
-        if( flags & ( IN6_IFF_DUPLICATED | IN6_IFF_DETACHED | IN6_IFF_DEPRECATED | IN6_IFF_TEMPORARY ) )
-        {
-            dmsg( kDebugLevelNotice, DEBUG_NAME "%s: %8s(%d), SIOCGIFAFLAG_IN6 not ready yet (0x%X)\n", __ROUTINE__,
-                  ifa->ifa_name, if_nametoindex( ifa->ifa_name ), flags );
-            continue;
-        }
-        if( ifa->ifa_flags & IFF_LOOPBACK )
-        {
-            if( family == AF_INET ) loopbackV4 = ifa;
-            else loopbackV6 = ifa;
-        }
-        else
-        {
-            if( ( family == AF_INET ) && gMDNSDeferIPv4 && IsLinkLocalSockAddr( ifa->ifa_addr ) ) continue;
-            i = AddInterfaceToList( inMDNS, ifa, inUTC );
-            if( i && i->multicast )
-            {
-                if( family == AF_INET ) foundV4 = mDNStrue;
-                else foundV6 = mDNStrue;
-            }
-        }
-    }
-
-    // For efficiency, we don't register a loopback interface when other interfaces of that family are available.
-
-    if( !foundV4 && loopbackV4 ) AddInterfaceToList( inMDNS, loopbackV4, inUTC );
-    if( !foundV6 && loopbackV6 ) AddInterfaceToList( inMDNS, loopbackV6, inUTC );
-    freeifaddrs( ifaList );
-    if( IsValidSocket( infoSock ) ) close_compat( infoSock );
-
-    // 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.
-
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        if( i->exists )
-        {
-            mDNSBool txrx;
-
-            txrx = i->multicast && ( ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) || !FindRoutableIPv4( inMDNS, i->scopeID ) );
-            if( i->ifinfo.McastTxRx != txrx )
-            {
-                i->ifinfo.McastTxRx = txrx;
-                i->exists           = 2;    // 2=state change; need to de-register and re-register this interface.
-            }
-        }
-    }
-
-    // Set up the user-specified, friendly name, which is allowed to be full UTF-8.
-
-    mDNS_snprintf( defaultName, sizeof( defaultName ), "Device-%02X:%02X:%02X:%02X:%02X:%02X",
-                   primaryMAC.b[ 0 ], primaryMAC.b[ 1 ], primaryMAC.b[ 2 ], primaryMAC.b[ 3 ], primaryMAC.b[ 4 ], primaryMAC.b[ 5 ] );
-
-    MakeDomainLabelFromLiteralString( &nicelabel, "Put Nice Name Here" ); // $$$ Implementers: Fill in nice name of device.
-    if( nicelabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &nicelabel, defaultName );
-
-    // Set up the RFC 1034-compliant label. If not set or it is not RFC 1034 compliant, try the user-specified nice name.
-
-    MakeDomainLabelFromLiteralString( &tmp, "Put-DNS-Name-Here" ); // $$$ Implementers: Fill in DNS name of device.
-    ConvertUTF8PstringToRFC1034HostLabel( tmp.c, &hostlabel );
-    if( hostlabel.c[ 0 ] == 0 ) ConvertUTF8PstringToRFC1034HostLabel( nicelabel.c, &hostlabel );
-    if( hostlabel.c[ 0 ] == 0 ) MakeDomainLabelFromLiteralString( &hostlabel, defaultName );
-
-    // Update our globals and mDNS with the new labels.
-
-    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( !SameDomainLabelCS( inMDNS->p->userHostLabel.c, hostlabel.c ) )
-    {
-        dmsg( kDebugLevelInfo, DEBUG_NAME "Updating hostlabel to \"%#s\"\n", hostlabel.c );
-        inMDNS->p->userHostLabel    = hostlabel;
-        inMDNS->hostlabel           = hostlabel;
-        mDNS_SetFQDN( inMDNS );
-    }
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     AddInterfaceToList
-//===========================================================================================================================
-
-mDNSlocal NetworkInterfaceInfoVxWorks * AddInterfaceToList( mDNS *const inMDNS, struct ifaddrs *inIFA, mDNSs32 inUTC )
-{
-    mStatus err;
-    mDNSAddr ip;
-    mDNSAddr mask;
-    mDNSu32 scopeID;
-    NetworkInterfaceInfoVxWorks **      p;
-    NetworkInterfaceInfoVxWorks *       i;
-
-    i = NULL;
-
-    err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ip );
-    require_noerr( err, exit );
-
-    err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &mask );
-    require_noerr( err, exit );
-
-    // Search for an existing interface with the same info. If found, just return that one.
-
-    scopeID = if_nametoindex( inIFA->ifa_name );
-    check( scopeID );
-    for( p = &inMDNS->p->interfaceList; *p; p = &( *p )->next )
-    {
-        if( ( scopeID == ( *p )->scopeID ) && mDNSSameAddress( &ip, &( *p )->ifinfo.ip ) )
-        {
-            dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Found existing interface %u with address %#a at %#p\n", __ROUTINE__,
-                  scopeID, &ip, *p );
-            ( *p )->exists = mDNStrue;
-            i = *p;
-            goto exit;
-        }
-    }
-
-    // Allocate the new interface info and fill it out.
-
-    i = (NetworkInterfaceInfoVxWorks *) calloc( 1, sizeof( *i ) );
-    require( i, exit );
-
-    dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Making   new   interface %u with address %#a at %#p\n", __ROUTINE__, scopeID, &ip, i );
-    strncpy( i->ifinfo.ifname, inIFA->ifa_name, sizeof( i->ifinfo.ifname ) );
-    i->ifinfo.ifname[ sizeof( i->ifinfo.ifname ) - 1 ] = '\0';
-    i->ifinfo.InterfaceID   = NULL;
-    i->ifinfo.ip            = ip;
-    i->ifinfo.mask          = mask;
-    i->ifinfo.Advertise     = inMDNS->AdvertiseLocalAddresses;
-    i->ifinfo.McastTxRx     = mDNSfalse; // For now; will be set up later at the end of UpdateInterfaceList.
-
-    i->next                 = NULL;
-    i->exists               = mDNStrue;
-    i->lastSeen             = inUTC;
-    i->scopeID              = scopeID;
-    i->family               = inIFA->ifa_addr->sa_family;
-    i->multicast            = ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTOPOINT );
-
-    i->ss.info              = i;
-    i->ss.sockV4            = kInvalidSocketRef;
-    i->ss.sockV6            = kInvalidSocketRef;
-    *p = i;
-
-exit:
-    return( i );
-}
-
-//===========================================================================================================================
-//     SetupActiveInterfaces
-//
-//     Returns a count of non-link local IPv4 addresses registered.
-//===========================================================================================================================
-
-#define mDNSAddressIsNonLinkLocalIPv4( X )  \
-    ( ( ( X )->type == mDNSAddrType_IPv4 ) && ( ( ( X )->ip.v4.b[ 0 ] != 169 ) || ( ( X )->ip.v4.b[ 1 ] != 254 ) ) )
-
-mDNSlocal int   SetupActiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC )
-{
-    int count;
-    NetworkInterfaceInfoVxWorks *       i;
-
-    count = 0;
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        NetworkInterfaceInfo *              n;
-        NetworkInterfaceInfoVxWorks *       primary;
-
-        if( !i->exists ) continue;
-
-        // Search for the primary interface and sanity check it.
-
-        n = &i->ifinfo;
-        primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID );
-        if( !primary )
-        {
-            dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! didn't find %s(%u)\n", __ROUTINE__, i->ifinfo.ifname, i->scopeID );
-            continue;
-        }
-        if( n->InterfaceID && ( n->InterfaceID != (mDNSInterfaceID) primary ) )
-        {
-            dmsg( kDebugLevelError, DEBUG_NAME "%s: ERROR! n->InterfaceID %#p != primary %#p\n", __ROUTINE__,
-                  n->InterfaceID, primary );
-            n->InterfaceID = NULL;
-        }
-
-        // If n->InterfaceID is set, it means we've already called mDNS_RegisterInterface() for this interface.
-        // so we don't need to call it again. Otherwise, register the interface with mDNS.
-
-        if( !n->InterfaceID )
-        {
-            mDNSBool flapping;
-
-            n->InterfaceID = (mDNSInterfaceID) primary;
-
-            // If lastSeen == inUTC, then this is a brand-new interface, or an interface that never went away.
-            // If lastSeen != inUTC, then this is an old interface, that went away for (inUTC - lastSeen) seconds.
-            // 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 ? SlowActivation : NormalActivation));
-            if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
-
-            dmsg( kDebugLevelInfo, DEBUG_NAME "%s:   Registered    %8s(%u) InterfaceID %#p %#a%s%s\n", __ROUTINE__,
-                  i->ifinfo.ifname, i->scopeID, primary, &n->ip,
-                  flapping            ? " (Flapping)" : "",
-                  n->InterfaceActive  ? " (Primary)"  : "" );
-        }
-
-        // Set up a socket if it's not already set up. If multicast is not enabled on this interface then we
-        // don't need a socket since unicast traffic will be handled on the unicast socket.
-
-        if( n->McastTxRx )
-        {
-            mStatus err;
-
-            if( ( ( i->family == AF_INET  ) && !IsValidSocket( primary->ss.sockV4 ) ) ||
-                ( ( i->family == AF_INET6 ) && !IsValidSocket( primary->ss.sockV6 ) ) )
-            {
-                err = SetupSocket( inMDNS, &i->ifinfo.ip, mDNStrue, i->family, &primary->ss );
-                check_noerr( err );
-            }
-        }
-        else
-        {
-            dmsg( kDebugLevelInfo, DEBUG_NAME "%s:   No Tx/Rx on   %8s(%u) InterfaceID %#p %#a\n", __ROUTINE__,
-                  i->ifinfo.ifname, i->scopeID, primary, &n->ip );
-        }
-    }
-    return( count );
-}
-
-//===========================================================================================================================
-//     MarkAllInterfacesInactive
-//===========================================================================================================================
-
-mDNSlocal void  MarkAllInterfacesInactive( mDNS *const inMDNS, mDNSs32 inUTC )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        if( !i->exists ) continue;
-        i->lastSeen = inUTC;
-        i->exists   = mDNSfalse;
-    }
-}
-
-//===========================================================================================================================
-//     ClearInactiveInterfaces
-//
-//     Returns count of non-link local IPv4 addresses de-registered.
-//===========================================================================================================================
-
-mDNSlocal int   ClearInactiveInterfaces( mDNS *const inMDNS, mDNSs32 inUTC, mDNSBool inClosing )
-{
-    int count;
-    NetworkInterfaceInfoVxWorks *       i;
-    NetworkInterfaceInfoVxWorks **      p;
-
-    // First pass:
-    // If an interface is going away, then de-register it from mDNSCore.
-    // We also have to de-register it if the primary interface that it's using for its InterfaceID is going away.
-    // We have to do this because mDNSCore will use that InterfaceID when sending packets, and if the memory
-    // it refers to has gone away, we'll crash. Don't actually close the sockets or free the memory yet though:
-    // When the last representative of an interface goes away mDNSCore may want to send goodbye packets on that
-    // interface. (Not yet implemented, but a good idea anyway.).
-
-    count = 0;
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        NetworkInterfaceInfoVxWorks *       primary;
-
-        // 1. If this interface is no longer active, or its InterfaceID is changing, de-register it.
-
-        if( !i->ifinfo.InterfaceID ) continue;
-        primary = FindInterfaceByIndex( inMDNS, i->family, i->scopeID );
-        if( ( i->exists == 0 ) || ( i->exists == 2 ) || ( i->ifinfo.InterfaceID != (mDNSInterfaceID) primary ) )
-        {
-            dmsg( kDebugLevelInfo, DEBUG_NAME "%s: Deregistering %8s(%u) InterfaceID %#p %#a%s\n", __ROUTINE__,
-                  i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
-                  i->ifinfo.InterfaceActive ? " (Primary)" : "" );
-
-            mDNS_DeregisterInterface( inMDNS, &i->ifinfo, NormalActivation );
-            i->ifinfo.InterfaceID = NULL;
-            if( mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) ) ++count;
-        }
-    }
-
-    // Second pass:
-    // Now that everything that's going to de-register has done so, we can close sockets and free the memory.
-
-    p = &inMDNS->p->interfaceList;
-    while( *p )
-    {
-        i = *p;
-
-        // 2. Close all our sockets. We'll recreate them later as needed.
-        // (We may have previously had both v4 and v6, and we may not need both any more.).
-
-        ForgetSocket( &i->ss.sockV4 );
-        ForgetSocket( &i->ss.sockV6 );
-
-        // 3. If no longer active, remove the interface from the list and free its memory.
-
-        if( !i->exists )
-        {
-            mDNSBool deleteIt;
-
-            if( inClosing )
-            {
-                check_string( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0, "closing with in-use records!" );
-                deleteIt = mDNStrue;
-            }
-            else
-            {
-                if( i->lastSeen == inUTC ) i->lastSeen = inUTC - 1;
-                deleteIt = ( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) i ) == 0 ) && ( ( inUTC - i->lastSeen ) >= 60 );
-            }
-            dmsg( kDebugLevelInfo, DEBUG_NAME "%s: %-13s %8s(%u) InterfaceID %#p %#a Age %d%s\n", __ROUTINE__,
-                  deleteIt ? "Deleting" : "Holding", i->ifinfo.ifname, i->scopeID, i->ifinfo.InterfaceID, &i->ifinfo.ip,
-                  inUTC - i->lastSeen, i->ifinfo.InterfaceActive ? " (Primary)" : "" );
-            if( deleteIt )
-            {
-                *p = i->next;
-                free( i );
-                continue;
-            }
-        }
-        p = &i->next;
-    }
-    return( count );
-}
-
-//===========================================================================================================================
-//     FindRoutableIPv4
-//===========================================================================================================================
-
-mDNSlocal NetworkInterfaceInfoVxWorks * FindRoutableIPv4( mDNS *const inMDNS, mDNSu32 inScopeID )
-{
-#if ( MDNS_EXCLUDE_IPV4_ROUTABLE_IPV6 )
-    NetworkInterfaceInfoVxWorks *       i;
-
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        if( i->exists && ( i->scopeID == inScopeID ) && mDNSAddressIsNonLinkLocalIPv4( &i->ifinfo.ip ) )
-        {
-            break;
-        }
-    }
-    return( i );
-#else
-    DEBUG_UNUSED( inMDNS );
-    DEBUG_UNUSED( inScopeID );
-
-    return( NULL );
-#endif
-}
-
-//===========================================================================================================================
-//     FindInterfaceByIndex
-//===========================================================================================================================
-
-mDNSlocal NetworkInterfaceInfoVxWorks * FindInterfaceByIndex( mDNS *const inMDNS, int inFamily, mDNSu32 inIndex )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-
-    check( inIndex != 0 );
-
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        if( i->exists && ( i->scopeID == inIndex ) &&
-            ( MDNS_AAAA_OVER_IPV4                                                           ||
-              ( ( inFamily == AF_INET  ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv4 ) )    ||
-              ( ( inFamily == AF_INET6 ) && ( i->ifinfo.ip.type == mDNSAddrType_IPv6 ) ) ) )
-        {
-            return( i );
-        }
-    }
-    return( NULL );
-}
-
-//===========================================================================================================================
-//     SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus   SetupSocket( mDNS *const inMDNS, const mDNSAddr *inAddr, mDNSBool inMcast, int inFamily, SocketSet *inSS )
-{
-    mStatus err;
-    SocketRef *     sockPtr;
-    mDNSIPPort port;
-    SocketRef sock;
-    const int on = 1;
-
-    check( inAddr );
-    check( inSS );
-
-    sockPtr = ( inFamily == AF_INET ) ? &inSS->sockV4 : &inSS->sockV6;
-    port    = ( inMcast || inMDNS->CanReceiveUnicastOn5353 ) ? MulticastDNSPort : zeroIPPort;
-
-    sock = socket( inFamily, SOCK_DGRAM, IPPROTO_UDP );
-    err = translate_errno( IsValidSocket( sock ), errno_compat(), mStatus_UnknownErr );
-    require_noerr( err, exit );
-
-    // Allow multiple listeners if this is a multicast port.
-
-    if( port.NotAnInteger )
-    {
-        err = setsockopt( sock, SOL_SOCKET, SO_REUSEPORT, (char *) &on, sizeof( on ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-    }
-
-    // Set up the socket based on the family (IPv4 or IPv6).
-
-    if( inFamily == AF_INET )
-    {
-        const int ttlV4       = 255;
-        const u_char ttlV4Mcast  = 255;
-        struct sockaddr_in sa4;
-
-        // Receive destination addresses so we know which address the packet was sent to.
-
-        err = setsockopt( sock, IPPROTO_IP, IP_RECVDSTADDR, (char *) &on, sizeof( on ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Receive interface indexes so we know which interface received the packet.
-
-        err = setsockopt( sock, IPPROTO_IP, IP_RECVIF, (char *) &on, sizeof( on ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
-
-        if( inMcast )
-        {
-            struct in_addr addrV4;
-            struct ip_mreq mreqV4;
-
-            addrV4.s_addr               = inAddr->ip.v4.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 );
-
-            err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addrV4, sizeof( addrV4 ) );
-            check_translated_errno( err == 0, errno_compat(), kOptionErr );
-        }
-
-        // Send unicast packets with TTL 255 (helps against spoofing).
-
-        err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &ttlV4, sizeof( ttlV4 ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Send multicast packets with TTL 255 (helps against spoofing).
-
-        err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &ttlV4Mcast, sizeof( ttlV4Mcast ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Start listening for packets.
-
-        mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
-        sa4.sin_len         = sizeof( sa4 );
-        sa4.sin_family      = AF_INET;
-        sa4.sin_port        = port.NotAnInteger;
-        sa4.sin_addr.s_addr = htonl( INADDR_ANY ); // We want to receive multicasts AND unicasts on this socket.
-        err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-    }
-    else if( inFamily == AF_INET6 )
-    {
-        struct sockaddr_in6 sa6;
-        const int ttlV6 = 255;
-
-        // Receive destination addresses and interface index so we know where the packet was received and intended.
-
-        err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &on, sizeof( on ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Receive only IPv6 packets because otherwise, we may get IPv4 addresses as IPv4-mapped IPv6 addresses.
-
-        err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof( on ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Join the multicast group on this interface and specify the outgoing interface, if it's for multicast receiving.
-
-        if( inMcast )
-        {
-            u_int ifindex;
-            struct ipv6_mreq mreqV6;
-
-            ifindex                 = inSS->info->scopeID;
-            mreqV6.ipv6mr_interface = ifindex;
-            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 );
-
-            err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &ifindex, sizeof( ifindex ) );
-            check_translated_errno( err == 0, errno_compat(), kOptionErr );
-        }
-
-        // Send unicast packets with TTL 255 (helps against spoofing).
-
-        err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Send multicast packets with TTL 255 (helps against spoofing).
-
-        err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &ttlV6, sizeof( ttlV6 ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Receive our own packets for same-machine operation.
-
-        err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &on, sizeof( on ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-        // Start listening for packets.
-
-        mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
-        sa6.sin6_len        = sizeof( sa6 );
-        sa6.sin6_family     = AF_INET6;
-        sa6.sin6_port       = port.NotAnInteger;
-        sa6.sin6_flowinfo   = 0;
-        sa6.sin6_addr       = in6addr_any; // We want to receive multicasts AND unicasts on this socket.
-        sa6.sin6_scope_id   = 0;
-        err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
-        check_translated_errno( err == 0, errno_compat(), kOptionErr );
-    }
-    else
-    {
-        dmsg( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inFamily );
-        err = kUnsupportedErr;
-        goto exit;
-    }
-
-    // Make the socket non-blocking so we can potentially get multiple packets per select call.
-
-    err = ioctl( sock, FIONBIO, (int) &on );
-    check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-    *sockPtr = sock;
-    sock = kInvalidSocketRef;
-    err = mStatus_NoError;
-
-exit:
-    if( IsValidSocket( sock ) ) close_compat( sock );
-    return( err );
-}
-
-//===========================================================================================================================
-//     SockAddrToMDNSAddr
-//===========================================================================================================================
-
-mDNSlocal mStatus   SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP )
-{
-    mStatus err;
-
-    check( inSA );
-    check( outIP );
-
-    if( inSA->sa_family == AF_INET )
-    {
-        struct sockaddr_in *        sa4;
-
-        sa4 = (struct sockaddr_in *) inSA;
-        outIP->type                 = mDNSAddrType_IPv4;
-        outIP->ip.v4.NotAnInteger   = sa4->sin_addr.s_addr;
-        err = mStatus_NoError;
-    }
-    else if( inSA->sa_family == AF_INET6 )
-    {
-        struct sockaddr_in6 *       sa6;
-
-        sa6 = (struct sockaddr_in6 *) inSA;
-        outIP->type     = mDNSAddrType_IPv6;
-        outIP->ip.v6    = *( (mDNSv6Addr *) &sa6->sin6_addr );
-        if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) ) outIP->ip.v6.w[ 1 ] = 0;
-        err = mStatus_NoError;
-    }
-    else
-    {
-        dmsg( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family (%d)\n", __ROUTINE__, inSA->sa_family );
-        err = mStatus_BadParamErr;
-    }
-    return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Commands ==
-#endif
-
-//===========================================================================================================================
-//     SetupCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus   SetupCommandPipe( mDNS * const inMDNS )
-{
-    mStatus err;
-
-    err = pipeDevCreate( "/pipe/mDNS", 32, 1 );
-    check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-
-    inMDNS->p->commandPipe = open( "/pipe/mDNS", O_RDWR, 0 );
-    err = translate_errno( inMDNS->p->commandPipe != ERROR, errno_compat(), mStatus_UnsupportedErr );
-    require_noerr( err, exit );
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     TearDownCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus   TearDownCommandPipe( mDNS * const inMDNS )
-{
-    mStatus err;
-
-    if( inMDNS->p->commandPipe != ERROR )
-    {
-        err = close( inMDNS->p->commandPipe );
-        check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-        inMDNS->p->commandPipe = ERROR;
-
-        err = pipeDevDelete( "/pipe/mDNS", FALSE );
-        check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-    }
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     SendCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus   SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode )
-{
-    mStatus err;
-
-    require_action_quiet( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
-
-    err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) );
-    err = translate_errno( err >= 0, errno_compat(), kWriteErr );
-    require_noerr( err, exit );
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     ProcessCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus   ProcessCommand( mDNS * const inMDNS )
-{
-    mStatus err;
-    MDNSPipeCommandCode cmd;
-    mDNSs32 utc;
-
-    err = read( inMDNS->p->commandPipe, &cmd, sizeof( cmd ) );
-    err = translate_errno( err >= 0, errno_compat(), kReadErr );
-    require_noerr( err, exit );
-
-    switch( cmd )
-    {
-    case kMDNSPipeCommandCodeReschedule:        // Reschedule: just break out to re-run mDNS_Execute.
-        break;
-
-    case kMDNSPipeCommandCodeReconfigure:       // Reconfigure: rebuild the interface list after a config change.
-        dmsg( kDebugLevelInfo, DEBUG_NAME "***   NETWORK CONFIGURATION CHANGE   ***\n" );
-        mDNSPlatformLock( inMDNS );
-
-        utc = mDNSPlatformUTC();
-        MarkAllInterfacesInactive( inMDNS, utc );
-        UpdateInterfaceList( inMDNS, utc );
-        ClearInactiveInterfaces( inMDNS, utc, mDNSfalse );
-        SetupActiveInterfaces( inMDNS, utc );
-
-        mDNSPlatformUnlock( inMDNS );
-        mDNS_ConfigChanged(inMDNS);
-        break;
-
-    case kMDNSPipeCommandCodeQuit:              // Quit: just set a flag so the task exits cleanly.
-        inMDNS->p->quit = mDNStrue;
-        break;
-
-    default:
-        dmsg( kDebugLevelError, DEBUG_NAME "unknown pipe command (%d)\n", cmd );
-        err = mStatus_BadParamErr;
-        goto exit;
-    }
-
-exit:
-    return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Threads ==
-#endif
-
-//===========================================================================================================================
-//     Task
-//===========================================================================================================================
-
-mDNSlocal void  Task( mDNS *inMDNS )
-{
-    mStatus err;
-    mDNSs32 nextEvent;
-    fd_set readSet;
-    int maxFd;
-    struct timeval timeout;
-    NetworkInterfaceInfoVxWorks *       i;
-    int fd;
-    int n;
-
-    check( inMDNS );
-
-    err = TaskInit( inMDNS );
-    require_noerr( err, exit );
-
-    while( !inMDNS->p->quit )
-    {
-        // Let mDNSCore do its work then wait for an event. On idle timeouts (n == 0), just loop back to mDNS_Exceute.
-
-        nextEvent = mDNS_Execute( inMDNS );
-        TaskSetupSelect( inMDNS, &readSet, &maxFd, nextEvent, &timeout );
-        n = select( maxFd + 1, &readSet, NULL, NULL, &timeout );
-        check_translated_errno( n >= 0, errno_compat(), kUnknownErr );
-        if( n == 0 ) continue;
-
-        // Process interface-specific sockets with pending data.
-
-        n = 0;
-        for( i = inMDNS->p->interfaceList; i; i = i->next )
-        {
-            fd = i->ss.sockV4;
-            if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
-            {
-                TaskProcessPackets( inMDNS, &i->ss, fd );
-                ++n;
-            }
-            fd = i->ss.sockV6;
-            if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
-            {
-                TaskProcessPackets( inMDNS, &i->ss, fd );
-                ++n;
-            }
-        }
-
-        // Process unicast sockets with pending data.
-
-        fd = inMDNS->p->unicastSS.sockV4;
-        if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
-        {
-            TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
-            ++n;
-        }
-        fd = inMDNS->p->unicastSS.sockV6;
-        if( IsValidSocket( fd ) && FD_ISSET( fd, &readSet ) )
-        {
-            TaskProcessPackets( inMDNS, &inMDNS->p->unicastSS, fd );
-            ++n;
-        }
-
-        // Processing pending commands.
-
-        fd = inMDNS->p->commandPipe;
-        check( fd >= 0 );
-        if( FD_ISSET( fd, &readSet ) )
-        {
-            ProcessCommand( inMDNS );
-            ++n;
-        }
-        check_string( n > 0, "select said something was readable, but nothing was" );
-    }
-
-exit:
-    TaskTerm( inMDNS );
-}
-
-//===========================================================================================================================
-//     TaskInit
-//===========================================================================================================================
-
-mDNSlocal mStatus   TaskInit( mDNS *inMDNS )
-{
-    mStatus err;
-    mDNSs32 utc;
-    socklen_t len;
-
-    inMDNS->p->taskID = taskIdSelf();
-
-    err = SetupCommandPipe( inMDNS );
-    require_noerr( err, exit );
-
-    inMDNS->CanReceiveUnicastOn5353 = mDNStrue;
-
-    // Set up the HINFO string using the description property (e.g. "Device V1.0").
-
-    inMDNS->HIHardware.c[ 0 ] = 11;
-    memcpy( &inMDNS->HIHardware.c[ 1 ], "Device V1.0", inMDNS->HIHardware.c[ 0 ] ); // $$$ Implementers: Fill in real info.
-
-    // Set up the unicast sockets.
-
-    err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET, &inMDNS->p->unicastSS );
-    check_noerr( err );
-    if( err == mStatus_NoError )
-    {
-        struct sockaddr_in sa4;
-
-        len = sizeof( sa4 );
-        err = getsockname( inMDNS->p->unicastSS.sockV4, (struct sockaddr *) &sa4, &len );
-        check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-        if( err == 0 ) inMDNS->UnicastPort4.NotAnInteger = sa4.sin_port;
-    }
-
-    err = SetupSocket( inMDNS, &zeroAddr, mDNSfalse, AF_INET6, &inMDNS->p->unicastSS );
-    check_noerr( err );
-    if( err == mStatus_NoError )
-    {
-        struct sockaddr_in6 sa6;
-
-        len = sizeof( sa6 );
-        err = getsockname( inMDNS->p->unicastSS.sockV6, (struct sockaddr *) &sa6, &len );
-        check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-        if( err == 0 ) inMDNS->UnicastPort6.NotAnInteger = sa6.sin6_port;
-    }
-
-    // Set up the interfaces.
-
-    utc = mDNSPlatformUTC();
-    UpdateInterfaceList( inMDNS, utc );
-    SetupActiveInterfaces( inMDNS, utc );
-    err = mStatus_NoError;
-
-exit:
-    // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
-
-    inMDNS->p->initErr = err;
-    semGive( inMDNS->p->initEvent );
-    return( err );
-}
-
-//===========================================================================================================================
-//     TaskTerm
-//===========================================================================================================================
-
-mDNSlocal void  TaskTerm( mDNS *inMDNS )
-{
-    mStatus err;
-    mDNSs32 utc;
-
-    // Tear down all interfaces.
-
-    utc = mDNSPlatformUTC();
-    MarkAllInterfacesInactive( inMDNS, utc );
-    ClearInactiveInterfaces( inMDNS, utc, mDNStrue );
-    check_string( !inMDNS->p->interfaceList, "LEAK: closing without deleting all interfaces" );
-
-    // Close unicast sockets.
-
-    ForgetSocket( &inMDNS->p->unicastSS.sockV4);
-    ForgetSocket( &inMDNS->p->unicastSS.sockV6 );
-
-    // Tear down everything else that was set up in TaskInit then signal back that we're done.
-
-    err = TearDownCommandPipe( inMDNS );
-    check_noerr( err );
-
-    err = semGive( inMDNS->p->quitEvent );
-    check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-}
-
-//===========================================================================================================================
-//     TaskSetupSelect
-//===========================================================================================================================
-
-mDNSlocal void  TaskSetupSelect( mDNS *inMDNS, fd_set *outSet, int *outMaxFd, mDNSs32 inNextEvent, struct timeval *outTimeout )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-    int maxFd;
-    int fd;
-    mDNSs32 delta;
-
-    FD_ZERO( outSet );
-    maxFd = -1;
-
-    // Add the interface-specific sockets.
-
-    for( i = inMDNS->p->interfaceList; i; i = i->next )
-    {
-        fd = i->ss.sockV4;
-        if( IsValidSocket( fd ) )
-        {
-            FD_SET( fd, outSet );
-            if( fd > maxFd ) maxFd = fd;
-        }
-
-        fd = i->ss.sockV6;
-        if( IsValidSocket( fd ) )
-        {
-            FD_SET( fd, outSet );
-            if( fd > maxFd ) maxFd = fd;
-        }
-    }
-
-    // Add the unicast sockets.
-
-    fd = inMDNS->p->unicastSS.sockV4;
-    if( IsValidSocket( fd ) )
-    {
-        FD_SET( fd, outSet );
-        if( fd > maxFd ) maxFd = fd;
-    }
-
-    fd = inMDNS->p->unicastSS.sockV6;
-    if( IsValidSocket( fd ) )
-    {
-        FD_SET( fd, outSet );
-        if( fd > maxFd ) maxFd = fd;
-    }
-
-    // Add the command pipe.
-
-    fd = inMDNS->p->commandPipe;
-    check( fd >= 0 );
-    FD_SET( fd, outSet );
-    if( fd > maxFd ) maxFd = fd;
-
-    check( maxFd > 0 );
-    *outMaxFd = maxFd;
-
-    // Calculate how long to wait before performing idle processing.
-
-    delta = inNextEvent - mDNS_TimeNow( inMDNS );
-    if( delta <= 0 )
-    {
-        // The next task time is now or in the past. Set the timeout to fire immediately.
-
-        outTimeout->tv_sec  = 0;
-        outTimeout->tv_usec = 0;
-    }
-    else
-    {
-        // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
-        // before multiplying to account for integer rounding error and avoid firing the timeout too early.
-
-        outTimeout->tv_sec  = delta / mDNSPlatformOneSecond;
-        outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicro;
-        if( outTimeout->tv_usec >= 1000000L )
-        {
-            outTimeout->tv_sec += 1;
-            outTimeout->tv_usec = 0;
-        }
-    }
-}
-
-//===========================================================================================================================
-//     TaskProcessPackets
-//===========================================================================================================================
-
-mDNSlocal void  TaskProcessPackets( mDNS *inMDNS, SocketSet *inSS, SocketRef inSock )
-{
-    mDNSu32 ifindex;
-    ssize_t n;
-    mDNSu8 *                    buf;
-    size_t size;
-    struct sockaddr_storage from;
-    size_t fromSize;
-    mDNSAddr destAddr;
-    mDNSAddr senderAddr;
-    mDNSIPPort senderPort;
-    mDNSInterfaceID id;
-
-    buf  = (mDNSu8 *) &inMDNS->imsg;
-    size = sizeof( inMDNS->imsg );
-    for( ;; )
-    {
-        ifindex = 0;
-        n = mDNSRecvMsg( inSock, buf, size, &from, sizeof( from ), &fromSize, &destAddr, &ifindex );
-        if( n < 0 ) break;
-        if( from.ss_family == AF_INET )
-        {
-            struct sockaddr_in *        sa4;
-
-            sa4 = (struct sockaddr_in *) &from;
-            senderAddr.type                 = mDNSAddrType_IPv4;
-            senderAddr.ip.v4.NotAnInteger   = sa4->sin_addr.s_addr;
-            senderPort.NotAnInteger         = sa4->sin_port;
-        }
-        else if( from.ss_family == AF_INET6 )
-        {
-            struct sockaddr_in6 *       sa6;
-
-            sa6 = (struct sockaddr_in6 *) &from;
-            senderAddr.type         = mDNSAddrType_IPv6;
-            senderAddr.ip.v6        = *( (mDNSv6Addr *) &sa6->sin6_addr );
-            senderPort.NotAnInteger = sa6->sin6_port;
-        }
-        else
-        {
-            dmsg( kDebugLevelWarning, DEBUG_NAME "%s: WARNING! from addr unknown family %d\n", __ROUTINE__, from.ss_family );
-            continue;
-        }
-
-        // Even though we indicated a specific interface when joining the multicast group, 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/IPV6_PKTINFO options to find the interface
-        // on which the packet arrived, and ignore the packet if it really arrived on some other interface.
-
-        if( mDNSAddrIsDNSMulticast( &destAddr ) )
-        {
-            if( !inSS->info || !inSS->info->exists )
-            {
-                dpkt( kDebugLevelChatty - 3, DEBUG_NAME "  ignored mcast, src=[%#39a],       dst=[%#39a],       if= unicast socket %d\n",
-                      &senderAddr, &destAddr, inSock );
-                continue;
-            }
-            if( ifindex != inSS->info->scopeID )
-            {
-                #if ( DEBUG && MDNS_DEBUG_PACKETS )
-                char ifname[ IF_NAMESIZE ];
-                #endif
-
-                dpkt( kDebugLevelChatty - 3,
-                      DEBUG_NAME "  ignored mcast, src=[%#39a]        dst=[%#39a],       if=%8s(%u) -- really for %8s(%u)\n",
-                      &senderAddr, &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID,
-                      if_indextoname( ifindex, ifname ), ifindex );
-                continue;
-            }
-
-            id = inSS->info->ifinfo.InterfaceID;
-            dpkt( kDebugLevelChatty - 2, DEBUG_NAME "recv %4d bytes, src=[%#39a]:%5hu, dst=[%#39a],       if=%8s(%u) %#p\n",
-                  n, &senderAddr, mDNSVal16( senderPort ), &destAddr, inSS->info->ifinfo.ifname, inSS->info->scopeID, id );
-        }
-        else
-        {
-            NetworkInterfaceInfoVxWorks *       i;
-
-            // For unicast packets, try to find the matching interface.
-
-            for( i = inMDNS->p->interfaceList; i && ( i->scopeID != ifindex ); i = i->next ) {}
-            if( i ) id = i->ifinfo.InterfaceID;
-            else id = NULL;
-        }
-        mDNSCoreReceive( inMDNS, buf, buf + n, &senderAddr, senderPort, &destAddr, MulticastDNSPort, id );
-    }
-}
-
-//===========================================================================================================================
-//     mDNSRecvMsg
-//===========================================================================================================================
-
-mDNSlocal ssize_t
-mDNSRecvMsg(
-    SocketRef inSock,
-    void *      inBuffer,
-    size_t inBufferSize,
-    void *      outFrom,
-    size_t inFromSize,
-    size_t *    outFromSize,
-    mDNSAddr *  outDstAddr,
-    uint32_t *  outIndex )
-{
-    struct msghdr msg;
-    struct iovec iov;
-    ssize_t n;
-    char ancillary[ 1024 ];
-    struct cmsghdr *        cmPtr;
-    int err;
-
-    // Read a packet and any ancillary data. Note: EWOULDBLOCK errors are expected when we've read all pending packets.
-
-    iov.iov_base        = (char *) inBuffer;
-    iov.iov_len         = inBufferSize;
-    msg.msg_name        = (caddr_t) outFrom;
-    msg.msg_namelen     = inFromSize;
-    msg.msg_iov         = &iov;
-    msg.msg_iovlen      = 1;
-    msg.msg_control     = (caddr_t) &ancillary;
-    msg.msg_controllen  = sizeof( ancillary );
-    msg.msg_flags       = 0;
-    n = recvmsg( inSock, &msg, 0 );
-    if( n < 0 )
-    {
-        err = errno_compat();
-        if( err != EWOULDBLOCK ) dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) returned %d, errno %d\n",
-                                       __ROUTINE__, inSock, n, err );
-        goto exit;
-    }
-    if( msg.msg_controllen < sizeof( struct cmsghdr ) )
-    {
-        dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) msg_controllen %d < sizeof( struct cmsghdr ) %u\n",
-              __ROUTINE__, inSock, msg.msg_controllen, sizeof( struct cmsghdr ) );
-        n = mStatus_UnknownErr;
-        goto exit;
-    }
-    if( msg.msg_flags & MSG_CTRUNC )
-    {
-        dmsg( kDebugLevelWarning, DEBUG_NAME "%s: recvmsg(%d) MSG_CTRUNC (%d recv'd)\n", __ROUTINE__, inSock, n );
-        n = mStatus_BadFlagsErr;
-        goto exit;
-    }
-    *outFromSize = msg.msg_namelen;
-
-    // Parse each option out of the ancillary data.
-
-    for( cmPtr = CMSG_FIRSTHDR( &msg ); cmPtr; cmPtr = CMSG_NXTHDR( &msg, cmPtr ) )
-    {
-        if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVDSTADDR ) )
-        {
-            outDstAddr->type                = mDNSAddrType_IPv4;
-            outDstAddr->ip.v4.NotAnInteger  = *( (mDNSu32 *) CMSG_DATA( cmPtr ) );
-        }
-        else if( ( cmPtr->cmsg_level == IPPROTO_IP ) && ( cmPtr->cmsg_type == IP_RECVIF ) )
-        {
-            struct sockaddr_dl *        sdl;
-
-            sdl = (struct sockaddr_dl *) CMSG_DATA( cmPtr );
-            *outIndex = sdl->sdl_index;
-        }
-        else if( ( cmPtr->cmsg_level == IPPROTO_IPV6 ) && ( cmPtr->cmsg_type == IPV6_PKTINFO ) )
-        {
-            struct in6_pktinfo *        pi6;
-
-            pi6 = (struct in6_pktinfo *) CMSG_DATA( cmPtr );
-            outDstAddr->type    = mDNSAddrType_IPv6;
-            outDstAddr->ip.v6   = *( (mDNSv6Addr *) &pi6->ipi6_addr );
-            *outIndex           = pi6->ipi6_ifindex;
-        }
-    }
-
-exit:
-    return( n );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Debugging ==
-#endif
-
-#if ( DEBUG && MDNS_DEBUG_SHOW )
-//===========================================================================================================================
-//     mDNSShow
-//===========================================================================================================================
-
-void    mDNSShow( void );
-
-void    mDNSShow( void )
-{
-    NetworkInterfaceInfoVxWorks *       i;
-    int num;
-    AuthRecord *                        r;
-    mDNSs32 utc;
-
-    // Globals
-
-    dmsg( kDebugLevelMax, "\n-- mDNS globals --\n" );
-    dmsg( kDebugLevelMax, "    sizeof( mDNS )           = %d\n", (int) sizeof( mDNS ) );
-    dmsg( kDebugLevelMax, "    sizeof( ResourceRecord ) = %d\n", (int) sizeof( ResourceRecord ) );
-    dmsg( kDebugLevelMax, "    sizeof( AuthRecord )     = %d\n", (int) sizeof( AuthRecord ) );
-    dmsg( kDebugLevelMax, "    sizeof( CacheRecord )    = %d\n", (int) sizeof( CacheRecord ) );
-    dmsg( kDebugLevelMax, "    mDNSPlatformOneSecond    = %ld\n", mDNSPlatformOneSecond );
-    dmsg( kDebugLevelMax, "    gMDNSTicksToMicro        = %ld\n", gMDNSTicksToMicro );
-    dmsg( kDebugLevelMax, "    gMDNSPtr                 = %#p\n", gMDNSPtr );
-    if( !gMDNSPtr )
-    {
-        dmsg( kDebugLevelMax, "### mDNS not initialized\n" );
-        return;
-    }
-    dmsg( kDebugLevelMax, "    nicelabel                = \"%#s\"\n", gMDNSPtr->nicelabel.c );
-    dmsg( kDebugLevelMax, "    hostLabel                = \"%#s\"\n", gMDNSPtr->hostlabel.c );
-    dmsg( kDebugLevelMax, "    MulticastHostname        = \"%##s\"\n", gMDNSPtr->MulticastHostname.c );
-    dmsg( kDebugLevelMax, "    HIHardware               = \"%#s\"\n", gMDNSPtr->HIHardware.c );
-    dmsg( kDebugLevelMax, "    HISoftware               = \"%#s\"\n", gMDNSPtr->HISoftware.c );
-    dmsg( kDebugLevelMax, "    UnicastPort4/6           = %d/%d\n",
-          mDNSVal16( gMDNSPtr->UnicastPort4 ), mDNSVal16( gMDNSPtr->UnicastPort6 ) );
-    dmsg( kDebugLevelMax, "    unicastSS.sockV4/V6      = %d/%d\n",
-          gMDNSPtr->p->unicastSS.sockV4, gMDNSPtr->p->unicastSS.sockV6 );
-    dmsg( kDebugLevelMax, "    lock                     = %#p\n", gMDNSPtr->p->lock );
-    dmsg( kDebugLevelMax, "    initEvent                = %#p\n", gMDNSPtr->p->initEvent );
-    dmsg( kDebugLevelMax, "    initErr                  = %ld\n", gMDNSPtr->p->initErr );
-    dmsg( kDebugLevelMax, "    quitEvent                = %#p\n", gMDNSPtr->p->quitEvent );
-    dmsg( kDebugLevelMax, "    commandPipe              = %d\n", gMDNSPtr->p->commandPipe );
-    dmsg( kDebugLevelMax, "    taskID                   = %#p\n", gMDNSPtr->p->taskID );
-    dmsg( kDebugLevelMax, "\n" );
-
-    // Interfaces
-
-    utc = mDNSPlatformUTC();
-    dmsg( kDebugLevelMax, "-- mDNS interfaces --\n" );
-    num = 0;
-    for( i = gMDNSPtr->p->interfaceList; i; i = i->next )
-    {
-        dmsg( kDebugLevelMax, "    interface %2d %8s(%u) [%#39a] %s, sockV4 %2d, sockV6 %2d, Age %d\n",
-              num, i->ifinfo.ifname, i->scopeID, &i->ifinfo.ip,
-              i->ifinfo.InterfaceID ? "      REGISTERED" : "*NOT* registered",
-              i->ss.sockV4, i->ss.sockV6, utc - i->lastSeen );
-        ++num;
-    }
-    dmsg( kDebugLevelMax, "\n" );
-
-    // Resource Records
-
-    dmsg( kDebugLevelMax, "-- mDNS resource records --\n" );
-    num = 0;
-    for( r = gMDNSPtr->ResourceRecords; r; r = r->next )
-    {
-        i = (NetworkInterfaceInfoVxWorks *) r->resrec.InterfaceID;
-        if( r->resrec.rrtype == kDNSType_TXT )
-        {
-            RDataBody *         rd;
-            const mDNSu8 *      txt;
-            const mDNSu8 *      end;
-            mDNSu8 size;
-            int nEntries;
-
-            rd = &r->resrec.rdata->u;
-            dmsg( kDebugLevelMax, "    record %2d: %#p %8s(%u): %4d %##s %s:\n", num, i,
-                  i ? i->ifinfo.ifname    : "<any>",
-                  i ? i->scopeID          : 0,
-                  r->resrec.rdlength, r->resrec.name->c, DNSTypeName( r->resrec.rrtype ) );
-
-            nEntries = 0;
-            txt = rd->txt.c;
-            end = txt + r->resrec.rdlength;
-            while( txt < end )
-            {
-                size = *txt++;
-                if( ( txt + size ) > end )
-                {
-                    dmsg( kDebugLevelMax, "        ### ERROR! txt length byte too big (%u, %u max)\n", size, end - txt );
-                    break;
-                }
-                dmsg( kDebugLevelMax, "        string %2d (%3d bytes): \"%.*s\"\n", nEntries, size, size, txt );
-                txt += size;
-                ++nEntries;
-            }
-        }
-        else
-        {
-            dmsg( kDebugLevelMax, "    record %2d: %#p %8s(%u): %s\n", num, i,
-                  i ? i->ifinfo.ifname    : "<any>",
-                  i ? i->scopeID          : 0,
-                  ARDisplayString( gMDNSPtr, r ) );
-        }
-        ++num;
-    }
-    dmsg( kDebugLevelMax, "\n");
-}
-#endif  // DEBUG && MDNS_DEBUG_SHOW
diff --git a/mDNSVxWorks/mDNSVxWorks.h b/mDNSVxWorks/mDNSVxWorks.h
deleted file mode 100644 (file)
index afd41e3..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2005 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __MDNS_VXWORKS_H__
-#define __MDNS_VXWORKS_H__
-
-#include    "vxWorks.h"
-#include    "config.h"
-
-#include    "semLib.h"
-
-#include    "CommonServices.h"
-#include    "DebugServices.h"
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-// Forward Declarations
-
-typedef struct  NetworkInterfaceInfoVxWorks NetworkInterfaceInfoVxWorks;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         SocketSet
-
-    @abstract  Data for IPv4 and IPv6 sockets.
- */
-
-typedef struct  SocketSet SocketSet;
-struct  SocketSet
-{
-    NetworkInterfaceInfoVxWorks *       info;
-    SocketRef sockV4;
-    SocketRef sockV6;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         NetworkInterfaceInfoVxWorks
-
-    @abstract  Interface info for VxWorks.
- */
-
-struct  NetworkInterfaceInfoVxWorks
-{
-    NetworkInterfaceInfo ifinfo;                    // MUST be the first element in this structure.
-    NetworkInterfaceInfoVxWorks *       next;
-    mDNSu32 exists;                                 // 1 = currently exists in getifaddrs list; 0 = doesn't.
-                                                    // 2 = exists, but McastTxRx state changed.
-    mDNSs32 lastSeen;                               // If exists == 0, last time this interface appeared in getifaddrs list.
-    mDNSu32 scopeID;                                // Interface index / IPv6 scope ID.
-    int family;                                     // Socket address family of the primary socket.
-    mDNSBool multicast;
-    SocketSet ss;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         mDNS_PlatformSupport_struct
-
-    @abstract  Data for mDNS platform plugin.
- */
-
-struct  mDNS_PlatformSupport_struct
-{
-    NetworkInterfaceInfoVxWorks *       interfaceList;
-    SocketSet unicastSS;
-    domainlabel userNiceLabel;
-    domainlabel userHostLabel;
-
-    SEM_ID lock;
-    SEM_ID initEvent;
-    mStatus initErr;
-    SEM_ID quitEvent;
-    int commandPipe;
-    int taskID;
-    mDNSBool quit;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       mDNSReconfigure
-
-    @abstract  Tell mDNS that the configuration has changed. Call when IP address changes, link goes up after being down, etc.
-
-    @discussion
-
-    VxWorks does not provide a generic mechanism for getting notified when network interfaces change so this routines
-    provides a way for BSP-specific code to signal mDNS that something has changed and it should re-build its interfaces.
- */
-
-void    mDNSReconfigure( void );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       mDNSDeferIPv4
-
-    @abstract  Tells mDNS whether to defer advertising of IPv4 interfaces.
-
-    @discussion
-
-    To workaround problems with clients getting a link-local IPv4 address before a DHCP address is acquired, this allows
-    external code to defer advertising of IPv4 addresses until a DHCP lease has been acquired (or it times out).
- */
-
-void    mDNSDeferIPv4( mDNSBool inDefer );
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif  // __MDNS_VXWORKS_H__
diff --git a/mDNSVxWorks/mDNSVxWorksIPv4Only.c b/mDNSVxWorks/mDNSVxWorksIPv4Only.c
deleted file mode 100644 (file)
index 38a21d2..0000000
+++ /dev/null
@@ -1,2088 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2003 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.
-
-    Contains:  mDNS platform plugin for VxWorks.
-
-    Copyright:  Copyright (C) 2002-2004 Apple Computer, Inc., All Rights Reserved.
-
-    Notes for non-Apple platforms:
-
-        TARGET_NON_APPLE should be defined to 1 to avoid relying on Apple-only header files, macros, or functions.
-
-    To Do:
-
-        - Add support for IPv6 (needs VxWorks IPv6 support).
- */
-
-// Set up the debug library to use the default category (see DebugServicesLite.h for details).
-
-#if ( !TARGET_NON_APPLE )
-    #define DEBUG_USE_DEFAULT_CATEGORY      1
-#endif
-
-#include    <stdarg.h>
-#include    <stddef.h>
-#include    <stdio.h>
-#include    <stdlib.h>
-#include    <string.h>
-
-#include    <sys/types.h>
-#include    <arpa/inet.h>
-#include    <fcntl.h>
-#include    <netinet/if_ether.h>
-#include    <netinet/in.h>
-#include    <netinet/ip.h>
-#include    <sys/ioctl.h>
-#include    <sys/socket.h>
-#include    <unistd.h>
-
-#include    "vxWorks.h"
-#include    "ifLib.h"
-#include    "inetLib.h"
-#include    "pipeDrv.h"
-#include    "selectLib.h"
-#include    "semLib.h"
-#include    "sockLib.h"
-#include    "sysLib.h"
-#include    "taskLib.h"
-#include    "tickLib.h"
-
-#include    "config.h"
-
-#if ( !TARGET_NON_APPLE )
-    #include    "ACP/ACPUtilities.h"
-    #include    "Support/DebugServicesLite.h"
-    #include    "Support/MiscUtilities.h"
-#endif
-
-#include    "mDNSEmbeddedAPI.h"
-
-#include    "mDNSVxWorks.h"
-
-#if 0
-#pragma mark == Preprocessor ==
-#endif
-
-//===========================================================================================================================
-//     Preprocessor
-//===========================================================================================================================
-
-#if ( !TARGET_NON_APPLE )
-debug_log_new_default_category( mdns );
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#define DEBUG_NAME                      "[mDNS] "
-
-#define kMDNSDefaultName                "My-Device"
-
-#define kMDNSTaskName                   "tMDNS"
-#define kMDNSTaskPriority               102
-#define kMDNSTaskStackSize              49152
-
-#define kMDNSPipeName                   "/pipe/mDNS"
-#define kMDNSPipeMessageQueueSize       32
-#define kMDNSPipeMessageSize            1
-
-#define kInvalidSocketRef               -1
-
-typedef uint8_t MDNSPipeCommandCode;
-enum
-{
-    kMDNSPipeCommandCodeInvalid         = 0,
-    kMDNSPipeCommandCodeReschedule      = 1,
-    kMDNSPipeCommandCodeReconfigure     = 2,
-    kMDNSPipeCommandCodeQuit            = 3
-};
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-//     Structures
-//===========================================================================================================================
-
-typedef int MDNSSocketRef;
-
-struct  MDNSInterfaceItem
-{
-    MDNSInterfaceItem *         next;
-    char name[ 32 ];
-    MDNSSocketRef multicastSocketRef;
-    MDNSSocketRef sendingSocketRef;
-    NetworkInterfaceInfo hostSet;
-    mDNSBool hostRegistered;
-
-    int sendMulticastCounter;
-    int sendUnicastCounter;
-    int sendErrorCounter;
-
-    int recvCounter;
-    int recvErrorCounter;
-    int recvLoopCounter;
-};
-
-#if 0
-#pragma mark == Macros ==
-#endif
-
-//===========================================================================================================================
-//     Macros
-//===========================================================================================================================
-
-#if ( TARGET_NON_APPLE )
-
-// Do-nothing versions of the debugging macros for non-Apple platforms.
-
-    #define check(assertion)
-    #define check_string( assertion, cstring )
-    #define check_noerr(err)
-    #define check_noerr_string( error, cstring )
-    #define check_errno( assertion, errno_value )
-    #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)
-    #define require_errno( assertion, errno_value, label )                  do { if( !(assertion) ) goto label;} while(0)
-    #define require_errno_action( assertion, errno_value, label, action )   do { if( !(assertion) ) { {action;}; goto label; } } while(0)
-
-    #define dlog( ARGS... )
-
-    #define DEBUG_UNUSED( X )           (void)( X )
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-// ifIndexToIfp is in net/if.c, but not exported by net/if.h so provide it here.
-
-extern struct ifnet * ifIndexToIfp(int ifIndex);
-
-// Platform Internals
-
-mDNSlocal void      SetupNames( mDNS * const inMDNS );
-mDNSlocal mStatus   SetupInterfaceList( mDNS * const inMDNS );
-mDNSlocal mStatus   TearDownInterfaceList( mDNS * const inMDNS );
-mDNSlocal mStatus   SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inAddr, MDNSInterfaceItem **outItem );
-mDNSlocal mStatus   TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inItem );
-mDNSlocal mStatus
-SetupSocket(
-    mDNS * const inMDNS,
-    const struct ifaddrs *  inAddr,
-    mDNSIPPort inPort,
-    MDNSSocketRef *         outSocketRef );
-
-// Commands
-
-mDNSlocal mStatus   SetupCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus   TearDownCommandPipe( mDNS * const inMDNS );
-mDNSlocal mStatus   SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode );
-mDNSlocal mStatus   ProcessCommand( mDNS * const inMDNS );
-mDNSlocal void      ProcessCommandReconfigure( mDNS *inMDNS );
-
-// Threads
-
-mDNSlocal mStatus   SetupTask( mDNS * const inMDNS );
-mDNSlocal mStatus   TearDownTask( mDNS * const inMDNS );
-mDNSlocal void      Task( mDNS *inMDNS );
-mDNSlocal mStatus   TaskInit( mDNS *inMDNS );
-mDNSlocal void      TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket );
-mDNSlocal void      TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout );
-mDNSlocal void      TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef );
-
-// Utilities
-
-#if ( TARGET_NON_APPLE )
-mDNSlocal void  GenerateUniqueHostName( char *outName, long *ioSeed );
-mDNSlocal void  GenerateUniqueDNSName( char *outName, long *ioSeed );
-#endif
-
-// Platform Accessors
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-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 );
-
-#ifdef  __cplusplus
-}
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-mDNSlocal mDNS *                    gMDNSPtr                            = NULL;
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSlocal mDNSs32 gMDNSTicksToMicrosecondsMultiplier  = 0;
-
-// Platform support
-
-mDNSs32 mDNSPlatformOneSecond;
-
-#if 0
-#pragma mark -
-#pragma mark == Public APIs ==
-#endif
-
-//===========================================================================================================================
-//     mDNSReconfigure
-//===========================================================================================================================
-
-void    mDNSReconfigure( void )
-{
-    // Send a "reconfigure" command to the MDNS task.
-
-    if( gMDNSPtr )
-    {
-        SendCommand( gMDNSPtr, kMDNSPipeCommandCodeReconfigure );
-    }
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Support ==
-#endif
-
-//===========================================================================================================================
-//     mDNSPlatformInit
-//===========================================================================================================================
-
-mStatus mDNSPlatformInit( mDNS * const inMDNS )
-{
-    mStatus err;
-
-    dlog( kDebugLevelInfo, DEBUG_NAME "platform init\n" );
-
-    // Initialize variables.
-
-    mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
-    inMDNS->p                           = &gMDNSPlatformSupport;
-    inMDNS->p->commandPipe              = ERROR;
-    inMDNS->p->task                     = ERROR;
-    inMDNS->p->rescheduled              = 1;        // Default to rescheduled until fully initialized.
-    mDNSPlatformOneSecond               = sysClkRateGet();
-    gMDNSTicksToMicrosecondsMultiplier  = ( 1000000L / mDNSPlatformOneSecond );
-
-    // Allocate semaphores.
-
-    inMDNS->p->lockID = semMCreate( SEM_Q_FIFO );
-    require_action( inMDNS->p->lockID, exit, err = mStatus_NoMemoryErr );
-
-    inMDNS->p->readyEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
-    require_action( inMDNS->p->readyEvent, exit, err = mStatus_NoMemoryErr );
-
-    inMDNS->p->quitEvent = semBCreate( SEM_Q_FIFO, SEM_EMPTY );
-    require_action( inMDNS->p->quitEvent, exit, err = mStatus_NoMemoryErr );
-
-    gMDNSPtr = inMDNS;
-
-    // Set up the task and wait for it to initialize. Initialization is done from the task instead of here to avoid
-    // stack space issues. Some of the initialization may require a larger stack than the current task supports.
-
-    err = SetupTask( inMDNS );
-    require_noerr( err, exit );
-
-    err = semTake( inMDNS->p->readyEvent, WAIT_FOREVER );
-    require_noerr( err, exit );
-    err = inMDNS->p->taskInitErr;
-    require_noerr( err, exit );
-
-    mDNSCoreInitComplete( inMDNS, err );
-
-exit:
-    if( err )
-    {
-        mDNSPlatformClose( inMDNS );
-    }
-    dlog( kDebugLevelInfo, DEBUG_NAME "platform init done (err=%ld)\n", err );
-    return( err );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformClose
-//===========================================================================================================================
-
-void    mDNSPlatformClose( mDNS * const inMDNS )
-{
-    mStatus err;
-
-    dlog( kDebugLevelInfo, DEBUG_NAME "platform close\n" );
-    check( inMDNS );
-
-    // Tear everything down.
-
-    err = TearDownTask( inMDNS );
-    check_noerr( err );
-
-    err = TearDownInterfaceList( inMDNS );
-    check_noerr( err );
-
-    err = TearDownCommandPipe( inMDNS );
-    check_noerr( err );
-
-    gMDNSPtr = NULL;
-
-    // Release semaphores.
-
-    if( inMDNS->p->quitEvent )
-    {
-        semDelete( inMDNS->p->quitEvent );
-        inMDNS->p->quitEvent = 0;
-    }
-    if( inMDNS->p->readyEvent )
-    {
-        semDelete( inMDNS->p->readyEvent );
-        inMDNS->p->readyEvent = 0;
-    }
-    if( inMDNS->p->lockID )
-    {
-        semDelete( inMDNS->p->lockID );
-        inMDNS->p->lockID = 0;
-    }
-
-    dlog( kDebugLevelInfo, DEBUG_NAME "platform close done\n" );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mStatus
-mDNSPlatformSendUDP(
-    const mDNS * const inMDNS,
-    const void * const inMsg,
-    const mDNSu8 * const inMsgEnd,
-    mDNSInterfaceID inInterfaceID,
-    const mDNSAddr *            inDstIP,
-    mDNSIPPort inDstPort )
-{
-    mStatus err;
-    MDNSInterfaceItem *     item;
-    struct sockaddr_in addr;
-    int n;
-
-    dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP\n" );
-
-    // Check parameters.
-
-    check( inMDNS );
-    check( inMsg );
-    check( inMsgEnd );
-    check( inInterfaceID );
-    check( inDstIP );
-    if( inDstIP->type != mDNSAddrType_IPv4 )
-    {
-        err = mStatus_BadParamErr;
-        goto exit;
-    }
-
-#if ( DEBUG )
-    // Make sure the InterfaceID is valid.
-
-    for( item = inMDNS->p->interfaceList; item; item = item->next )
-    {
-        if( item == (MDNSInterfaceItem *) inInterfaceID )
-        {
-            break;
-        }
-    }
-    require_action( item, exit, err = mStatus_NoSuchNameErr );
-#endif
-
-    // Send the packet.
-
-    item = (MDNSInterfaceItem *) inInterfaceID;
-    check( item->sendingSocketRef != kInvalidSocketRef );
-
-    mDNSPlatformMemZero( &addr, sizeof( addr ) );
-    addr.sin_family         = AF_INET;
-    addr.sin_port           = inDstPort.NotAnInteger;
-    addr.sin_addr.s_addr    = inDstIP->ip.v4.NotAnInteger;
-
-    n = inMsgEnd - ( (const mDNSu8 * const) inMsg );
-    n = sendto( item->sendingSocketRef, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
-    check_errno( n, errno );
-
-    item->sendErrorCounter      += ( n < 0 );
-    item->sendMulticastCounter  += ( inDstPort.NotAnInteger == MulticastDNSPort.NotAnInteger );
-    item->sendUnicastCounter    += ( inDstPort.NotAnInteger != MulticastDNSPort.NotAnInteger );
-
-    dlog( kDebugLevelChatty, DEBUG_NAME "sent (to=%u.%u.%u.%u:%hu)\n",
-          inDstIP->ip.v4.b[ 0 ], inDstIP->ip.v4.b[ 1 ], inDstIP->ip.v4.b[ 2 ], inDstIP->ip.v4.b[ 3 ],
-          htons( inDstPort.NotAnInteger ) );
-    err = mStatus_NoError;
-
-exit:
-    dlog( kDebugLevelChatty, DEBUG_NAME "platform send UDP done\n" );
-    return( err );
-}
-
-//===========================================================================================================================
-//     Connection-oriented (TCP) functions
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTCPConnect(const mDNSAddr *dst, mDNSOpaque16 dstport, mDNSInterfaceID InterfaceID,
-                                          TCPConnectionCallback callback, void *context, int *descriptor)
-{
-    (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)
-{
-    (void)sd;           // Unused
-}
-
-mDNSexport long mDNSPlatformReadTCP(int sd, void *buf, unsigned long buflen)
-{
-    (void)sd;           // Unused
-    (void)buf;          // Unused
-    (void)buflen;           // Unused
-    return(0);
-}
-
-mDNSexport long mDNSPlatformWriteTCP(int sd, const char *msg, unsigned long len)
-{
-    (void)sd;           // Unused
-    (void)msg;          // Unused
-    (void)len;          // Unused
-    return(0);
-}
-
-//===========================================================================================================================
-//     mDNSPlatformLock
-//===========================================================================================================================
-
-void    mDNSPlatformLock( const mDNS * const inMDNS )
-{
-    check( inMDNS->p->lockID );
-
-    if( inMDNS->p->lockID )
-    {
-        #if ( TARGET_NON_APPLE )
-        semTake( inMDNS->p->lockID, WAIT_FOREVER );
-        #else
-        semTakeDeadlockDetect( inMDNS->p->lockID, WAIT_FOREVER );
-        #endif
-    }
-}
-
-//===========================================================================================================================
-//     mDNSPlatformUnlock
-//===========================================================================================================================
-
-void    mDNSPlatformUnlock( const mDNS * const inMDNS )
-{
-    check( inMDNS );
-    check( inMDNS->p );
-    check( inMDNS->p->lockID );
-    check_string( inMDNS->p->task != ERROR, "mDNS task not started" );
-
-    // When an API routine is called, "m->NextScheduledEvent" is reset to "timenow" before calling mDNSPlatformUnlock()
-    // Since our main mDNS_Execute() loop is on a different thread, we need to wake up that thread to:
-    // (a) handle immediate work (if any) resulting from this API call
-    // (b) calculate the next sleep time between now and the next interesting event
-
-    if( ( mDNS_TimeNow(inMDNS) - inMDNS->NextScheduledEvent ) >= 0 )
-    {
-        // We only need to send the reschedule event when called from a task other than the mDNS task since if we are
-        // called from mDNS task, we'll loop back and call mDNS_Execute. This avoids filling up the command queue.
-
-        if( ( inMDNS->p->rescheduled++ == 0 ) && ( taskIdSelf() != inMDNS->p->task ) )
-        {
-            SendCommand( inMDNS, kMDNSPipeCommandCodeReschedule );
-        }
-    }
-
-    if( inMDNS->p->lockID )
-    {
-        semGive( inMDNS->p->lockID );
-    }
-}
-
-//===========================================================================================================================
-//     mDNSPlatformStrLen
-//===========================================================================================================================
-
-mDNSu32  mDNSPlatformStrLen( const void *inSrc )
-{
-    check( inSrc );
-
-    return( (mDNSu32) strlen( (const char *) inSrc ) );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformStrCopy
-//===========================================================================================================================
-
-void    mDNSPlatformStrCopy( void *inDst, const void *inSrc )
-{
-    check( inSrc );
-    check( inDst );
-
-    strcpy( (char *) inDst, (const char*) inSrc );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemCopy
-//===========================================================================================================================
-
-void    mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-    check( inSrc );
-    check( inDst );
-
-    memcpy( inDst, inSrc, inSize );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemSame
-//===========================================================================================================================
-
-mDNSBool    mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-    check( inSrc );
-    check( inDst );
-
-    return( memcmp( inSrc, inDst, inSize ) == 0 );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemZero
-//===========================================================================================================================
-
-void    mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
-{
-    check( inDst );
-
-    memset( inDst, 0, inSize );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemAllocate
-//===========================================================================================================================
-
-mDNSexport void *   mDNSPlatformMemAllocate( mDNSu32 inSize )
-{
-    void *      mem;
-
-    check( inSize > 0 );
-
-    mem = malloc( inSize );
-    check( mem );
-
-    return( mem );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemFree
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformMemFree( void *inMem )
-{
-    check( inMem );
-
-    free( inMem );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformRandomSeed
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformRandomSeed(void)
-{
-    return( tickGet() );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTimeInit
-//===========================================================================================================================
-
-mDNSexport mStatus mDNSPlatformTimeInit( void )
-{
-    // No special setup is required on VxWorks -- we just use tickGet().
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformRawTime
-//===========================================================================================================================
-
-mDNSs32 mDNSPlatformRawTime( void )
-{
-    return( (mDNSs32) tickGet() );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformUTC
-//===========================================================================================================================
-
-mDNSexport mDNSs32  mDNSPlatformUTC( void )
-{
-    return( -1 );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceNameToID
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
-{
-    mStatus err;
-    MDNSInterfaceItem *     ifd;
-
-    check( inMDNS );
-    check( inMDNS->p );
-    check( inName );
-
-    // Search for an interface with the specified name,
-
-    for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
-    {
-        if( strcmp( ifd->name, inName ) == 0 )
-        {
-            break;
-        }
-    }
-    if( !ifd )
-    {
-        err = mStatus_NoSuchNameErr;
-        goto exit;
-    }
-
-    // Success!
-
-    if( outID )
-    {
-        *outID = (mDNSInterfaceID) ifd;
-    }
-    err = mStatus_NoError;
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceIDToInfo
-//===========================================================================================================================
-
-mStatus mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
-{
-    mStatus err;
-    MDNSInterfaceItem *     ifd;
-
-    check( inMDNS );
-    check( inID );
-    check( outInfo );
-
-    // Search for an interface with the specified ID,
-
-    for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
-    {
-        if( ifd == (MDNSInterfaceItem *) inID )
-        {
-            break;
-        }
-    }
-    if( !ifd )
-    {
-        err = mStatus_NoSuchNameErr;
-        goto exit;
-    }
-
-    // Success!
-
-    outInfo->name   = ifd->name;
-    outInfo->ip     = ifd->hostSet.ip;
-    err             = mStatus_NoError;
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     debugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS )
-mDNSexport void debugf_( const char *format, ... )
-{
-    char buffer[ 512 ];
-    va_list args;
-    mDNSu32 length;
-
-    va_start( args, format );
-    length = mDNS_vsnprintf( buffer, sizeof( buffer ), format, args );
-    va_end( args );
-
-    dlog( kDebugLevelInfo, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-//     verbosedebugf_
-//===========================================================================================================================
-
-#if ( MDNS_DEBUGMSGS > 1 )
-mDNSexport void verbosedebugf_( const char *format, ... )
-{
-    char buffer[ 512 ];
-    va_list args;
-    mDNSu32 length;
-
-    va_start( args, format );
-    length = mDNS_vsnprintf( buffer, sizeof( buffer ), format, args );
-    va_end( args );
-
-    dlog( kDebugLevelVerbose, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-//     LogMsg
-//===========================================================================================================================
-
-void LogMsg( const char *inFormat, ... )
-{
-    char buffer[ 512 ];
-    va_list args;
-    mDNSu32 length;
-
-    va_start( args, inFormat );
-    length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-    va_end( args );
-
-    dlog( kDebugLevelWarning, "%s\n", buffer );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Internals ==
-#endif
-
-//===========================================================================================================================
-//     SetupNames
-//===========================================================================================================================
-
-mDNSlocal void  SetupNames( mDNS * const inMDNS )
-{
-    char tempCString[ 128 ];
-    mDNSu8 tempPString[ 128 ];
-    mDNSu8 *        namePtr;
-
-    // Set up the host name.
-
-    tempCString[ 0 ] = '\0';
-    GenerateUniqueHostName( tempCString, NULL );
-    check( tempCString[ 0 ] != '\0' );
-    if( tempCString[ 0 ] == '\0' )
-    {
-        // No name so use the default.
-
-        strcpy( tempCString, kMDNSDefaultName );
-    }
-    inMDNS->nicelabel.c[ 0 ] = strlen( tempCString );
-    memcpy( &inMDNS->nicelabel.c[ 1 ], tempCString, inMDNS->nicelabel.c[ 0 ] );
-    check( inMDNS->nicelabel.c[ 0 ] > 0 );
-
-    // Set up the DNS name.
-
-    tempCString[ 0 ] = '\0';
-    GenerateUniqueDNSName( tempCString, NULL );
-    if( tempCString[ 0 ] != '\0' )
-    {
-        tempPString[ 0 ] = strlen( tempCString );
-        memcpy( &tempPString[ 1 ], tempCString, tempPString[ 0 ] );
-        namePtr = tempPString;
-    }
-    else
-    {
-        // No DNS name so use the host name.
-
-        namePtr = inMDNS->nicelabel.c;
-    }
-    ConvertUTF8PstringToRFC1034HostLabel( namePtr, &inMDNS->hostlabel );
-    if( inMDNS->hostlabel.c[ 0 ] == 0 )
-    {
-        // Nice name has no characters that are representable as an RFC 1034 name (e.g. Japanese) so use the default.
-
-        MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
-    }
-    check( inMDNS->hostlabel.c[ 0 ] > 0 );
-
-    mDNS_SetFQDN( inMDNS );
-
-    dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
-    dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
-}
-
-//===========================================================================================================================
-//     SetupInterfaceList
-//===========================================================================================================================
-
-mDNSlocal mStatus   SetupInterfaceList( mDNS * const inMDNS )
-{
-    mStatus err;
-    struct ifaddrs *            addrs;
-    struct ifaddrs *            p;
-    uint32_t flagMask;
-    uint32_t flagTest;
-    MDNSInterfaceItem **        next;
-    MDNSInterfaceItem *         item;
-
-    addrs = NULL;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list\n" );
-    check( inMDNS );
-
-    // Tear down any existing interfaces that may be set up.
-
-    TearDownInterfaceList( inMDNS );
-    inMDNS->p->interfaceList = NULL;
-    next = &inMDNS->p->interfaceList;
-
-    // Set up each interface that is active, multicast-capable, and not the loopback interface or point-to-point.
-
-    flagMask = IFF_UP | IFF_MULTICAST | IFF_LOOPBACK | IFF_POINTOPOINT;
-    flagTest = IFF_UP | IFF_MULTICAST;
-
-    err = getifaddrs( &addrs );
-    require_noerr( err, exit );
-
-    for( p = addrs; p; p = p->ifa_next )
-    {
-        if( ( p->ifa_flags & flagMask ) == flagTest )
-        {
-            err = SetupInterface( inMDNS, p, &item );
-            require_noerr( err, exit );
-
-            *next = item;
-            next = &item->next;
-        }
-    }
-    err = mStatus_NoError;
-
-exit:
-    if( addrs )
-    {
-        freeifaddrs( addrs );
-    }
-    if( err )
-    {
-        TearDownInterfaceList( inMDNS );
-    }
-    dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface list done (err=%ld)\n", err );
-    return( err );
-}
-
-//===========================================================================================================================
-//     TearDownInterfaceList
-//===========================================================================================================================
-
-mDNSlocal mStatus   TearDownInterfaceList( mDNS * const inMDNS )
-{
-    dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list\n" );
-    check( inMDNS );
-
-    // Tear down all the interfaces.
-
-    while( inMDNS->p->interfaceList )
-    {
-        MDNSInterfaceItem *     item;
-
-        item = inMDNS->p->interfaceList;
-        inMDNS->p->interfaceList = item->next;
-
-        TearDownInterface( inMDNS, item );
-    }
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down interface list done\n" );
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     SetupInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus   SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inAddr, MDNSInterfaceItem **outItem )
-{
-    mStatus err;
-    MDNSInterfaceItem *             item;
-    MDNSSocketRef socketRef;
-    const struct sockaddr_in *      ipv4, *mask;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface (name=%s)\n", inAddr->ifa_name );
-    check( inMDNS );
-    check( inAddr );
-    check( inAddr->ifa_addr );
-    ipv4 = (const struct sockaddr_in *) inAddr->ifa_addr;
-    mask = (const struct sockaddr_in *) inAddr->ifa_netmask;
-    check( outItem );
-
-    // Allocate memory for the info item.
-
-    item = (MDNSInterfaceItem *) calloc( 1, sizeof( *item ) );
-    require_action( item, exit, err = mStatus_NoMemoryErr );
-    strcpy( item->name, inAddr->ifa_name );
-    item->multicastSocketRef    = kInvalidSocketRef;
-    item->sendingSocketRef      = kInvalidSocketRef;
-
-    // Set up the multicast DNS (port 5353) socket for this interface.
-
-    err = SetupSocket( inMDNS, inAddr, MulticastDNSPort, &socketRef );
-    require_noerr( err, exit );
-    item->multicastSocketRef = socketRef;
-
-    // Set up the sending socket for this interface.
-
-    err = SetupSocket( inMDNS, inAddr, zeroIPPort, &socketRef );
-    require_noerr( err, exit );
-    item->sendingSocketRef = socketRef;
-
-    // Register this interface with mDNS.
-
-    item->hostSet.InterfaceID             = (mDNSInterfaceID) item;
-    item->hostSet.ip.type               = mDNSAddrType_IPv4;
-    item->hostSet.ip.ip.v4.NotAnInteger = ipv4->sin_addr.s_addr;
-    item->hostSet.mask.type               = mDNSAddrType_IPv4;
-    item->hostSet.mask.ip.v4.NotAnInteger = mask->sin_addr.s_addr;
-    item->hostSet.ifname[0]               = 0;
-    item->hostSet.Advertise               = inMDNS->AdvertiseLocalAddresses;
-    item->hostSet.McastTxRx               = mDNStrue;
-
-    err = mDNS_RegisterInterface( inMDNS, &item->hostSet, NormalActivation );
-    require_noerr( err, exit );
-    item->hostRegistered = mDNStrue;
-
-    dlog( kDebugLevelInfo, DEBUG_NAME "Registered IP address: %u.%u.%u.%u\n",
-          item->hostSet.ip.ip.v4.b[ 0 ], item->hostSet.ip.ip.v4.b[ 1 ],
-          item->hostSet.ip.ip.v4.b[ 2 ], item->hostSet.ip.ip.v4.b[ 3 ] );
-
-    // Success!
-
-    *outItem = item;
-    item = NULL;
-
-exit:
-    if( item )
-    {
-        TearDownInterface( inMDNS, item );
-    }
-    dlog( kDebugLevelVerbose, DEBUG_NAME "setting up interface done (name=%s, err=%ld)\n", inAddr->ifa_name, err );
-    return( err );
-}
-
-//===========================================================================================================================
-//     TearDownInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus   TearDownInterface( mDNS * const inMDNS, MDNSInterfaceItem *inItem )
-{
-    MDNSSocketRef socketRef;
-
-    check( inMDNS );
-    check( inItem );
-
-    // Deregister this interface with mDNS.
-
-    dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering IP address: %u.%u.%u.%u\n",
-          inItem->hostSet.ip.ip.v4.b[ 0 ], inItem->hostSet.ip.ip.v4.b[ 1 ],
-          inItem->hostSet.ip.ip.v4.b[ 2 ], inItem->hostSet.ip.ip.v4.b[ 3 ] );
-
-    if( inItem->hostRegistered )
-    {
-        inItem->hostRegistered = mDNSfalse;
-        mDNS_DeregisterInterface( inMDNS, &inItem->hostSet, NormalActivation );
-    }
-
-    // Close the multicast socket.
-
-    socketRef = inItem->multicastSocketRef;
-    inItem->multicastSocketRef = kInvalidSocketRef;
-    if( socketRef != kInvalidSocketRef )
-    {
-        dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down multicast socket %d\n", socketRef );
-        close( socketRef );
-    }
-
-    // Close the sending socket.
-
-    socketRef = inItem->sendingSocketRef;
-    inItem->sendingSocketRef = kInvalidSocketRef;
-    if( socketRef != kInvalidSocketRef )
-    {
-        dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down sending socket %d\n", socketRef );
-        close( socketRef );
-    }
-
-    // Free the memory used by the interface info.
-
-    free( inItem );
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus
-SetupSocket(
-    mDNS * const inMDNS,
-    const struct ifaddrs *  inAddr,
-    mDNSIPPort inPort,
-    MDNSSocketRef *         outSocketRef  )
-{
-    mStatus err;
-    MDNSSocketRef socketRef;
-    int option;
-    unsigned char optionByte;
-    struct ip_mreq mreq;
-    const struct sockaddr_in *      ipv4;
-    struct sockaddr_in addr;
-    mDNSv4Addr ip;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done\n" );
-    check( inMDNS );
-    check( inAddr );
-    check( inAddr->ifa_addr );
-    ipv4 = (const struct sockaddr_in *) inAddr->ifa_addr;
-    check( outSocketRef );
-
-    // Set up a UDP socket for multicast DNS.
-
-    socketRef = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-    require_errno_action( socketRef, errno, exit, err = mStatus_UnknownErr );
-
-    // A port of zero means this socket is for sending and should be set up for sending. Otherwise, it is for receiving
-    // and should be set up for receiving. The reason for separate sending vs receiving sockets is to workaround problems
-    // with VxWorks IP stack when using dynamic IP configuration such as DHCP (problems binding to wildcard IP when the
-    // IP address later changes). Since we have to bind the Multicast DNS address to workaround these issues we have to
-    // use a separate sending socket since it is illegal to send a packet with a multicast source address (RFC 1122).
-
-    if( inPort.NotAnInteger != zeroIPPort.NotAnInteger )
-    {
-        // Turn on reuse port option so multiple servers can listen for Multicast DNS packets.
-
-        option = 1;
-        err = setsockopt( socketRef, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
-        check_errno( err, errno );
-
-        // Join the all-DNS multicast group so we receive Multicast DNS packets.
-
-        ip.NotAnInteger             = ipv4->sin_addr.s_addr;
-        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 );
-
-        // Bind to the multicast DNS address and port 5353.
-
-        mDNSPlatformMemZero( &addr, sizeof( addr ) );
-        addr.sin_family         = AF_INET;
-        addr.sin_port           = inPort.NotAnInteger;
-        addr.sin_addr.s_addr    = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
-        err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
-        check_errno( err, errno );
-
-        dlog( kDebugLevelVerbose, DEBUG_NAME "setting up socket done (%s, %u.%u.%u.%u:%u, %d)\n",
-              inAddr->ifa_name, ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], ntohs( inPort.NotAnInteger ), socketRef );
-    }
-    else
-    {
-        // Bind to the interface address and multicast DNS port.
-
-        ip.NotAnInteger         = ipv4->sin_addr.s_addr;
-        mDNSPlatformMemZero( &addr, sizeof( addr ) );
-        addr.sin_family         = AF_INET;
-        addr.sin_port           = MulticastDNSPort.NotAnInteger;
-        addr.sin_addr.s_addr    = ip.NotAnInteger;
-        err = bind( socketRef, (struct sockaddr *) &addr, sizeof( addr ) );
-        check_errno( err, errno );
-
-        // Direct multicast packets to the specified interface.
-
-        addr.sin_addr.s_addr = ip.NotAnInteger;
-        err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_IF, (char *) &addr.sin_addr, sizeof( addr.sin_addr ) );
-        check_errno( err, errno );
-
-        // Set the TTL of outgoing unicast packets to 255 (helps against spoofing).
-
-        option = 255;
-        err = setsockopt( socketRef, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
-        check_errno( err, errno );
-
-        // Set the TTL of outgoing multicast packets to 255 (helps against spoofing).
-
-        optionByte = 255;
-        err = setsockopt( socketRef, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &optionByte, sizeof( optionByte ) );
-        check_errno( err, errno );
-
-        // WARNING: Setting this option causes unicast responses to be routed to the wrong interface so they are
-        // WARNING: disabled. These options were only hints to improve 802.11 performance (and not implemented) anyway.
-
-#if 0
-        // Mark packets as high-throughput/low-delay (i.e. lowest reliability) to maximize 802.11 multicast rate.
-
-        option = IPTOS_LOWDELAY | IPTOS_THROUGHPUT;
-        err = setsockopt( socketRef, IPPROTO_IP, IP_TOS, (char *) &option, sizeof( option ) );
-        check_errno( err, errno );
-#endif
-
-        dlog( kDebugLevelVerbose, DEBUG_NAME "setting up sending socket done (%s, %u.%u.%u.%u, %d)\n",
-              inAddr->ifa_name, ip.b[ 0 ], ip.b[ 1 ], ip.b[ 2 ], ip.b[ 3 ], socketRef );
-    }
-
-    // Success!
-
-    *outSocketRef = socketRef;
-    socketRef = kInvalidSocketRef;
-    err = mStatus_NoError;
-
-exit:
-    if( socketRef != kInvalidSocketRef )
-    {
-        close( socketRef );
-    }
-    return( err );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Commands ==
-#endif
-
-//===========================================================================================================================
-//     SetupCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus   SetupCommandPipe( mDNS * const inMDNS )
-{
-    mStatus err;
-
-    // Clean up any leftover command pipe.
-
-    TearDownCommandPipe( inMDNS );
-
-    // Create the pipe device and open it.
-
-    pipeDevCreate( kMDNSPipeName, kMDNSPipeMessageQueueSize, kMDNSPipeMessageSize );
-
-    inMDNS->p->commandPipe = open( kMDNSPipeName, O_RDWR, 0 );
-    require_errno_action( inMDNS->p->commandPipe, errno, exit, err = mStatus_UnsupportedErr );
-
-    err = mStatus_NoError;
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     TearDownCommandPipe
-//===========================================================================================================================
-
-mDNSlocal mStatus   TearDownCommandPipe( mDNS * const inMDNS )
-{
-    if( inMDNS->p->commandPipe != ERROR )
-    {
-        close( inMDNS->p->commandPipe );
-#ifdef _WRS_VXWORKS_5_X
-        // pipeDevDelete is not defined in older versions of VxWorks
-        pipeDevDelete( kMDNSPipeName, FALSE );
-#endif
-        inMDNS->p->commandPipe = ERROR;
-    }
-    return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     SendCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus   SendCommand( const mDNS * const inMDNS, MDNSPipeCommandCode inCommandCode )
-{
-    mStatus err;
-
-    require_action( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
-
-    err = write( inMDNS->p->commandPipe, &inCommandCode, sizeof( inCommandCode ) );
-    require_errno( err, errno, exit );
-
-    err = mStatus_NoError;
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     ProcessCommand
-//===========================================================================================================================
-
-mDNSlocal mStatus   ProcessCommand( mDNS * const inMDNS )
-{
-    mStatus err;
-    MDNSPipeCommandCode commandCode;
-
-    require_action( inMDNS->p->commandPipe != ERROR, exit, err = mStatus_NotInitializedErr );
-
-    // Read the command code from the pipe and dispatch it.
-
-    err = read( inMDNS->p->commandPipe, &commandCode, sizeof( commandCode ) );
-    require_errno( err, errno, exit );
-
-    switch( commandCode )
-    {
-    case kMDNSPipeCommandCodeReschedule:
-
-        // Reschedule event. Do nothing here, but this will cause mDNS_Execute to run before waiting again.
-
-        dlog( kDebugLevelChatty, DEBUG_NAME "reschedule\n" );
-        break;
-
-    case kMDNSPipeCommandCodeReconfigure:
-        ProcessCommandReconfigure( inMDNS );
-        break;
-
-    case kMDNSPipeCommandCodeQuit:
-
-        // Quit requested. Set quit flag and bump the config ID to let the thread exit normally.
-
-        dlog( kDebugLevelVerbose, DEBUG_NAME "processing pipe quit command\n" );
-        inMDNS->p->quit = mDNStrue;
-        ++inMDNS->p->configID;
-        break;
-
-    default:
-        dlog( kDebugLevelError, DEBUG_NAME "unknown pipe command code (code=0x%08X)\n", commandCode );
-        err = mStatus_BadParamErr;
-        goto exit;
-        break;
-    }
-    err = mStatus_NoError;
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     ProcessCommandReconfigure
-//===========================================================================================================================
-
-mDNSlocal void  ProcessCommandReconfigure( mDNS *inMDNS )
-{
-    mStatus err;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "processing pipe reconfigure command\n" );
-
-    // Tear down the existing interfaces and set up new ones using the new IP info.
-
-    mDNSPlatformLock( inMDNS );
-
-    err = TearDownInterfaceList( inMDNS );
-    check_noerr( err );
-
-    err = SetupInterfaceList( inMDNS );
-    check_noerr( err );
-
-    mDNSPlatformUnlock( inMDNS );
-
-    // Inform clients of the change.
-
-    mDNS_ConfigChanged(m);
-
-    // Force mDNS to update.
-
-    mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
-
-    // Bump the config ID so the main processing loop detects the configuration change.
-
-    ++inMDNS->p->configID;
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Threads ==
-#endif
-
-//===========================================================================================================================
-//     SetupTask
-//===========================================================================================================================
-
-mDNSlocal mStatus   SetupTask( mDNS * const inMDNS )
-{
-    mStatus err;
-    int task;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread\n" );
-    check( inMDNS );
-
-    // Create our main thread. Note: The task will save off its ID in the globals. We cannot do it here because the
-    // task invokes code that needs it and the task may begin execution before taskSpawn returns the task ID.
-    // This also means code in this thread context cannot rely on the task ID until the task has fully initialized.
-
-    task = taskSpawn( kMDNSTaskName, kMDNSTaskPriority, 0, kMDNSTaskStackSize, (FUNCPTR) Task,
-                      (int) inMDNS, 0, 0, 0, 0, 0, 0, 0, 0, 0 );
-    require_action( task != ERROR, exit, err = mStatus_NoMemoryErr );
-
-    err = mStatus_NoError;
-
-exit:
-    dlog( kDebugLevelVerbose, DEBUG_NAME "setting up thread done (err=%ld, id=%d)\n", err, task );
-    return( err );
-}
-
-//===========================================================================================================================
-//     TearDownTask
-//===========================================================================================================================
-
-mDNSlocal mStatus   TearDownTask( mDNS * const inMDNS )
-{
-    mStatus err;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down thread\n" );
-    check( inMDNS );
-
-    // Send a quit command to cause the thread to exit.
-
-    SendCommand( inMDNS, kMDNSPipeCommandCodeQuit );
-
-    // Wait for the thread to signal it has exited. Timeout in 10 seconds to handle a hung thread.
-
-    if( inMDNS->p->quitEvent )
-    {
-        err = semTake( inMDNS->p->quitEvent, sysClkRateGet() * 10 );
-        check_noerr( err );
-    }
-    err = mStatus_NoError;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "tearing down thread done (err=%ld)\n", err );
-    return( err );
-}
-
-//===========================================================================================================================
-//     Task
-//===========================================================================================================================
-
-mDNSlocal void  Task( mDNS *inMDNS )
-{
-    mStatus err;
-    fd_set allReadSet;
-    MDNSInterfaceItem *     item;
-    int maxSocket;
-    long configID;
-    struct timeval timeout;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "task starting\n" );
-    check( inMDNS );
-
-    // Set up everything up.
-
-    err = TaskInit( inMDNS );
-    require_noerr( err, exit );
-
-    // Main Processing Loop.
-
-    while( !inMDNS->p->quit )
-    {
-        // Set up the read set here to avoid the overhead of setting it up each iteration of the main processing loop.
-        // If the configuration changes, the server ID will be bumped, causing this code to set up the read set again.
-
-        TaskSetupReadSet( inMDNS, &allReadSet, &maxSocket );
-        configID = inMDNS->p->configID;
-        dlog( kDebugLevelVerbose, DEBUG_NAME "task starting processing loop (configID=%ld)\n", configID );
-
-        while( configID == inMDNS->p->configID )
-        {
-            mDNSs32 nextTaskTime;
-            fd_set readSet;
-            int n;
-
-            // Give the mDNS core a chance to do its work. Reset the rescheduled flag before calling mDNS_Execute
-            // so anything that needs processing during or after causes a re-schedule to wake up the thread. The
-            // reschedule flag is set to 1 after processing a waking up to prevent redundant reschedules while
-            // processing packets. This introduces a window for a race condition because the thread wake-up and
-            // reschedule set are not atomic, but this would be benign. Even if the reschedule flag is "corrupted"
-            // like this, it would only result in a redundant reschedule since it will loop back to mDNS_Execute.
-
-            inMDNS->p->rescheduled = 0;
-            nextTaskTime = mDNS_Execute( inMDNS );
-            TaskSetupTimeout( inMDNS, nextTaskTime, &timeout );
-
-            // Wait until something occurs (e.g. command, incoming packet, or timeout).
-
-            readSet = allReadSet;
-            n = select( maxSocket + 1, &readSet, NULL, NULL, &timeout );
-            inMDNS->p->rescheduled = 1;
-            check_errno( n, errno );
-            dlog( kDebugLevelChatty - 1, DEBUG_NAME "task select result = %d\n", n );
-            if( n == 0 )
-            {
-                // Next task timeout occurred. Loop back up to give mDNS core a chance to work.
-
-                dlog( kDebugLevelChatty, DEBUG_NAME "next task timeout occurred (%ld)\n", mDNS_TimeNow(inMDNS) );
-                continue;
-            }
-
-            // Scan the read set to determine if any sockets have something pending and process them.
-
-            n = 0;
-            for( item = inMDNS->p->interfaceList; item; item = item->next )
-            {
-                if( FD_ISSET( item->multicastSocketRef, &readSet ) )
-                {
-                    TaskProcessPacket( inMDNS, item, item->multicastSocketRef );
-                    ++n;
-                }
-            }
-
-            // Check for a pending command and process it.
-
-            if( FD_ISSET( inMDNS->p->commandPipe, &readSet ) )
-            {
-                ProcessCommand( inMDNS );
-                ++n;
-            }
-            check( n > 0 );
-        }
-    }
-
-exit:
-    // Signal we've quit.
-
-    check( inMDNS->p->quitEvent );
-    semGive( inMDNS->p->quitEvent );
-
-    dlog( kDebugLevelInfo, DEBUG_NAME "task ended\n" );
-}
-
-//===========================================================================================================================
-//     TaskInit
-//===========================================================================================================================
-
-mDNSlocal mStatus   TaskInit( mDNS *inMDNS )
-{
-    mStatus err;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "task init\n" );
-    check( inMDNS->p->readyEvent );
-
-    inMDNS->p->task = taskIdSelf();
-
-    err = SetupCommandPipe( inMDNS );
-    require_noerr( err, exit );
-
-    SetupNames( inMDNS );
-
-    err = SetupInterfaceList( inMDNS );
-    require_noerr( err, exit );
-
-exit:
-    // Signal the "ready" semaphore to indicate the task initialization code has completed (success or not).
-
-    inMDNS->p->taskInitErr = err;
-    semGive( inMDNS->p->readyEvent );
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "task init done (err=%ld)\n", err );
-    return( err );
-}
-
-//===========================================================================================================================
-//     TaskSetupReadSet
-//===========================================================================================================================
-
-mDNSlocal void  TaskSetupReadSet( mDNS *inMDNS, fd_set *outReadSet, int *outMaxSocket )
-{
-    MDNSInterfaceItem *     item;
-    int maxSocket;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "task setting up read set\n" );
-    check( inMDNS );
-    check( outReadSet );
-    check( outMaxSocket );
-
-    // Initialize the read set. Default the max socket to -1 so "maxSocket + 1" (as needed by select) is zero. This
-    // should never happen since we should always have at least one interface, but it's just to be safe.
-
-    FD_ZERO( outReadSet );
-    maxSocket = -1;
-
-    // Add all the receiving sockets to the read set.
-
-    for( item = inMDNS->p->interfaceList; item; item = item->next )
-    {
-        FD_SET( item->multicastSocketRef, outReadSet );
-        if( item->multicastSocketRef > maxSocket )
-        {
-            maxSocket = item->multicastSocketRef;
-        }
-    }
-
-    // Add the command pipe to the read set.
-
-    FD_SET( inMDNS->p->commandPipe, outReadSet );
-    if( inMDNS->p->commandPipe > maxSocket )
-    {
-        maxSocket = inMDNS->p->commandPipe;
-    }
-    check( maxSocket > 0 );
-    *outMaxSocket = maxSocket;
-
-    dlog( kDebugLevelVerbose, DEBUG_NAME "task setting up read set done (maxSocket=%d)\n", maxSocket );
-}
-
-//===========================================================================================================================
-//     TaskSetupTimeout
-//===========================================================================================================================
-
-mDNSlocal void  TaskSetupTimeout( mDNS *inMDNS, mDNSs32 inNextTaskTime, struct timeval *outTimeout )
-{
-    mDNSs32 delta;
-
-    // Calculate how long to wait before performing idle processing.
-
-    delta = inNextTaskTime - mDNS_TimeNow(inMDNS);
-    if( delta <= 0 )
-    {
-        // The next task time is now or in the past. Set the timeout to fire immediately.
-
-        outTimeout->tv_sec  = 0;
-        outTimeout->tv_usec = 0;
-    }
-    else
-    {
-        // Calculate the seconds and microseconds until the timeout should occur. Add one to the ticks remainder
-        // before multiplying to account for integer rounding error and avoid firing the timeout too early.
-
-        outTimeout->tv_sec  = delta / mDNSPlatformOneSecond;
-        outTimeout->tv_usec = ( ( delta % mDNSPlatformOneSecond ) + 1 ) * gMDNSTicksToMicrosecondsMultiplier;
-
-        // Check if the microseconds is more than 1 second. If so, bump the seconds instead.
-
-        if( outTimeout->tv_usec >= 1000000L )
-        {
-            outTimeout->tv_sec += 1;
-            outTimeout->tv_usec = 0;
-        }
-    }
-
-    dlog( kDebugLevelChatty, DEBUG_NAME "next task in %ld:%ld seconds (%ld)\n",
-          outTimeout->tv_sec, outTimeout->tv_usec, inNextTaskTime );
-}
-//===========================================================================================================================
-//     TaskProcessPacket
-//===========================================================================================================================
-
-mDNSlocal void  TaskProcessPacket( mDNS *inMDNS, MDNSInterfaceItem *inItem, MDNSSocketRef inSocketRef )
-{
-    int n;
-    DNSMessage packet;
-    struct sockaddr_in addr;
-    int addrSize;
-    mDNSu8 *                packetEndPtr;
-    mDNSAddr srcAddr;
-    mDNSIPPort srcPort;
-    mDNSAddr dstAddr;
-    mDNSIPPort dstPort;
-
-    // Receive the packet.
-
-    addrSize = sizeof( addr );
-    n = recvfrom( inSocketRef, (char *) &packet, sizeof( packet ), 0, (struct sockaddr *) &addr, &addrSize );
-    check( n >= 0 );
-    if( n >= 0 )
-    {
-        // Set up the src/dst/interface info.
-
-        srcAddr.type                = mDNSAddrType_IPv4;
-        srcAddr.ip.v4.NotAnInteger  = addr.sin_addr.s_addr;
-        srcPort.NotAnInteger        = addr.sin_port;
-        dstAddr.type                = mDNSAddrType_IPv4;
-        dstAddr.ip.v4               = AllDNSLinkGroup_v4.ip.v4;
-        dstPort                     = MulticastDNSPort;
-
-        dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
-        dlog( kDebugLevelChatty, DEBUG_NAME "    size      = %d\n", n );
-        dlog( kDebugLevelChatty, DEBUG_NAME "    src       = %u.%u.%u.%u:%hu\n",
-              srcAddr.ip.v4.b[ 0 ], srcAddr.ip.v4.b[ 1 ], srcAddr.ip.v4.b[ 2 ], srcAddr.ip.v4.b[ 3 ],
-              ntohs( srcPort.NotAnInteger ) );
-        dlog( kDebugLevelChatty, DEBUG_NAME "    dst       = %u.%u.%u.%u:%hu\n",
-              dstAddr.ip.v4.b[ 0 ], dstAddr.ip.v4.b[ 1 ], dstAddr.ip.v4.b[ 2 ], dstAddr.ip.v4.b[ 3 ],
-              ntohs( dstPort.NotAnInteger ) );
-        dlog( kDebugLevelChatty, DEBUG_NAME "    interface = 0x%08X\n", (int) inItem->hostSet.InterfaceID );
-        dlog( kDebugLevelChatty, DEBUG_NAME "--\n" );
-
-        // Dispatch the packet to mDNS.
-
-        packetEndPtr = ( (mDNSu8 *) &packet ) + n;
-        mDNSCoreReceive( inMDNS, &packet, packetEndPtr, &srcAddr, srcPort, &dstAddr, dstPort, inItem->hostSet.InterfaceID );
-    }
-
-    // Update counters.
-
-    inItem->recvCounter         += 1;
-    inItem->recvErrorCounter    += ( n < 0 );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-#if ( TARGET_NON_APPLE )
-//===========================================================================================================================
-//     GenerateUniqueHostName
-//
-//     Non-Apple platform stub routine to generate a unique name for the device. Should be implemented to return a unique name.
-//===========================================================================================================================
-
-mDNSlocal void  GenerateUniqueHostName( char *outName, long *ioSeed )
-{
-    DEBUG_UNUSED( ioSeed );
-
-    // $$$ Non-Apple Platforms: Fill in appropriate name for device.
-
-    mDNSPlatformStrCopy( outName, kMDNSDefaultName );
-}
-
-//===========================================================================================================================
-//     GenerateUniqueDNSName
-//
-//     Non-Apple platform stub routine to generate a unique RFC 1034-compatible DNS name for the device. Should be
-//     implemented to return a unique name.
-//===========================================================================================================================
-
-mDNSlocal void  GenerateUniqueDNSName( char *outName, long *ioSeed )
-{
-    DEBUG_UNUSED( ioSeed );
-
-    // $$$ Non-Apple Platforms: Fill in appropriate DNS name for device.
-
-    mDNSPlatformStrCopy( outName, kMDNSDefaultName );
-}
-#endif
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     getifaddrs
-//===========================================================================================================================
-
-int getifaddrs( struct ifaddrs **outAddrs )
-{
-    int err;
-    struct ifaddrs *        head;
-    struct ifaddrs **       next;
-    struct ifaddrs *        ifa;
-    int i;
-    struct ifnet *          ifp;
-    char ipString[ INET_ADDR_LEN ];
-    int n;
-
-    head = NULL;
-    next = &head;
-
-    i = 1;
-    for( ;; )
-    {
-        ifp = ifIndexToIfp( i );
-        if( !ifp )
-        {
-            break;
-        }
-        ++i;
-
-        // Allocate and initialize the ifaddrs structure and attach it to the linked list.
-
-        ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
-        require_action( ifa, exit, err = ENOMEM );
-
-        *next = ifa;
-        next  = &ifa->ifa_next;
-
-        // Fetch the name.
-
-        ifa->ifa_name = (char *) malloc( 16 );
-        require_action( ifa->ifa_name, exit, err = ENOMEM );
-
-        n = sprintf( ifa->ifa_name, "%s%d", ifp->if_name, ifp->if_unit );
-        require_action( n < 16, exit, err = ENOBUFS );
-
-        // Fetch the address.
-
-        ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( struct sockaddr_in ) );
-        require_action( ifa->ifa_addr, exit, err = ENOMEM );
-
-        ipString[ 0 ] = '\0';
-        #if ( TARGET_NON_APPLE )
-        err = ifAddrGet( ifa->ifa_name, ipString );
-        require_noerr( err, exit );
-        #else
-        err = ifAddrGetNonAlias( ifa->ifa_name, ipString );
-        require_noerr( err, exit );
-        #endif
-
-        err = sock_pton( ipString, AF_INET, ifa->ifa_addr, 0, NULL );
-        require_noerr( err, exit );
-
-        // Fetch flags.
-
-        ifa->ifa_flags = ifp->if_flags;
-    }
-
-    // Success!
-
-    if( outAddrs )
-    {
-        *outAddrs = head;
-        head = NULL;
-    }
-    err = 0;
-
-exit:
-    if( head )
-    {
-        freeifaddrs( head );
-    }
-    return( err );
-}
-
-//===========================================================================================================================
-//     freeifaddrs
-//===========================================================================================================================
-
-void    freeifaddrs( struct ifaddrs *inAddrs )
-{
-    struct ifaddrs *        p;
-    struct ifaddrs *        q;
-
-    // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
-
-    for( p = inAddrs; p; p = q )
-    {
-        q = p->ifa_next;
-
-        if( p->ifa_name )
-        {
-            free( p->ifa_name );
-            p->ifa_name = NULL;
-        }
-        if( p->ifa_addr )
-        {
-            free( p->ifa_addr );
-            p->ifa_addr = NULL;
-        }
-        if( p->ifa_netmask )
-        {
-            free( p->ifa_netmask );
-            p->ifa_netmask = NULL;
-        }
-        if( p->ifa_dstaddr )
-        {
-            free( p->ifa_dstaddr );
-            p->ifa_dstaddr = NULL;
-        }
-        if( p->ifa_data )
-        {
-            free( p->ifa_data );
-            p->ifa_data = NULL;
-        }
-        free( p );
-    }
-}
-
-//===========================================================================================================================
-//     sock_pton
-//===========================================================================================================================
-
-int sock_pton( const char *inString, int inFamily, void *outAddr, size_t inAddrSize, size_t *outAddrSize )
-{
-    int err;
-
-    if( inFamily == AF_INET )
-    {
-        struct sockaddr_in *        ipv4;
-
-        if( inAddrSize == 0 )
-        {
-            inAddrSize = sizeof( struct sockaddr_in );
-        }
-        if( inAddrSize < sizeof( struct sockaddr_in ) )
-        {
-            err = EINVAL;
-            goto exit;
-        }
-
-        ipv4 = (struct sockaddr_in *) outAddr;
-        err = inet_aton( (char *) inString, &ipv4->sin_addr );
-        if( err == 0 )
-        {
-            ipv4->sin_family = AF_INET;
-            if( outAddrSize )
-            {
-                *outAddrSize = sizeof( struct sockaddr_in );
-            }
-        }
-    }
-#if ( defined( AF_INET6 ) )
-    else if( inFamily == AF_INET6 )     // $$$ TO DO: Add IPv6 support.
-    {
-        err = EAFNOSUPPORT;
-        goto exit;
-    }
-#endif
-    else
-    {
-        err = EAFNOSUPPORT;
-        goto exit;
-    }
-
-exit:
-    return( err );
-}
-
-//===========================================================================================================================
-//     sock_ntop
-//===========================================================================================================================
-
-char *  sock_ntop( const void *inAddr, size_t inAddrSize, char *inBuffer, size_t inBufferSize )
-{
-    const struct sockaddr *     addr;
-
-    addr = (const struct sockaddr *) inAddr;
-    if( addr->sa_family == AF_INET )
-    {
-        struct sockaddr_in *        ipv4;
-
-        if( inAddrSize == 0 )
-        {
-            inAddrSize = sizeof( struct sockaddr_in );
-        }
-        if( inAddrSize < sizeof( struct sockaddr_in ) )
-        {
-            errno = EINVAL;
-            inBuffer = NULL;
-            goto exit;
-        }
-        if( inBufferSize < 16 )
-        {
-            errno = ENOBUFS;
-            inBuffer = NULL;
-            goto exit;
-        }
-
-        ipv4 = (struct sockaddr_in *) addr;
-        inet_ntoa_b( ipv4->sin_addr, inBuffer );
-    }
-#if ( defined( AF_INET6 ) )
-    else if( addr->sa_family == AF_INET6 )  // $$$ TO DO: Add IPv6 support.
-    {
-        errno = EAFNOSUPPORT;
-        inBuffer = NULL;
-        goto exit;
-    }
-#endif
-    else
-    {
-        errno = EAFNOSUPPORT;
-        inBuffer = NULL;
-        goto exit;
-    }
-
-exit:
-    return( inBuffer );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Debugging ==
-#endif
-
-#if ( DEBUG )
-
-void    mDNSShow( BOOL inShowRecords );
-void    mDNSShowRecords( void );
-void    mDNSShowTXT( const void *inTXT, size_t inTXTSize );
-
-//===========================================================================================================================
-//     mDNSShow
-//===========================================================================================================================
-
-void    mDNSShow( BOOL inShowRecords )
-{
-    MDNSInterfaceItem *     item;
-    mDNSAddr ip;
-    int n;
-
-    if( !gMDNSPtr )
-    {
-        printf( "### mDNS not initialized\n" );
-        return;
-    }
-
-    // Globals
-
-    printf( "\n-- mDNS globals --\n" );
-    printf( "    sizeof( mDNS )                     = %d\n", (int) sizeof( mDNS ) );
-    printf( "    sizeof( ResourceRecord )           = %d\n", (int) sizeof( ResourceRecord ) );
-    printf( "    sizeof( AuthRecord )               = %d\n", (int) sizeof( AuthRecord ) );
-    printf( "    sizeof( CacheRecord )              = %d\n", (int) sizeof( CacheRecord ) );
-    printf( "    gMDNSPtr                           = 0x%08lX\n", (unsigned long) gMDNSPtr );
-    printf( "    gMDNSTicksToMicrosecondsMultiplier = %ld\n", gMDNSTicksToMicrosecondsMultiplier );
-    printf( "    lockID                             = 0x%08lX\n", (unsigned long) gMDNSPtr->p->lockID );
-    printf( "    readyEvent                         = 0x%08lX\n", (unsigned long) gMDNSPtr->p->readyEvent );
-    printf( "    taskInitErr                        = %ld\n", gMDNSPtr->p->taskInitErr );
-    printf( "    quitEvent                          = 0x%08lX\n", (unsigned long) gMDNSPtr->p->quitEvent );
-    printf( "    commandPipe                        = %d\n", gMDNSPtr->p->commandPipe );
-    printf( "    task                               = 0x%08lX\n", (unsigned long) gMDNSPtr->p->task );
-    printf( "    quit                               = %d\n", gMDNSPtr->p->quit );
-    printf( "    configID                           = %ld\n", gMDNSPtr->p->configID );
-    printf( "    rescheduled                        = %d\n", gMDNSPtr->p->rescheduled );
-    printf( "    nicelabel                          = \"%.*s\"\n", gMDNSPtr->nicelabel.c[ 0 ], (char *) &gMDNSPtr->nicelabel.c[ 1 ] );
-    printf( "    hostLabel                          = \"%.*s\"\n", gMDNSPtr->hostlabel.c[ 0 ], (char *) &gMDNSPtr->hostlabel.c[ 1 ] );
-    printf( "\n");
-
-    // Interfaces
-
-    printf( "\n-- mDNS interfaces --\n" );
-    n = 1;
-    for( item = gMDNSPtr->p->interfaceList; item; item = item->next )
-    {
-        printf( "    -- interface %u --\n", n );
-        printf( "        name                           = \"%s\"\n", item->name );
-        printf( "        multicastSocketRef             = %d\n", item->multicastSocketRef );
-        printf( "        sendingSocketRef               = %d\n", item->sendingSocketRef );
-        ip = item->hostSet.ip;
-        printf( "        hostSet.ip                     = %u.%u.%u.%u\n", ip.ip.v4.b[ 0 ], ip.ip.v4.b[ 1 ],
-                ip.ip.v4.b[ 2 ], ip.ip.v4.b[ 3 ] );
-        printf( "        hostSet.advertise              = %s\n", item->hostSet.Advertise ? "YES" : "NO" );
-        printf( "        hostRegistered                 = %s\n", item->hostRegistered ? "YES" : "NO" );
-        printf( "        --\n" );
-        printf( "        sendMulticastCounter           = %d\n", item->sendMulticastCounter );
-        printf( "        sendUnicastCounter             = %d\n", item->sendUnicastCounter );
-        printf( "        sendErrorCounter               = %d\n", item->sendErrorCounter );
-        printf( "        recvCounter                    = %d\n", item->recvCounter );
-        printf( "        recvErrorCounter               = %d\n", item->recvErrorCounter );
-        printf( "        recvLoopCounter                = %d\n", item->recvLoopCounter );
-        printf( "\n" );
-        ++n;
-    }
-
-    // Resource Records
-
-    if( inShowRecords )
-    {
-        mDNSShowRecords();
-    }
-}
-
-//===========================================================================================================================
-//     mDNSShowRecords
-//===========================================================================================================================
-
-void    mDNSShowRecords( void )
-{
-    MDNSInterfaceItem *     item;
-    int n;
-    AuthRecord *            record;
-    char name[ MAX_ESCAPED_DOMAIN_NAME ];
-
-    printf( "\n-- mDNS resource records --\n" );
-    n = 1;
-    for( record = gMDNSPtr->ResourceRecords; record; record = record->next )
-    {
-        item = (MDNSInterfaceItem *) record->resrec.InterfaceID;
-        ConvertDomainNameToCString( &record->resrec.name, name );
-        printf( "    -- record %d --\n", n );
-        printf( "        interface = 0x%08X (%s)\n", (int) item, item ? item->name : "<any>" );
-        printf( "        name      = \"%s\"\n", name );
-        printf( "\n" );
-        ++n;
-    }
-    printf( "\n");
-}
-
-//===========================================================================================================================
-//     mDNSShowTXT
-//===========================================================================================================================
-
-void    mDNSShowTXT( const void *inTXT, size_t inTXTSize )
-{
-    const mDNSu8 *      p;
-    const mDNSu8 *      end;
-    int i;
-    mDNSu8 size;
-
-    printf( "\nTXT record (%u bytes):\n\n", inTXTSize );
-
-    p   = (const mDNSu8 *) inTXT;
-    end = p + inTXTSize;
-    i   = 0;
-
-    while( p < end )
-    {
-        size = *p++;
-        if( ( p + size ) > end )
-        {
-            printf( "\n### MALFORMED TXT RECORD (length byte too big for record)\n\n" );
-            break;
-        }
-        printf( "%2d (%3d bytes): \"%.*s\"\n", i, size, size, p );
-        p += size;
-        ++i;
-    }
-    printf( "\n" );
-}
-#endif  // DEBUG
diff --git a/mDNSVxWorks/mDNSVxWorksIPv4Only.h b/mDNSVxWorks/mDNSVxWorksIPv4Only.h
deleted file mode 100644 (file)
index ecde894..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2003 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.
-
-    Contains:  mDNS platform plugin for VxWorks.
-
-    Copyright:  Copyright (C) 2002-2003 Apple Computer, Inc., All Rights Reserved.
-
- */
-
-#ifndef __MDNS_VXWORKS__
-#define __MDNS_VXWORKS__
-
-#include    "vxWorks.h"
-#include    "semLib.h"
-
-#include    "mDNSEmbeddedAPI.h"
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-// Forward Declarations
-
-typedef struct  MDNSInterfaceItem MDNSInterfaceItem;
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         mDNS_PlatformSupport_struct
-
-    @abstract  Structure containing platform-specific data.
- */
-
-struct  mDNS_PlatformSupport_struct
-{
-    SEM_ID lockID;
-    SEM_ID readyEvent;
-    mStatus taskInitErr;
-    SEM_ID quitEvent;
-    MDNSInterfaceItem *     interfaceList;
-    int commandPipe;
-    int task;
-    mDNSBool quit;
-    long configID;
-    int rescheduled;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       mDNSReconfigure
-
-    @abstract  Tell mDNS that the configuration has changed. Call when IP address changes, link goes up after being down, etc.
-
-    @discussion
-
-    VxWorks does not provide a generic mechanism for getting notified when network interfaces change so this routines
-    provides a way for BSP-specific code to signal mDNS that something has changed and it should re-build its interfaces.
- */
-
-void    mDNSReconfigure( void );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         ifaddrs
-
-    @abstract  Interface information
- */
-
-struct ifaddrs
-{
-    struct ifaddrs *    ifa_next;
-    char *              ifa_name;
-    u_int ifa_flags;
-    struct sockaddr *   ifa_addr;
-    struct sockaddr *   ifa_netmask;
-    struct sockaddr *   ifa_dstaddr;
-    void *              ifa_data;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       getifaddrs
-
-    @abstract  Builds a linked list of interfaces. Caller must free using freeifaddrs if successful.
- */
-
-int getifaddrs( struct ifaddrs **outAddrs );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       freeifaddrs
-
-    @abstract  Frees a linked list of interfaces built with getifaddrs.
- */
-
-void    freeifaddrs( struct ifaddrs *inAddrs );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       sock_pton
-
-    @abstract  Converts a 'p'resentation address string into a 'n'umeric sockaddr structure.
-
-    @result            0 if successful or an error code on failure.
- */
-
-int sock_pton( const char *inString, int inFamily, void *outAddr, size_t inAddrSize, size_t *outAddrSize );
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @function       sock_ntop
-
-    @abstract  Converts a 'n'umeric sockaddr structure into a 'p'resentation address string.
-
-    @result            Ptr to 'p'resentation address string buffer if successful or NULL on failure.
- */
-
-char *  sock_ntop( const void *inAddr, size_t inAddrSize, char *inBuffer, size_t inBufferSize );
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif  // __MDNS_VXWORKS__
diff --git a/mDNSWindows/BonjourQuickLooks.sln b/mDNSWindows/BonjourQuickLooks.sln
deleted file mode 100644 (file)
index 3b1cbe7..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-\r
-Microsoft Visual Studio Solution File, Format Version 11.00\r
-# Visual Studio 2010\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL", "DLL\dnssd.vcxproj", "{AB581101-18F0-46F6-B56A-83A6B1EA657E}"\r
-EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mDNSResponder", "SystemService\Service.vcxproj", "{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"\r
-EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mdnsNSP", "mdnsNSP\mdnsNSP.vcxproj", "{F4F15529-F0EB-402F-8662-73C5797EE557}"\r
-EndProject\r
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dns-sd", "..\Clients\DNS-SD.VisualStudio\dns-sd.vcxproj", "{AA230639-E115-4A44-AA5A-44A61235BA50}"\r
-       ProjectSection(ProjectDependencies) = postProject\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E} = {AB581101-18F0-46F6-B56A-83A6B1EA657E}\r
-       EndProjectSection\r
-EndProject\r
-Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "BonjourQuickLooksInstaller", "BonjourQuickLooksInstaller\BonjourQuickLooksInstaller.wixproj", "{E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}"\r
-EndProject\r
-Global\r
-       GlobalSection(SolutionConfigurationPlatforms) = preSolution\r
-               Debug|Win32 = Debug|Win32\r
-               Debug|x64 = Debug|x64\r
-               Debug|x86 = Debug|x86\r
-               Release|Win32 = Release|Win32\r
-               Release|x64 = Release|x64\r
-               Release|x86 = Release|x86\r
-       EndGlobalSection\r
-       GlobalSection(ProjectConfigurationPlatforms) = postSolution\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|Win32.Build.0 = Debug|Win32\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.ActiveCfg = Debug|x64\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x64.Build.0 = Debug|x64\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Debug|x86.ActiveCfg = Debug|Win32\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.ActiveCfg = Release|Win32\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|Win32.Build.0 = Release|Win32\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.ActiveCfg = Release|x64\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x64.Build.0 = Release|x64\r
-               {AB581101-18F0-46F6-B56A-83A6B1EA657E}.Release|x86.ActiveCfg = Release|Win32\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|Win32.Build.0 = Debug|Win32\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.ActiveCfg = Debug|x64\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x64.Build.0 = Debug|x64\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Debug|x86.ActiveCfg = Debug|Win32\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.ActiveCfg = Release|Win32\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|Win32.Build.0 = Release|Win32\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.ActiveCfg = Release|x64\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x64.Build.0 = Release|x64\r
-               {C1D98254-BA27-4427-A3BE-A68CA2CC5F69}.Release|x86.ActiveCfg = Release|Win32\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|Win32.Build.0 = Debug|Win32\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.ActiveCfg = Debug|x64\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x64.Build.0 = Debug|x64\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Debug|x86.ActiveCfg = Debug|Win32\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.ActiveCfg = Release|Win32\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|Win32.Build.0 = Release|Win32\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.ActiveCfg = Release|x64\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x64.Build.0 = Release|x64\r
-               {F4F15529-F0EB-402F-8662-73C5797EE557}.Release|x86.ActiveCfg = Release|Win32\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.ActiveCfg = Debug|Win32\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|Win32.Build.0 = Debug|Win32\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.ActiveCfg = Debug|x64\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x64.Build.0 = Debug|x64\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Debug|x86.ActiveCfg = Debug|Win32\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.ActiveCfg = Release|Win32\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|Win32.Build.0 = Release|Win32\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.ActiveCfg = Release|x64\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x64.Build.0 = Release|x64\r
-               {AA230639-E115-4A44-AA5A-44A61235BA50}.Release|x86.ActiveCfg = Release|Win32\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|Win32.ActiveCfg = Debug|x86\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x64.ActiveCfg = Debug|x64\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x64.Build.0 = Debug|x64\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x86.ActiveCfg = Debug|x86\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Debug|x86.Build.0 = Debug|x86\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|Win32.ActiveCfg = Release|x86\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x64.ActiveCfg = Release|x64\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x64.Build.0 = Release|x64\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x86.ActiveCfg = Release|x86\r
-               {E24A4DC1-9B6F-4DA4-BD76-7D5FE73732BF}.Release|x86.Build.0 = Release|x86\r
-       EndGlobalSection\r
-       GlobalSection(SolutionProperties) = preSolution\r
-               HideSolutionNode = FALSE\r
-       EndGlobalSection\r
-EndGlobal\r
diff --git a/mDNSWindows/BonjourQuickLooksInstaller/BonjourQuickLooksInstaller.wixproj b/mDNSWindows/BonjourQuickLooksInstaller/BonjourQuickLooksInstaller.wixproj
deleted file mode 100644 (file)
index 9c0520c..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <PropertyGroup>\r
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>\r
-    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>\r
-    <ProductVersion>3.10</ProductVersion>\r
-    <ProjectGuid>e24a4dc1-9b6f-4da4-bd76-7d5fe73732bf</ProjectGuid>\r
-    <SchemaVersion>2.0</SchemaVersion>\r
-    <OutputName>BonjourQuickLooks</OutputName>\r
-    <OutputType>Package</OutputType>\r
-    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>\r
-    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>\r
-    <Name>BonjourQuickLooksInstaller</Name>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">\r
-    <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
-    <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
-    <DefineConstants>Debug</DefineConstants>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">\r
-    <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
-    <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">\r
-    <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
-    <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
-    <DefineConstants>Debug</DefineConstants>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">\r
-    <OutputPath>bin\$(Platform)\$(Configuration)\</OutputPath>\r
-    <IntermediateOutputPath>obj\$(Platform)\$(Configuration)\</IntermediateOutputPath>\r
-  </PropertyGroup>\r
-  <ItemGroup>\r
-    <Compile Include="Product.wxs" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="..\..\Clients\DNS-SD.VisualStudio\dns-sd.vcxproj">\r
-      <Name>dns-sd</Name>\r
-      <Project>{aa230639-e115-4a44-aa5a-44a61235ba50}</Project>\r
-      <Private>True</Private>\r
-      <DoNotHarvest>True</DoNotHarvest>\r
-      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
-      <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
-    </ProjectReference>\r
-    <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
-      <Name>DLL</Name>\r
-      <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
-      <Private>True</Private>\r
-      <DoNotHarvest>True</DoNotHarvest>\r
-      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
-      <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
-    </ProjectReference>\r
-    <ProjectReference Include="..\mdnsNSP\mdnsNSP.vcxproj">\r
-      <Name>mdnsNSP</Name>\r
-      <Project>{f4f15529-f0eb-402f-8662-73c5797ee557}</Project>\r
-      <Private>True</Private>\r
-      <DoNotHarvest>True</DoNotHarvest>\r
-      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
-      <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
-    </ProjectReference>\r
-    <ProjectReference Include="..\SystemService\Service.vcxproj">\r
-      <Name>mDNSResponder</Name>\r
-      <Project>{c1d98254-ba27-4427-a3be-a68ca2cc5f69}</Project>\r
-      <Private>True</Private>\r
-      <DoNotHarvest>True</DoNotHarvest>\r
-      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>\r
-      <RefTargetDir>INSTALLFOLDER</RefTargetDir>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <WixExtension Include="WixFirewallExtension">\r
-      <HintPath>$(WixExtDir)\WixFirewallExtension.dll</HintPath>\r
-      <Name>WixFirewallExtension</Name>\r
-    </WixExtension>\r
-  </ItemGroup>\r
-  <Import Project="$(WixTargetsPath)" />\r
-  <!--\r
-       To modify your build process, add your task inside one of the targets below and uncomment it.\r
-       Other similar extension points exist, see Wix.targets.\r
-       <Target Name="BeforeBuild">\r
-       </Target>\r
-       <Target Name="AfterBuild">\r
-       </Target>\r
-       -->\r
-</Project>\r
diff --git a/mDNSWindows/BonjourQuickLooksInstaller/Product.wxs b/mDNSWindows/BonjourQuickLooksInstaller/Product.wxs
deleted file mode 100644 (file)
index 88cb831..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!-- Copyright (c) 2016 Apple Inc. All rights reserved. -->
-
-<Wix   xmlns           = "http://schemas.microsoft.com/wix/2006/wi"
-               xmlns:fire      = "http://schemas.microsoft.com/wix/FirewallExtension" >
-       
-       <?define ProductManufacturer            = "Apple Inc."?>
-       <?define ProductName                            = "Bonjour (QuickLooks Testing)"?>
-       <?define UpgradeCode                            = "46AE3251-43D6-41CF-8CDF-E902C38516D1"?>
-       <?define ProductVersion                         = "1.0.0"?>
-       <?define ProductVersionMarketing        = "1.0.0"?>
-       <?if $(var.Platform) = x64?>
-               <?define Win64 = "yes" ?>
-               <?define PlatformSystemFolder           = "System64Folder"?>
-               <?define PlatformProgramFilesFolder     = "ProgramFiles64Folder"?>
-               <?define PlatformInstallDir                     = "INSTALLDIR64"?>
-               <?define GUID_DNSSDExe                          = "528ACC12-D4A8-11DE-927F-58D855D89593"?>
-               <?define GUID_DNSSDDLL                          = "20F30EC6-1F92-11DC-8314-0800200C9A66"?>
-               <?define GUID_MDNSNSPDLL                        = "255EBC6C-1F92-11DC-8314-0800200C9A66"?>
-               <?define GUID_MDNSResponderExe          = "BB3076CA-D4DF-11E0-8AC8-AA0E4824019B"?>
-       <?else?>
-               <?define Win64 = "no" ?>
-               <?define PlatformSystemFolder           = "SystemFolder"?>
-               <?define PlatformProgramFilesFolder     = "ProgramFilesFolder"?>
-               <?define PlatformInstallDir                     = "INSTALLDIR"?>
-               <?define GUID_DNSSDExe                          = "DCA08E52-8D4E-43AF-A0F7-9B809FCCFEBF"?>
-               <?define GUID_DNSSDDLL                          = "E6B826D2-6338-4822-8DEA-EC03C2CA41A7"?>
-               <?define GUID_MDNSNSPDLL                        = "0E416468-0A21-4778-BE61-64AAA5BE1039"?>
-               <?define GUID_MDNSResponderExe          = "836FE314-37A7-4905-90F0-AFE25F315CA3"?>
-       <?endif?>
-       <?define GUID_InstallerCache            = "EDD5CC92-97D7-4364-9CA6-F7001C75A90E"?>
-       
-       <Product
-               Id                              = "*"
-               Language                = "1033"
-               Manufacturer    = "$(var.ProductManufacturer)"
-               Name                    = "$(var.ProductName)"
-               UpgradeCode             = "$(var.UpgradeCode)"
-               Version                 = "$(var.ProductVersion)" >
-               
-               <Package
-                       Keywords                        = "Installer,MSI"
-                       Comments                        = "$(var.ProductName) $(var.ProductVersion)"
-                       Compressed                      = "yes"
-                       Description                     = "[ProductName] Installer"
-                       InstallerVersion        = "300"
-                       Languages                       = "1033"
-                       Manufacturer            = "$(var.ProductManufacturer)"
-                       SummaryCodepage         = "1252" />
-               
-               <!-- Launch Conditions -->
-               <Condition
-                       Message = "You do not have sufficient privileges to complete this installation for all users of the machine. Log on as an administrator and then retry this installation." >
-                       <![CDATA[Privileged]]>
-               </Condition>
-               <Condition
-                       Message = "[ProductName] requires that your computer is running Windows XP SP2 or newer.">
-                       <![CDATA[((VersionNT=501 AND ServicePackLevel>=2) OR VersionNT>501)]]>
-               </Condition>
-               <?if $(var.Win64) = "no"?>
-               <Condition
-                       Message = "This installer is intended for 32-bit versions of Windows" >
-                       <![CDATA[NOT VersionNT64]]>
-               </Condition>
-               <?endif?>
-               
-               <!-- Directory Table -->
-               <Directory Id="TARGETDIR" Name="SourceDir">
-                       <Directory Id="$(var.PlatformSystemFolder)" />
-                       <Directory Id="$(var.PlatformProgramFilesFolder)">
-                               <Directory Id="Bonjour64InstallFolder" Name="Bonjour">
-                                       <Directory Id="$(var.PlatformInstallDir)" />
-                               </Directory>
-                       </Directory>
-                       <Directory Id="DesktopFolder" />
-                       <Directory Id="CommonAppDataFolder" Name="Application Data">
-                               <Directory Id="AppleCommonAppDataFolder" Name="Apple">
-                                       <Directory Id="CachedInstallationsFolder" Name="Installer Cache">
-                                               <Directory Id="INSTALLERCACHE" Name="$(var.ProductName) $(var.ProductVersion)" />
-                                       </Directory>
-                               </Directory>
-                       </Directory>
-               </Directory>
-               
-               <!-- Features -->
-               <Feature Id="Bonjour" Title="Bonjour" Level="1" AllowAdvertise="no" Display="expand">
-                       <ComponentRef Id="InstallerCache" />
-                       <Feature Id="mDNSResponder" Title="mDNSResponder" Level="1" AllowAdvertise="no" Absent="disallow">
-                               <ComponentRef Id="dns_sd.exe" />
-                               <ComponentRef Id="dnssd.dll" />
-                               <ComponentRef Id="mdnsNSP.dll" />
-                               <ComponentRef Id="mDNSResponder.exe" />
-                       </Feature>
-               </Feature>
-               
-               <!-- InstallerCache -->
-               <DirectoryRef Id="INSTALLERCACHE">
-                       <Component Id="InstallerCache" Guid="$(var.GUID_InstallerCache)" KeyPath="yes">
-                               <Condition><![CDATA[NOT DONTCACHEMSI]]></Condition>
-                               <CreateFolder />
-                               <CopyFile Id="BonjourQuickLooks.msi" SourceProperty="SourceDir" SourceName="BonjourQuickLooks.msi" DestinationDirectory="INSTALLERCACHE" />
-                               <RemoveFile Id="BonjourQuickLooks.msi" Directory="INSTALLERCACHE" Name="BonjourQuickLooks.msi" On="uninstall" />
-                               <RemoveFolder Id="INSTALLERCACHE" Directory="INSTALLERCACHE" On="uninstall" />
-                       </Component>
-               </DirectoryRef>
-       
-               <!-- Bonjour -->
-               <DirectoryRef Id="$(var.PlatformSystemFolder)">
-                       <Component Id="dns_sd.exe" Guid="$(var.GUID_DNSSDExe)" Win64="$(var.Win64)">
-                               <File Id="dns_sd.exe" Name="dns-sd.exe" KeyPath="yes" Source="$(var.dns-sd.TargetPath)" />
-                       </Component>
-                       <Component Id="dnssd.dll" Guid="$(var.GUID_DNSSDDLL)" Win64="$(var.Win64)">
-                               <File Id="dnssd.dll" Name="dnssd.dll" KeyPath="yes" Source="$(var.DLL.TargetPath)" />
-                       </Component>
-               </DirectoryRef>
-               
-               <DirectoryRef Id="$(var.PlatformInstallDir)">
-                       <Component Id="mdnsNSP.dll" Guid="$(var.GUID_MDNSNSPDLL)" Win64="$(var.Win64)">
-                               <File Id="mdnsNSP.dll" Name="mdnsNSP.dll" Source="$(var.mdnsNSP.TargetPath)" KeyPath="yes" SelfRegCost="1024" />
-                       </Component>
-                       <Component Id="mDNSResponder.exe" Guid="$(var.GUID_MDNSResponderExe)" Win64="$(var.Win64)">
-                               <File Id="mDNSResponder.exe" Name="mDNSResponder.exe" Source="$(var.mDNSResponder.TargetPath)" KeyPath="yes">
-                                       <fire:FirewallException Id="mDNSException1" Name="Bonjour Service" IgnoreFailure="yes" Scope="any" />
-                               </File>
-                               <ServiceInstall
-                                       Id                              = "BonjourService"
-                                       Name                    = "Bonjour Service"
-                                       DisplayName             = "Bonjour Service"
-                                       Description             = "Enables hardware devices and software services to automatically configure themselves on the network and advertise their presence."
-                                       Start                   = "auto"
-                                       Type                    = "ownProcess"
-                                       ErrorControl    = "normal"
-                                       Vital                   = "yes" >
-                                       <ServiceDependency Id="Tcpip" Group="no" />
-                               </ServiceInstall>
-                               <ServiceControl
-                                       Id              = "BonjourService"
-                                       Name    = "Bonjour Service"
-                                       Start   = "install"
-                                       Stop    = "both"
-                                       Remove  = "uninstall"
-                                       Wait    = "yes" />
-                               <RegistryValue
-                                       Name    = "ManageLLRouting"
-                                       Root    = "HKLM"
-                                       Key             = "SYSTEM\CurrentControlSet\Services\Bonjour Service\Parameters"
-                                       Type    = "integer"
-                                       Value   = "1" />
-                               <RegistryKey
-                                       Root    = "HKLM"
-                                       Key             = "SOFTWARE\Apple Inc.\Bonjour"
-                                       Action  = "createAndRemoveOnUninstall" >
-                                       <RegistryValue
-                                               Name    = "InstallDir"
-                                               Type    = "string"
-                                               Value   = "[$(var.PlatformInstallDir)]" />
-                                       <RegistryValue
-                                               Name    = "Version"
-                                               Type    = "string"
-                                               Value   = "$(var.ProductVersion)" />
-                               </RegistryKey>
-                       </Component>
-               </DirectoryRef>
-               
-               <!-- Media -->
-               <Media Id="1" EmbedCab="yes" Cabinet="BonjourQuickLooks.cab" CompressionLevel="high" />
-               
-               <!-- Properties -->
-               <Property Id="ALLUSERS" Value="1" />
-               <Property Id="ARPNOMODIFY" Value="1" />
-               <Property Id="MSIRESTARTMANAGERCONTROL" Value="Disable" />
-               
-               <MajorUpgrade AllowDowngrades="yes" Schedule="afterInstallValidate" />
-       </Product>
-</Wix>
diff --git a/mDNSWindows/ControlPanel/BrowsingPage.cpp b/mDNSWindows/ControlPanel/BrowsingPage.cpp
deleted file mode 100755 (executable)
index 084cf1b..0000000
+++ /dev/null
@@ -1,441 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "BrowsingPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-
-#include <WinServices.h>
-    
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CBrowsingPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::CBrowsingPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CBrowsingPage::CBrowsingPage()
-:
-       CPropertyPage(CBrowsingPage::IDD)
-{
-       //{{AFX_DATA_INIT(CBrowsingPage)
-       //}}AFX_DATA_INIT
-
-       m_firstTime = true;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::~CBrowsingPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CBrowsingPage::~CBrowsingPage()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CBrowsingPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CBrowsingPage)
-       //}}AFX_DATA_MAP
-       DDX_Control(pDX, IDC_BROWSE_LIST, m_browseListCtrl);
-       DDX_Control(pDX, IDC_REMOVE_BROWSE_DOMAIN, m_removeButton);
-}
-
-BEGIN_MESSAGE_MAP(CBrowsingPage, CPropertyPage)
-       //{{AFX_MSG_MAP(CBrowsingPage)
-       //}}AFX_MSG_MAP
-       ON_BN_CLICKED(IDC_ADD_BROWSE_DOMAIN, OnBnClickedAddBrowseDomain)
-       ON_BN_CLICKED(IDC_REMOVE_BROWSE_DOMAIN, OnBnClickedRemoveBrowseDomain)
-       ON_NOTIFY(LVN_ITEMCHANGED, IDC_BROWSE_LIST, OnLvnItemchangedBrowseList)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CBrowsingPage::SetModified( BOOL bChanged )
-{
-       m_modified = bChanged;
-
-       CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CBrowsingPage::OnSetActive()
-{
-       CConfigPropertySheet    *       psheet;
-       HKEY                                            key = NULL;
-       HKEY                                            subKey = NULL;
-       DWORD                                           dwSize;
-       DWORD                                           enabled;
-       DWORD                                           err;
-       TCHAR                                           subKeyName[MAX_KEY_LENGTH];
-       DWORD                                           cSubKeys = 0;
-       DWORD                                           cbMaxSubKey;
-       DWORD                                           cchMaxClass;
-       int                                                     nIndex;
-    DWORD                                              i; 
-       BOOL                                            b = CPropertyPage::OnSetActive();
-
-       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
-       require_quiet( psheet, exit );
-       
-       m_modified = FALSE;
-
-       if ( m_firstTime )
-       {
-               m_browseListCtrl.SetExtendedStyle((m_browseListCtrl.GetStyle() & (~LVS_EX_GRIDLINES))|LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT);
-
-               m_browseListCtrl.InsertColumn(0, L"", LVCFMT_LEFT, 20 );
-               m_browseListCtrl.InsertColumn(1, L"", LVCFMT_LEFT, 345);
-
-               m_firstTime = false;
-       }
-
-       m_initialized = false;
-
-       // Clear out what's there
-
-       m_browseListCtrl.DeleteAllItems();
-
-       // Now populate the browse domain box
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, 0,
-                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       // Get information about this node
-
-    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-       require_noerr( err, exit );
-
-       for ( i = 0; i < cSubKeys; i++)
-       {       
-               dwSize = MAX_KEY_LENGTH;
-            
-               err = RegEnumKeyEx( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-               require_noerr( err, exit );
-
-               err = RegOpenKey( key, subKeyName, &subKey );
-               require_noerr( err, exit );
-
-               dwSize = sizeof( DWORD );
-               err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-               require_noerr( err, exit );
-
-               nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
-               m_browseListCtrl.SetItemText( nIndex, 1, subKeyName );
-               m_browseListCtrl.SetCheck( nIndex, enabled );
-
-               RegCloseKey( subKey );
-               subKey = NULL;
-    }
-
-       m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
-
-       m_removeButton.EnableWindow( FALSE );
-exit:
-
-       if ( subKey )
-       {
-               RegCloseKey( subKey );
-       }
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       m_initialized = true;
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::OnOK()
-{
-       if ( m_modified )
-       {
-               Commit();
-       }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::Commit()
-{
-       HKEY            key             = NULL;
-       HKEY            subKey  = NULL;
-       TCHAR           subKeyName[MAX_KEY_LENGTH];
-       DWORD           cSubKeys = 0;
-       DWORD           cbMaxSubKey;
-       DWORD           cchMaxClass;
-       DWORD           dwSize;
-       int                     i;
-       DWORD           err;
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSBrowseDomains, 0,
-                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       // First, remove all the entries that are there
-
-    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-       require_noerr( err, exit );
-
-       for ( i = 0; i < (int) cSubKeys; i++ )
-       {       
-               dwSize = MAX_KEY_LENGTH;
-            
-               err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-               require_noerr( err, exit );
-                       
-               err = RegDeleteKey( key, subKeyName );
-               require_noerr( err, exit );
-       }
-
-       // Now re-populate
-
-       for ( i = 0; i < m_browseListCtrl.GetItemCount(); i++ )
-       {
-               DWORD enabled = (DWORD) m_browseListCtrl.GetCheck( i );
-
-               err = RegCreateKeyEx( key, m_browseListCtrl.GetItemText( i, 1 ), 0,
-                                     NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &subKey, NULL );
-               require_noerr( err, exit );
-
-               err = RegSetValueEx( subKey, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
-               require_noerr( err, exit );
-
-               RegCloseKey( subKey );
-               subKey = NULL;
-       }
-       
-exit:
-
-       if ( subKey )
-       {
-               RegCloseKey( subKey );
-       }
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::OnBnClickedAddBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::OnBnClickedAddBrowseDomain()
-{
-       CAddBrowseDomain dlg( GetParent() );
-
-       if ( ( dlg.DoModal() == IDOK ) && ( dlg.m_text.GetLength() > 0 ) )
-       {
-               int nIndex;
-
-               nIndex = m_browseListCtrl.InsertItem( m_browseListCtrl.GetItemCount(), L"");
-               m_browseListCtrl.SetItemText( nIndex, 1, dlg.m_text );
-               m_browseListCtrl.SetCheck( nIndex, 1 );
-
-               m_browseListCtrl.SortItems( SortFunc, (DWORD_PTR) this );
-
-               m_browseListCtrl.Invalidate();
-
-               SetModified( TRUE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage::OnBnClickedRemoveBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CBrowsingPage::OnBnClickedRemoveBrowseDomain()
-{
-       UINT    selectedCount = m_browseListCtrl.GetSelectedCount();
-       int             nItem = -1;
-       UINT    i;
-
-       // Update all of the selected items.
-
-       for ( i = 0; i < selectedCount; i++ )
-       {
-               nItem = m_browseListCtrl.GetNextItem( -1, LVNI_SELECTED );
-               check( nItem != -1 );
-
-               m_browseListCtrl.DeleteItem( nItem );
-
-               SetModified( TRUE );
-       }
-
-       m_removeButton.EnableWindow( FALSE );
-}
-
-
-void
-CBrowsingPage::OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult)
-{
-       if ( m_browseListCtrl.GetSelectedCount() )
-       {
-               m_removeButton.EnableWindow( TRUE );
-       }
-
-       if ( m_initialized )
-       {
-               NM_LISTVIEW * pNMListView = (NM_LISTVIEW*)pNMHDR; 
-        
-               BOOL bPrevState = (BOOL) ( ( ( pNMListView->uOldState & LVIS_STATEIMAGEMASK ) >> 12 ) - 1 ); 
-        
-               if ( bPrevState < 0 )
-               {
-                       bPrevState = 0;
-               }
-
-
-               BOOL bChecked = ( BOOL ) ( ( ( pNMListView->uNewState & LVIS_STATEIMAGEMASK ) >> 12) - 1 ); 
-        
-               if ( bChecked < 0 )
-               {
-                       bChecked = 0;
-               }
-
-               if ( bPrevState != bChecked )
-               {
-                       SetModified( TRUE );
-               }
-       }
-
-       *pResult = 0;
-}
-
-
-
-int CALLBACK 
-CBrowsingPage::SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
-{
-       CString str1;
-       CString str2;
-       int             ret = 0;
-
-       CBrowsingPage * self = reinterpret_cast<CBrowsingPage*>( lParamSort );
-       require_quiet( self, exit );
-
-       str1 = self->m_browseListCtrl.GetItemText( (int) lParam1, 1 );
-       str2 = self->m_browseListCtrl.GetItemText( (int) lParam2, 1 );
-
-       ret = str1.Compare( str2 );
-
-exit:
-
-       return ret;
-}
-
-
-// CAddBrowseDomain dialog
-
-IMPLEMENT_DYNAMIC(CAddBrowseDomain, CDialog)
-CAddBrowseDomain::CAddBrowseDomain(CWnd* pParent /*=NULL*/)
-       : CDialog(CAddBrowseDomain::IDD, pParent)
-{
-}
-
-CAddBrowseDomain::~CAddBrowseDomain()
-{
-}
-
-void CAddBrowseDomain::DoDataExchange(CDataExchange* pDX)
-{
-       CDialog::DoDataExchange(pDX);
-       DDX_Control(pDX, IDC_COMBO1, m_comboBox);
-}
-
-
-BOOL
-CAddBrowseDomain::OnInitDialog()
-{
-       CConfigPropertySheet    *       psheet;
-       CConfigPropertySheet::StringList::iterator              it;
-       
-       BOOL b = CDialog::OnInitDialog();
-
-       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
-       require_quiet( psheet, exit );
-
-       for ( it = psheet->m_browseDomains.begin(); it != psheet->m_browseDomains.end(); it++ )
-       {
-               CString text = *it;
-
-               if ( m_comboBox.FindStringExact( -1, *it ) == CB_ERR )
-               {
-                       m_comboBox.AddString( *it );
-               }
-       }
-
-exit:
-
-       return b;
-}
-
-
-void
-CAddBrowseDomain::OnOK()
-{
-       m_comboBox.GetWindowText( m_text );
-
-       CDialog::OnOK();
-}
-
-
-
-BEGIN_MESSAGE_MAP(CAddBrowseDomain, CDialog)
-END_MESSAGE_MAP()
-
diff --git a/mDNSWindows/ControlPanel/BrowsingPage.h b/mDNSWindows/ControlPanel/BrowsingPage.h
deleted file mode 100755 (executable)
index 4711b36..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-#include "afxcmn.h"
-
-#include "afxwin.h"
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CBrowsingPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CBrowsingPage : public CPropertyPage
-{
-public:
-       CBrowsingPage();
-       ~CBrowsingPage();
-
-protected:
-
-       //{{AFX_DATA(CBrowsingPage)
-       enum { IDD = IDR_APPLET_PAGE3 };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CBrowsingPage)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CBrowsingPage)
-
-       //{{AFX_MSG(CBrowsingPage)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-       
-private:
-       
-       typedef std::list<CString> StringList;
-
-       afx_msg BOOL
-       OnSetActive();
-       
-       afx_msg void
-       OnOK();
-       
-       void
-       SetModified( BOOL bChanged = TRUE );
-       
-       void
-       Commit();
-
-       BOOL                    m_modified;
-
-public:
-private:
-
-       static int CALLBACK 
-
-       SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
-
-
-
-       CListCtrl       m_browseListCtrl;
-
-       bool            m_initialized;
-
-       bool            m_firstTime;
-
-
-
-public:
-
-
-
-       afx_msg void OnBnClickedAddBrowseDomain();
-
-       afx_msg void OnBnClickedRemoveBrowseDomain();
-
-       afx_msg void OnLvnItemchangedBrowseList(NMHDR *pNMHDR, LRESULT *pResult);
-
-       CButton m_removeButton;
-
-};
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CAddBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-
-class CAddBrowseDomain : public CDialog
-
-{
-
-       DECLARE_DYNAMIC(CAddBrowseDomain)
-
-
-
-public:
-
-       CAddBrowseDomain(CWnd* pParent = NULL);   // standard constructor
-
-       virtual ~CAddBrowseDomain();
-
-
-
-// Dialog Data
-
-       enum { IDD = IDR_ADD_BROWSE_DOMAIN };
-
-
-
-protected:
-
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-
-       virtual BOOL OnInitDialog();
-
-       virtual void OnOK();
-
-       DECLARE_MESSAGE_MAP()
-
-public:
-
-       CComboBox       m_comboBox;
-
-       CString         m_text;
-
-};
-
diff --git a/mDNSWindows/ControlPanel/ConfigDialog.cpp b/mDNSWindows/ControlPanel/ConfigDialog.cpp
deleted file mode 100755 (executable)
index ad59066..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "ConfigDialog.h"
-#include "ControlPanel.h"
-
-
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-IMPLEMENT_DYNCREATE(CConfigDialog, CDialog)
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigDialog::CConfigDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-CConfigDialog::CConfigDialog()
-       : CDialog(CConfigDialog::IDD, NULL)
-{
-       //{{AFX_DATA_INIT(CConfigDialog)
-       //}}AFX_DATA_INIT
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigDialog::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CConfigDialog::DoDataExchange(CDataExchange* pDX)
-{
-       CDialog::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CConfigDialog)
-       //}}AFX_DATA_MAP
-}
-
-
-BEGIN_MESSAGE_MAP(CConfigDialog, CDialog)
-       //{{AFX_MSG_MAP(CConfigDialog)
-       //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
diff --git a/mDNSWindows/ControlPanel/ConfigDialog.h b/mDNSWindows/ControlPanel/ConfigDialog.h
deleted file mode 100644 (file)
index fa8df5f..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CConfigDialog : public CDialog
-{
-public:
-
-       CConfigDialog();
-
-protected:
-
-       //{{AFX_DATA(CConfigDialog)
-       enum { IDD = IDR_APPLET };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CConfigDialog)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       //{{AFX_MSG(CConfigDialog)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-
-       DECLARE_DYNCREATE(CConfigDialog)
-};
diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp b/mDNSWindows/ControlPanel/ConfigPropertySheet.cpp
deleted file mode 100755 (executable)
index 34c418e..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ConfigPropertySheet.h"
-#include <WinServices.h>
-extern "C"
-{
-#include <ClientCommon.h>
-}
-#include <process.h>
-
-// Custom events
-
-#define WM_DATAREADY           ( WM_USER + 0x100 )
-
-
-IMPLEMENT_DYNCREATE(CConfigPropertySheet, CPropertySheet)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::CConfigPropertySheet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CConfigPropertySheet::CConfigPropertySheet()
-:
-       CPropertySheet(),
-       m_browseDomainsRef( NULL ),
-       m_thread( NULL ),
-       m_threadExited( NULL )
-{
-       AddPage(&m_firstPage );
-       AddPage(&m_secondPage);
-       AddPage(&m_thirdPage);
-
-       InitializeCriticalSection( &m_lock );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::~CConfigPropertySheet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CConfigPropertySheet::~CConfigPropertySheet()
-{
-       DeleteCriticalSection( &m_lock );
-}
-
-
-BEGIN_MESSAGE_MAP(CConfigPropertySheet, CPropertySheet)
-       //{{AFX_MSG_MAP(CConfigPropertySheet)
-       //}}AFX_MSG_MAP
-       ON_MESSAGE( WM_DATAREADY, OnDataReady )
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::OnInitDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CConfigPropertySheet::OnInitDialog()
-{
-       OSStatus err;
-
-       BOOL b = CPropertySheet::OnInitDialog();
-
-       err = SetupBrowsing();
-       require_noerr( err, exit );
-
-exit:
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::OnCommand
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CConfigPropertySheet::OnCommand(WPARAM wParam, LPARAM lParam)
-{
-   // Check if OK or Cancel was hit
-
-   if ( ( wParam == ID_WIZFINISH ) || ( wParam == IDOK ) || ( wParam == IDCANCEL ) ) 
-   {
-      OnEndDialog();
-   }
-
-   return CPropertySheet::OnCommand(wParam, lParam);
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::OnDataReady
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CConfigPropertySheet::OnDataReady(WPARAM inWParam, LPARAM inLParam)
-{
-       if (WSAGETSELECTERROR(inLParam) && !(HIWORD(inLParam)))
-       {
-               dlog( kDebugLevelError, "OnSocket: window error\n" );
-       }
-       else
-       {
-               SOCKET sock = (SOCKET) inWParam;
-
-               if ( m_browseDomainsRef && DNSServiceRefSockFD( m_browseDomainsRef ) == (int) sock )
-               {
-                       DNSServiceProcessResult( m_browseDomainsRef );
-               }
-       }
-
-       return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::OnEndDialog
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CConfigPropertySheet::OnEndDialog()
-{
-       OSStatus err;
-
-       err = TearDownBrowsing();
-       check_noerr( err );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::SetupBrowsing
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::SetupBrowsing()
-{
-       OSStatus err;
-
-       // Start browsing for browse domains
-
-       err = DNSServiceEnumerateDomains( &m_browseDomainsRef, kDNSServiceFlagsBrowseDomains, 0, BrowseDomainsReply, this );
-       require_noerr( err, exit );
-
-       err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, WM_DATAREADY, FD_READ|FD_CLOSE );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( err )
-       {
-               TearDownBrowsing();
-       }
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::TearDownBrowsing
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::TearDownBrowsing()
-{
-       OSStatus err = kNoErr;
-
-       if ( m_browseDomainsRef )
-       {
-               err = WSAAsyncSelect( DNSServiceRefSockFD( m_browseDomainsRef ), m_hWnd, 0, 0 );
-               check_noerr( err );
-
-               DNSServiceRefDeallocate( m_browseDomainsRef );
-       
-               m_browseDomainsRef = NULL;
-       }
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::DecodeDomainName
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CConfigPropertySheet::DecodeDomainName( const char * raw, CString & decoded )
-{
-       char nextLabel[128] = "\0";
-       char decodedDomainString[kDNSServiceMaxDomainName];
-    char * buffer = (char *) raw;
-    int labels = 0, i;
-    char text[64];
-       const char *label[128];
-       OSStatus        err;
-    
-       // Initialize
-
-       decodedDomainString[0] = '\0';
-
-    // Count the labels
-
-       while ( *buffer )
-       {
-               label[labels++] = buffer;
-               buffer = (char *) GetNextLabel(buffer, text);
-    }
-        
-    buffer = (char*) raw;
-
-    for (i = 0; i < labels; i++)
-       {
-               buffer = (char *)GetNextLabel(buffer, nextLabel);
-        strcat_s(decodedDomainString, sizeof(decodedDomainString), nextLabel);
-        strcat_s(decodedDomainString, sizeof(decodedDomainString), ".");
-    }
-    
-    // Remove trailing dot from domain name.
-    
-       decodedDomainString[ strlen( decodedDomainString ) - 1 ] = '\0';
-
-       // Convert to Unicode
-
-       err = UTF8StringToStringObject( decodedDomainString, decoded );
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet::BrowseDomainsReply
-//---------------------------------------------------------------------------------------------------------------------------
-
-void DNSSD_API
-CConfigPropertySheet::BrowseDomainsReply
-                                                       (
-                                                       DNSServiceRef                   sdRef,
-                                                       DNSServiceFlags                 flags,
-                                                       uint32_t                                interfaceIndex,
-                                                       DNSServiceErrorType             errorCode,
-                                                       const char                      *       replyDomain,
-                                                       void                            *       context
-                                                       )
-{
-       CConfigPropertySheet    *       self = reinterpret_cast<CConfigPropertySheet*>(context);
-       CString                                         decoded;
-       OSStatus                                        err;
-
-       DEBUG_UNUSED( sdRef );
-       DEBUG_UNUSED( interfaceIndex );
-
-       if ( errorCode )
-       {
-               goto exit;
-       }
-
-       check( replyDomain );
-       
-       // Ignore local domains
-
-       if ( strcmp( replyDomain, "local." ) == 0 )
-       {
-               goto exit;
-       }
-
-       err = self->DecodeDomainName( replyDomain, decoded );
-       require_noerr( err, exit );
-
-       // Remove trailing '.'
-
-       decoded.TrimRight( '.' );
-
-       if ( flags & kDNSServiceFlagsAdd )
-       {
-               self->m_browseDomains.push_back( decoded );
-       }
-       else
-       {
-               self->m_browseDomains.remove( decoded );
-       }
-
-exit:
-
-       return;
-}
diff --git a/mDNSWindows/ControlPanel/ConfigPropertySheet.h b/mDNSWindows/ControlPanel/ConfigPropertySheet.h
deleted file mode 100755 (executable)
index 9e4fda8..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _ConfigPropertySheet_h
-#define _ConfigPropertySheet_h
-
-#include "stdafx.h"
-#include "ServicesPage.h"
-#include "RegistrationPage.h"
-#include "BrowsingPage.h"
-
-#include <RegNames.h>
-#include <dns_sd.h>
-#include <list>
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CConfigPropertySheet
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CConfigPropertySheet : public CPropertySheet
-{
-public:
-
-       CConfigPropertySheet();
-       virtual ~CConfigPropertySheet();
-
-       typedef std::list<CString> StringList;
-
-       StringList      m_browseDomains;
-
-protected:
-
-       CServicesPage           m_firstPage;
-       CRegistrationPage       m_secondPage;
-       CBrowsingPage           m_thirdPage;
-
-       //{{AFX_VIRTUAL(CConfigPropertySheet)
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CConfigPropertySheet)
-
-       //{{AFX_MSG(CConfigPropertySheet)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-
-       afx_msg BOOL    OnInitDialog();
-       afx_msg BOOL    OnCommand( WPARAM wParam, LPARAM lParam );
-       afx_msg LRESULT OnDataReady( WPARAM inWParam, LPARAM inLParam );
-       afx_msg LRESULT OnRegistryChanged( WPARAM inWParam, LPARAM inLParam );
-       void                    OnEndDialog();
-
-private:
-
-       OSStatus
-       SetupBrowsing();
-
-       OSStatus
-       TearDownBrowsing();
-
-       OSStatus
-       DecodeDomainName( const char * raw, CString & decoded );
-
-       static void DNSSD_API
-       BrowseDomainsReply
-                               (
-                               DNSServiceRef                   sdRef,
-                               DNSServiceFlags                 flags,
-                               uint32_t                                interfaceIndex,
-                               DNSServiceErrorType             errorCode,
-                               const char                      *       replyDomain,
-                               void                            *       context
-                               );
-
-       // This thread will watch for registry changes
-
-       static unsigned WINAPI
-       WatchRegistry
-                               (
-                               LPVOID inParam
-                               );
-
-       HKEY                            m_statusKey;
-       HANDLE                          m_thread;
-       HANDLE                          m_threadExited;
-       DNSServiceRef           m_browseDomainsRef;
-       CRITICAL_SECTION        m_lock;
-};
-
-
-#endif
diff --git a/mDNSWindows/ControlPanel/ControlPanel.cpp b/mDNSWindows/ControlPanel/ControlPanel.cpp
deleted file mode 100755 (executable)
index 4bf5df3..0000000
+++ /dev/null
@@ -1,380 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-    
-#include "ControlPanel.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 CCPApp theApp;
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     GetControlPanelApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApp*
-GetControlPanelApp()
-{
-       CCPApp * pApp = (CCPApp*) AfxGetApp();
-
-       check( pApp );
-       check( pApp->IsKindOf( RUNTIME_CLASS( CCPApp ) ) );
-
-       return pApp;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CPlApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-LONG APIENTRY
-CPlApplet(HWND hWndCPl, UINT uMsg, LONG lParam1, LONG lParam2)
-{
-       AFX_MANAGE_STATE(AfxGetStaticModuleState());
-
-       CCPApp * pApp = GetControlPanelApp();
-
-       return ( LONG ) pApp->OnCplMsg(hWndCPl, uMsg, lParam1, lParam2);
-}
-
-
-IMPLEMENT_DYNAMIC(CCPApplet, CCmdTarget);
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::CCPApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApplet::CCPApplet(UINT resourceId, UINT descId, CRuntimeClass * uiClass)
-:
-       m_resourceId(resourceId),
-       m_descId(descId),
-       m_uiClass(uiClass),
-       m_pageNumber(0)
-{
-       check( uiClass );
-       check( uiClass->IsDerivedFrom( RUNTIME_CLASS( CDialog ) ) || 
-              uiClass->IsDerivedFrom( RUNTIME_CLASS( CPropertySheet ) ) );
-
-       m_name.LoadString(resourceId);
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::~CCPApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApplet::~CCPApplet()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::OnStartParms
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnStartParms(CWnd * pParentWnd, LPCTSTR extra)
-{
-       DEBUG_UNUSED( pParentWnd );
-
-       if ( extra )
-       {
-               m_pageNumber = ::_ttoi( extra ) - 1;
-       }
-
-       return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::OnRun
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnRun(CWnd* pParentWnd)
-{
-       LRESULT         lResult = 1;
-       CWnd    *       pWnd;
-
-       InitCommonControls();
-
-       pWnd = (CWnd*) m_uiClass->CreateObject(); 
-
-       if ( pWnd )
-       {
-               lResult = ERROR_SUCCESS;
-
-               if ( pWnd->IsKindOf( RUNTIME_CLASS( CPropertySheet ) ) )
-               {
-                       CPropertySheet * pSheet = (CPropertySheet*) pWnd;
-
-                       pSheet->Construct(m_name, pParentWnd, m_pageNumber);
-
-                       pSheet->DoModal();
-               }
-               else
-               {
-                       check( pWnd->IsKindOf( RUNTIME_CLASS( CDialog ) ) );
-
-                       CDialog * pDialog = (CDialog*) pWnd;
-
-               pDialog->DoModal();
-       }
-
-               delete pWnd;
-       }
-
-       return lResult;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::OnInquire
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnInquire(CPLINFO* pInfo)
-{
-       pInfo->idIcon = m_resourceId;
-       pInfo->idName = m_resourceId;
-       pInfo->idInfo = m_descId;
-       pInfo->lData  = reinterpret_cast<LONG>(this);
-
-       return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::OnNewInquire
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnNewInquire(NEWCPLINFO* pInfo)
-{
-       DEBUG_UNUSED( pInfo );
-
-       return 1;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::OnSelect
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnSelect()
-{
-       return 0;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet::OnStop
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApplet::OnStop()
-{
-       return 0;
-}
-
-
-IMPLEMENT_DYNAMIC(CCPApp, CWinApp);
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApp::CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApp::CCPApp()
-{
-       debug_initialize( kDebugOutputTypeWindowsEventLog, "DNS-SD Control Panel", GetModuleHandle( NULL ) );
-       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelInfo );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApp::~CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-CCPApp::~CCPApp()
-{
-       while ( !m_applets.IsEmpty() )
-       {
-       delete m_applets.RemoveHead();
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApp::AddApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CCPApp::AddApplet( CCPApplet * applet )
-{
-       check( applet );
-
-       m_applets.AddTail( applet );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApp::OnInit
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApp::OnInit()
-{
-       CCPApplet * applet;
-
-       try
-       {
-               applet = new CCPApplet( IDR_APPLET, IDS_APPLET_DESCRIPTION, RUNTIME_CLASS( CConfigPropertySheet ) );
-       }
-       catch (...)
-       {
-               applet = NULL;
-       }
-   
-       require_action( applet, exit, kNoMemoryErr );
-       
-       AddApplet( applet );
-
-exit:
-
-       return m_applets.GetCount();
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApp::OnExit
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApp::OnExit()
-{
-  return 1;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApp::OnCplMsg
-//---------------------------------------------------------------------------------------------------------------------------
-
-LRESULT
-CCPApp::OnCplMsg(HWND hWndCPl, UINT uMsg, LPARAM lParam1, LPARAM lParam2)
-{
-       LRESULT lResult = 1;
-
-       switch ( uMsg )
-       {
-               case CPL_INIT:
-               {
-                       lResult = OnInit();
-               }
-               break;
-
-               case CPL_EXIT:
-               {
-                       lResult = OnExit();
-               }
-               break;
-
-               case CPL_GETCOUNT:
-               {      
-               lResult = m_applets.GetCount();
-               }
-               break;
-
-               default:
-               {
-               POSITION pos = m_applets.FindIndex( lParam1 );
-                       check( pos );
-
-                       CCPApplet * applet = m_applets.GetAt( pos );  
-                       check( applet );
-
-               switch (uMsg)
-               {
-                       case CPL_INQUIRE:
-                       {
-                                       LPCPLINFO pInfo = reinterpret_cast<LPCPLINFO>(lParam2);
-                               lResult = applet->OnInquire(pInfo);
-                               }  
-                       break;
-
-                               case CPL_NEWINQUIRE:
-                       {
-                               LPNEWCPLINFO pInfo = reinterpret_cast<LPNEWCPLINFO>(lParam2);
-                                       lResult = applet->OnNewInquire(pInfo);
-                               }  
-                       break;
-
-                               case CPL_STARTWPARMS:
-                       {
-                               CWnd * pParentWnd = CWnd::FromHandle(hWndCPl);
-                               LPCTSTR lpszExtra = reinterpret_cast<LPCTSTR>(lParam2);
-                               lResult = applet->OnStartParms(pParentWnd, lpszExtra);
-                               }
-                               break;
-
-                               case CPL_DBLCLK:
-                               {
-                               CWnd* pParentWnd = CWnd::FromHandle(hWndCPl);
-                               lResult = applet->OnRun(pParentWnd);
-                               }
-                       break;
-
-                               case CPL_SELECT:
-                               {
-                               lResult = applet->OnSelect();
-                               }
-                               break;
-
-                               case CPL_STOP:
-                               {
-                                       lResult = applet->OnStop();
-                               }
-                               break;
-
-                               default:
-                               {
-                                       // TRACE(_T("Warning, Received an unknown control panel message:%d\n"), uMsg);
-                                       lResult = 1;
-                               }
-                               break;
-               }
-               }
-               break;
-       }
-
-       return lResult;
-}
diff --git a/mDNSWindows/ControlPanel/ControlPanel.def b/mDNSWindows/ControlPanel/ControlPanel.def
deleted file mode 100644 (file)
index 3cb05eb..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-; -*- 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.
-    
-LIBRARY        "Bonjour"
-
-EXPORTS
-       CPlApplet
diff --git a/mDNSWindows/ControlPanel/ControlPanel.h b/mDNSWindows/ControlPanel/ControlPanel.h
deleted file mode 100644 (file)
index dec5e58..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-    
-#pragma once
-
-#include "stdafx.h"
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApplet
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CCPApplet : public CCmdTarget
-{
-public:
-
-       CCPApplet( UINT nResourceID, UINT nDescriptionID, CRuntimeClass* pUIClass );
-
-       virtual ~CCPApplet();
-
-protected:
-
-       virtual LRESULT OnRun(CWnd* pParentWnd);
-       virtual LRESULT OnStartParms(CWnd* pParentWnd, LPCTSTR lpszExtra);
-       virtual LRESULT OnInquire(CPLINFO* pInfo);
-       virtual LRESULT OnNewInquire(NEWCPLINFO* pInfo);
-       virtual LRESULT OnSelect();
-       virtual LRESULT OnStop();
-
-       CRuntimeClass   *       m_uiClass;
-       UINT                            m_resourceId;
-       UINT                            m_descId;
-       CString                         m_name;
-       int                                     m_pageNumber;
-  
-       friend class CCPApp;
-
-       DECLARE_DYNAMIC(CCPApplet);
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CCPApp
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CCPApp : public CWinApp
-{
-public:
-
-       CCPApp();
-       virtual ~CCPApp();
-
-       void AddApplet( CCPApplet* pApplet );
-
-protected:
-
-       CList<CCPApplet*, CCPApplet*&> m_applets;
-
-       friend LONG APIENTRY
-       CPlApplet(HWND hWndCPl, UINT uMsg, LONG lParam1, LONG lParam2);
-
-       virtual LRESULT OnCplMsg(HWND hWndCPl, UINT msg, LPARAM lp1, LPARAM lp2);
-       virtual LRESULT OnInit();
-       virtual LRESULT OnExit();
-
-       DECLARE_DYNAMIC(CCPApp);
-};
-
-
-CCPApp * GetControlPanelApp();
diff --git a/mDNSWindows/ControlPanel/ControlPanel.rc b/mDNSWindows/ControlPanel/ControlPanel.rc
deleted file mode 100644 (file)
index 1df3e90..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
-    "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
-    "#include ""afxres.h""\r\n"\r
-    "#include ""WinVersRes.h""\r\n"\r
-    "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
-    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
-    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
-    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
-    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
-    "\r\n"\r
-    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
-    "LANGUAGE 9, 1\r\n"\r
-    "#pragma code_page(1252)\r\n"\r
-    "#include ""afxres.rc""     // Standard components\r\n"\r
-    "#endif\r\n"\r
-    "\0"\r
-END\r
-\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Icon\r
-//\r
-\r
-// Icon with lowest ID value placed first to ensure application icon\r
-// remains consistent on all systems.\r
-IDR_APPLET              ICON                    "res\\controlpanel.ico"\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
-    BLOCK "StringFileInfo"\r
-    BEGIN\r
-        BLOCK "040904b0"\r
-        BEGIN\r
-            VALUE "CompanyName", MASTER_COMPANY_NAME\r
-            VALUE "FileDescription", "Bonjour Control Panel"\r
-            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
-            VALUE "InternalName", "ControlPanel.cpl"\r
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
-            VALUE "OriginalFilename", "ControlPanel.cpl"\r
-            VALUE "ProductName", MASTER_PROD_NAME\r
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
-        END\r
-    END\r
-    BLOCK "VarFileInfo"\r
-    BEGIN\r
-        VALUE "Translation", 0x409, 1200\r
-    END\r
-END\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// String Table\r
-//\r
-\r
-STRINGTABLE\r
-BEGIN\r
-       IDS_REINSTALL    "Bonjour Control Panel cannot run because some of its required files are missing.  Please reinstall Bonjour Control Panel."\r
-       IDS_REINSTALL_CAPTION "Bonjour"\r
-END\r
-#endif    // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc"     // Standard components\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif    // not APSTUDIO_INVOKED\r
-\r
diff --git a/mDNSWindows/ControlPanel/ControlPanel.vcproj b/mDNSWindows/ControlPanel/ControlPanel.vcproj
deleted file mode 100755 (executable)
index 2f2d0ab..0000000
+++ /dev/null
@@ -1,727 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="ControlPanel"\r
-       ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
-       RootNamespace="ControlPanel"\r
-       Keyword="MFCProj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderThrough=""\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="0"\r
-                               DisableSpecificWarnings="4311;4312"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="2"\r
-                               SuppressStartupBanner="true"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderThrough=""\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="0"\r
-                               DisableSpecificWarnings="4311;4312"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="2"\r
-                               SuppressStartupBanner="true"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel64.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="1"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="false"\r
-                               RuntimeLibrary="0"\r
-                               EnableFunctionLevelLinking="true"\r
-                               TreatWChar_tAsBuiltInType="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               DisableSpecificWarnings="4702"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="1"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="false"\r
-                               RuntimeLibrary="0"\r
-                               EnableFunctionLevelLinking="true"\r
-                               TreatWChar_tAsBuiltInType="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               DisableSpecificWarnings="4702"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel64.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-                       >\r
-                       <File\r
-                               RelativePath="ConfigDialog.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="ConfigPropertySheet.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ControlPanelExe.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ServicesPage.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="RegistrationPage.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\loclibrary.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="stdafx.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="BrowsingPage.cpp"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl"\r
-                       >\r
-                       <File\r
-                               RelativePath="ConfigDialog.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="ConfigPropertySheet.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ControlPanelExe.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ServicesPage.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="RegistrationPage.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\loclibrary.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="Resource.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="stdafx.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="BrowsingPage.h"\r
-                               >\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
-                       >\r
-                       <File\r
-                               RelativePath="res\configurator.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\controlpanel.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ControlPanel.rc"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\res\ControlPanel.rc2"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\res\EnergySaver.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\failure.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\success.ico"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Support"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\Clients\ClientCommon.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\Clients\ClientCommon.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\CommonServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dns_sd.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Secret.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Secret.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\WinServices.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\WinServices.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/ControlPanel/ControlPanel.vcxproj b/mDNSWindows/ControlPanel/ControlPanel.vcxproj
deleted file mode 100755 (executable)
index c341d42..0000000
+++ /dev/null
@@ -1,385 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}</ProjectGuid>\r
-    <RootNamespace>ControlPanel</RootNamespace>\r
-    <Keyword>MFCProj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderFile>\r
-      </PrecompiledHeaderFile>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ObjectFileName>$(IntDir)</ObjectFileName>\r
-      <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>Cdecl</CallingConvention>\r
-      <DisableSpecificWarnings>4311;4312;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\ControlPanel.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderFile>\r
-      </PrecompiledHeaderFile>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ObjectFileName>$(IntDir)</ObjectFileName>\r
-      <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>Cdecl</CallingConvention>\r
-      <DisableSpecificWarnings>4311;4312;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\ControlPanel64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
-      <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>false</MinimalRebuild>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <FunctionLevelLinking>true</FunctionLevelLinking>\r
-      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ObjectFileName>$(IntDir)</ObjectFileName>\r
-      <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\ControlPanel.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"   mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                  "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\r
-      <AdditionalIncludeDirectories>..;../../mDNSCore;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;_WIN32_WINNT=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>false</MinimalRebuild>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <FunctionLevelLinking>true</FunctionLevelLinking>\r
-      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ObjectFileName>$(IntDir)</ObjectFileName>\r
-      <ProgramDataBaseFileName>$(IntDir)vc80.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DisableSpecificWarnings>4702;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanel.exe</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <ProgramDatabaseFile>$(OutDir)ControlPanel.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <EntryPointSymbol>wWinMainCRTStartup</EntryPointSymbol>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\ControlPanel64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"   mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                  "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="ConfigDialog.cpp">\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-    </ClCompile>\r
-    <ClCompile Include="ConfigPropertySheet.cpp">\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-    </ClCompile>\r
-    <ClCompile Include="ControlPanelExe.cpp" />\r
-    <ClCompile Include="ServicesPage.cpp" />\r
-    <ClCompile Include="RegistrationPage.cpp">\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-    </ClCompile>\r
-    <ClCompile Include="..\loclibrary.c" />\r
-    <ClCompile Include="stdafx.cpp">\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-      </PrecompiledHeader>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Disabled</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-      </PrecompiledHeader>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-      </PrecompiledHeader>\r
-      <Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>\r
-      <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-      </PrecompiledHeader>\r
-    </ClCompile>\r
-    <ClCompile Include="BrowsingPage.cpp" />\r
-    <ClCompile Include="..\..\Clients\ClientCommon.c" />\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
-    <ClCompile Include="..\Secret.c" />\r
-    <ClCompile Include="..\WinServices.cpp" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="ConfigDialog.h" />\r
-    <ClInclude Include="ConfigPropertySheet.h" />\r
-    <ClInclude Include="ControlPanelExe.h" />\r
-    <ClInclude Include="ServicesPage.h" />\r
-    <ClInclude Include="RegistrationPage.h" />\r
-    <ClInclude Include="..\loclibrary.h" />\r
-    <ClInclude Include="Resource.h" />\r
-    <ClInclude Include="stdafx.h" />\r
-    <ClInclude Include="BrowsingPage.h" />\r
-    <ClInclude Include="..\..\Clients\ClientCommon.h" />\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\dns_sd.h" />\r
-    <ClInclude Include="..\Secret.h" />\r
-    <ClInclude Include="..\WinServices.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="res\configurator.ico" />\r
-    <None Include="res\controlpanel.ico" />\r
-    <None Include="res\ControlPanel.rc2" />\r
-    <None Include="res\EnergySaver.ico" />\r
-    <None Include="res\failure.ico" />\r
-    <None Include="res\success.ico" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="ControlPanel.rc" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="..\DLLStub\DLLStub.vcxproj">\r
-      <Project>{3a2b6325-3053-4236-84bd-aa9be2e323e5}</Project>\r
-      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/ControlPanel/ControlPanel.vcxproj.filters b/mDNSWindows/ControlPanel/ControlPanel.vcxproj.filters
deleted file mode 100755 (executable)
index 846d6a4..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{d534a12a-5d97-4d9e-87ba-898c97da20fb}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{e7514699-1b61-4910-a465-8950dd4c3fad}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{dad601b4-0fa4-4692-8c01-8cbb407b5a32}</UniqueIdentifier>\r
-      <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe</Extensions>\r
-    </Filter>\r
-    <Filter Include="Support">\r
-      <UniqueIdentifier>{ada5b5c6-cf44-4574-94a0-0e576fda469d}</UniqueIdentifier>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="ConfigDialog.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="ConfigPropertySheet.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="ControlPanelExe.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="ServicesPage.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="RegistrationPage.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\loclibrary.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="stdafx.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="BrowsingPage.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\Clients\ClientCommon.c">\r
-      <Filter>Support</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
-      <Filter>Support</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\Secret.c">\r
-      <Filter>Support</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\WinServices.cpp">\r
-      <Filter>Support</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="ConfigDialog.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="ConfigPropertySheet.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="ControlPanelExe.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="ServicesPage.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="RegistrationPage.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\loclibrary.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="Resource.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="stdafx.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="BrowsingPage.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\Clients\ClientCommon.h">\r
-      <Filter>Support</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
-      <Filter>Support</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
-      <Filter>Support</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\dns_sd.h">\r
-      <Filter>Support</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\Secret.h">\r
-      <Filter>Support</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\WinServices.h">\r
-      <Filter>Support</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="res\configurator.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\controlpanel.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\ControlPanel.rc2">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\EnergySaver.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\failure.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\success.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="ControlPanel.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/ControlPanel/ControlPanelDll.rc b/mDNSWindows/ControlPanel/ControlPanelDll.rc
deleted file mode 100644 (file)
index 5d1f495..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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
-#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
deleted file mode 100755 (executable)
index 94de794..0000000
+++ /dev/null
@@ -1,374 +0,0 @@
-/* -*- 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.
- */
-
-    
-#include "ControlPanelExe.h"
-#include "ConfigDialog.h"
-#include "ConfigPropertySheet.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include "loclibrary.h"
-#include <strsafe.h>
-
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-#ifndef HeapEnableTerminationOnCorruption
-#      define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS) 1
-#endif
-
-
-// Stash away pointers to our resource DLLs
-
-static HINSTANCE g_nonLocalizedResources       = NULL;
-static HINSTANCE g_localizedResources          = NULL;
-
-
-HINSTANCE      GetNonLocalizedResources()
-{
-       return g_nonLocalizedResources;
-}
-
-
-HINSTANCE      GetLocalizedResources()
-{
-       return g_localizedResources;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     Static Declarations
-//---------------------------------------------------------------------------------------------------------------------------
-DEFINE_GUID(CLSID_ControlPanel, 
-
-0x1207552c, 0xe59, 0x4d9f, 0x85, 0x54, 0xf1, 0xf8, 0x6, 0xcd, 0x7f, 0xa9);
-
-static LPCTSTR g_controlPanelGUID                      =       TEXT( "{1207552C-0E59-4d9f-8554-F1F806CD7FA9}" );
-static LPCTSTR g_controlPanelName                      =       TEXT( "Bonjour" );
-static LPCTSTR g_controlPanelCanonicalName     =       TEXT( "Apple.Bonjour" );
-static LPCTSTR g_controlPanelCategory          =       TEXT( "3,8" );
-
-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 inCanonicalName, 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,         inCanonicalName },
-               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "System.ControlPanel.Category" ), REG_SZ,         inCategory },
-               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "LocalizedString" ),                              REG_SZ,         inLocalizedName },
-               { HKEY_CLASSES_ROOT,    TEXT( "CLSID\\%s" ),                                                                                                                                                    TEXT( "InfoTip" ),                                              REG_SZ,         inInfoTip },
-               { 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 )
-       {
-               StringCbPrintf( keyName, sizeof( 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 ];
-
-       StringCbPrintf( keyName, sizeof( keyName ), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace\\%s", clsidString );
-       MyRegDeleteKey( HKEY_LOCAL_MACHINE, keyName );
-
-       StringCbPrintf( keyName, sizeof( keyName ), L"CLSID\\%s", clsidString );
-       MyRegDeleteKey( HKEY_CLASSES_ROOT, keyName );
-}
-
-
-
-//-----------------------------------------------------------
-//     CCPApp::InitInstance
-//-----------------------------------------------------------
-
-BOOL
-CCPApp::InitInstance()
-{
-       CCommandLineInfo        commandLine;
-       wchar_t                         resource[MAX_PATH];
-       CString                         errorMessage;
-       CString                         errorCaption;
-       int                                     res;
-       OSStatus                        err = kNoErr;
-
-       HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
-
-       //
-       // initialize the debugging framework
-       //
-       debug_initialize( kDebugOutputTypeWindowsDebugger, "ControlPanel", NULL );
-       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelTrace );
-
-       // Before we load the resources, let's load the error string
-
-       errorMessage.LoadString( IDS_REINSTALL );
-       errorCaption.LoadString( IDS_REINSTALL_CAPTION );
-
-       res = PathForResource( NULL, L"ControlPanelResources.dll", resource, MAX_PATH );
-       err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
-       require_noerr( err, exit );
-
-       g_nonLocalizedResources = LoadLibrary( resource );
-       translate_errno( g_nonLocalizedResources, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       res = PathForResource( NULL, L"ControlPanelLocalized.dll", resource, MAX_PATH );
-       err = translate_errno( res != 0, kUnknownErr, kUnknownErr );
-       require_noerr( err, exit );
-
-       g_localizedResources = LoadLibrary( resource );
-       translate_errno( g_localizedResources, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       AfxSetResourceHandle( g_localizedResources );
-
-       // InitCommonControls() is required on Windows XP if an application
-       // manifest specifies use of ComCtl32.dll version 6 or later to enable
-       // visual styles.  Otherwise, any window creation will fail.
-
-       InitCommonControls();
-
-       CWinApp::InitInstance();
-
-       AfxEnableControlContainer();
-
-       ParseCommandLine( commandLine );
-
-       if ( commandLine.m_nShellCommand == CCommandLineInfo::AppRegister )
-       {
-               CString         localizedName;
-               CString         toolTip;
-               TCHAR           iconPath[ MAX_PATH + 12 ]       = TEXT( "" );
-               TCHAR           exePath[ MAX_PATH ]                     = TEXT( "" );
-               DWORD           nChars;
-               OSStatus        err;
-
-               nChars = GetModuleFileName( NULL, exePath, sizeof_array( exePath ) );
-
-               err = translate_errno( nChars > 0, (OSStatus) GetLastError(), kUnknownErr );
-
-               require_noerr( err, exit );
-
-               StringCbPrintf( iconPath, sizeof( iconPath ), L"%s,-%d", exePath, IDR_APPLET );
-
-               localizedName.LoadString( IDS_APPLET_NAME );
-               toolTip.LoadString( IDS_APPLET_TOOLTIP );
-
-               Register( g_controlPanelGUID, g_controlPanelName, g_controlPanelCanonicalName, g_controlPanelCategory, localizedName, toolTip, iconPath, exePath );
-       }
-       else if ( commandLine.m_nShellCommand == CCommandLineInfo::AppUnregister )
-       {
-               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:
-
-       if ( err )
-       {
-               MessageBox( NULL, errorMessage, errorCaption, MB_ICONERROR | MB_OK );
-       }
-
-       // Since the dialog has been closed, return FALSE so that we exit the
-       //  application, rather than start the application's message pump.
-       return FALSE;
-}
diff --git a/mDNSWindows/ControlPanel/ControlPanelExe.h b/mDNSWindows/ControlPanel/ControlPanelExe.h
deleted file mode 100644 (file)
index 865ebc1..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- 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.
- */
-
-    
-#pragma once
-
-#include "stdafx.h"
-
-extern HINSTANCE       GetNonLocalizedResources();
-extern HINSTANCE       GetLocalizedResources();
-
-//-------------------------------------------------
-//     CCPApp
-//-------------------------------------------------
-
-class CCPApp : public CWinApp
-{
-public:
-
-       CCPApp();
-       virtual ~CCPApp();
-
-protected:
-
-       virtual BOOL    InitInstance();
-
-       void
-       Register( LPCTSTR inClsidString, LPCTSTR inName, LPCTSTR inCanonicalName, 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
deleted file mode 100644 (file)
index 4ea5f95..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-// 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
-#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
deleted file mode 100755 (executable)
index 8bc0b29..0000000
+++ /dev/null
@@ -1,764 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="ControlPanel (Vista)"\r
-       ProjectGUID="{0DF09484-B4C2-4AB4-9FC0-7B091ADEAFEB}"\r
-       Keyword="MFCProj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderThrough=""\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="0"\r
-                               DisableSpecificWarnings="4311;4312"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="2"\r
-                               SuppressStartupBanner="true"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;DEBUG=1;UNICODE;_UNICODE;_WINDOWS;WINVER=0x0501;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderThrough=""\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="0"\r
-                               DisableSpecificWarnings="4311;4312"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="2"\r
-                               SuppressStartupBanner="true"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel64.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="1"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="false"\r
-                               RuntimeLibrary="0"\r
-                               EnableFunctionLevelLinking="true"\r
-                               TreatWChar_tAsBuiltInType="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               DisableSpecificWarnings="4702"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="ExeBuild\$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="1"\r
-                               AdditionalIncludeDirectories="..;../../mDNSCore;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0501;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="false"\r
-                               RuntimeLibrary="0"\r
-                               EnableFunctionLevelLinking="true"\r
-                               TreatWChar_tAsBuiltInType="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ObjectFile="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\vc80.pdb"\r
-                               WarningLevel="4"\r
-                               SuppressStartupBanner="true"\r
-                               DisableSpecificWarnings="4702"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)/ControlPanel.exe"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               ProgramDatabaseFile="$(OutDir)\ControlPanel.pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               EntryPointSymbol="wWinMainCRTStartup"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\ControlPanel64.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"\r
-                       >\r
-                       <File\r
-                               RelativePath="ConfigDialog.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="ConfigPropertySheet.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ControlPanelExe.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\FifthPage.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="FirstPage.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\FourthPage.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="SecondPage.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="SharedSecret.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="stdafx.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="0"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               Optimization="2"\r
-                                               PreprocessorDefinitions=""\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="ThirdPage.cpp"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl"\r
-                       >\r
-                       <File\r
-                               RelativePath="ConfigDialog.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="ConfigPropertySheet.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ControlPanelExe.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\FifthPage.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="FirstPage.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\FourthPage.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="Resource.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="SecondPage.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="SharedSecret.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="stdafx.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="ThirdPage.h"\r
-                               >\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
-                       >\r
-                       <File\r
-                               RelativePath="res\configurator.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\controlpanel.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\res\ControlPanel.rc2"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\ControlPanelExe.rc"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\failure.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\success.ico"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Support"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\CommonServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dns_sd.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Secret.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Secret.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\WinServices.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\WinServices.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.rc b/mDNSWindows/ControlPanel/ControlPanelLocRes.rc
deleted file mode 100755 (executable)
index 4ba22b4..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
-    "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
-    "#include ""afxres.h""\r\n"\r
-    "#include ""WinVersRes.h""\r\n"\r
-    "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
-    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
-    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
-    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
-    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
-    "\r\n"\r
-    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
-    "LANGUAGE 9, 1\r\n"\r
-    "#pragma code_page(1252)\r\n"\r
-    "#include ""afxres.rc""     // Standard components\r\n"\r
-    "#endif\r\n"\r
-    "\0"\r
-END\r
-\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
-    BLOCK "StringFileInfo"\r
-    BEGIN\r
-        BLOCK "040904b0"\r
-        BEGIN\r
-            VALUE "CompanyName", MASTER_COMPANY_NAME\r
-            VALUE "FileDescription", "Bonjour Resource Module"\r
-            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
-            VALUE "InternalName", "ControlPanelLocalized.dll"\r
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
-            VALUE "OriginalFilename", "ControlPanelLocalized.dll"\r
-            VALUE "ProductName", MASTER_PROD_NAME\r
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
-        END\r
-    END\r
-    BLOCK "VarFileInfo"\r
-    BEGIN\r
-        VALUE "Translation", 0x409, 1200\r
-    END\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Dialog\r
-//\r
-\r
-IDR_APPLET_PAGE1 DIALOGEX 0, 0, 262, 140\r
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
-CAPTION "Registration"\r
-FONT 8, "MS Sans Serif", 0, 0, 0x0\r
-BEGIN\r
-    LTEXT           "Hostname:",IDC_STATIC,13,22,35,8\r
-    EDITTEXT        IDC_HOSTNAME,55,20,184,12,ES_AUTOHSCROLL\r
-    LTEXT           "User:",IDC_STATIC,13,38,35,8\r
-    EDITTEXT        IDC_USERNAME,55,36,184,12,ES_AUTOHSCROLL\r
-    LTEXT           "Password:",IDC_STATIC,13,54,35,8\r
-    EDITTEXT        IDC_PASSWORD,55,52,184,12,ES_PASSWORD | ES_AUTOHSCROLL\r
-    CONTROL         "Advertise services in this domain using Bonjour",IDC_ADVERTISE_SERVICES,\r
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,55,80,199,8\r
-END\r
-\r
-IDR_APPLET_PAGE3 DIALOGEX 0, 0, 262, 140\r
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
-CAPTION "Browsing"\r
-FONT 8, "MS Sans Serif", 0, 0, 0x0\r
-BEGIN\r
-    LTEXT           "Choose which domains to browse using wide-area Bonjour",\r
-                    -1,7,16,248,12\r
-    CONTROL         "",IDC_BROWSE_LIST,"SysListView32",LVS_REPORT | \r
-                    LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | WS_BORDER | \r
-                    WS_TABSTOP,7,37,248,57\r
-    PUSHBUTTON      "Add",IDC_ADD_BROWSE_DOMAIN,152,100,50,14\r
-    PUSHBUTTON      "Remove",IDC_REMOVE_BROWSE_DOMAIN,205,100,50,14\r
-END\r
-\r
-IDR_APPLET_PAGE5 DIALOGEX 0, 0, 262, 140\r
-STYLE DS_SETFONT | WS_CHILD | WS_CAPTION\r
-CAPTION "Services"\r
-FONT 8, "MS Sans Serif", 0, 0, 0x0\r
-BEGIN\r
-    CONTROL         "Advertise shared folders using Bonjour",IDC_ADVERTISE_SMB,\r
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,19,199,8\r
-    CONTROL         "Enable Wake on Demand",IDC_POWER_MANAGEMENT,\r
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,34,199,8\r
-END\r
-\r
-IDR_POWER_MANAGEMENT_WARNING DIALOGEX 0, 0, 230, 95\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
-    WS_SYSMENU\r
-CAPTION "Power Management"\r
-FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
-BEGIN\r
-    DEFPUSHBUTTON   "OK",IDOK,173,74,50,14\r
-    LTEXT           "When 'Wake On Demand' is enabled, you may hear your computer wake up occasionally.",\r
-                                       IDC_STATIC,50,12,175,26\r
-    LTEXT           "This informs other devices that your computer is still available on the network.",\r
-                    IDC_STATIC,50,38,175,26\r
-    ICON            IDI_ENERGY_SAVER,IDC_ENERGY_SAVER,2,10,64,64,SS_REALSIZEIMAGE\r
-END\r
-\r
-IDR_ADD_BROWSE_DOMAIN DIALOGEX 0, 0, 230, 95\r
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | \r
-    WS_SYSMENU\r
-CAPTION "Add Browse Domain"\r
-FONT 8, "MS Shell Dlg", 400, 0, 0x1\r
-BEGIN\r
-    DEFPUSHBUTTON   "OK",IDOK,117,74,50,14\r
-    PUSHBUTTON      "Cancel",IDCANCEL,173,74,50,14\r
-    COMBOBOX        IDC_COMBO1,35,42,188,100,CBS_DROPDOWN | CBS_SORT | \r
-                    WS_VSCROLL | WS_TABSTOP\r
-    LTEXT           "Domain:",IDC_STATIC,7,43,27,8\r
-    LTEXT           "The following domain will be added to your list of Bonjour browse domains.",\r
-                    IDC_STATIC,7,15,216,16\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// DESIGNINFO\r
-//\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-GUIDELINES DESIGNINFO \r
-BEGIN\r
-    IDR_APPLET_PAGE1, DIALOG\r
-    BEGIN\r
-        LEFTMARGIN, 7\r
-        RIGHTMARGIN, 255\r
-        TOPMARGIN, 7\r
-        BOTTOMMARGIN, 133\r
-    END\r
-\r
-    IDR_APPLET_PAGE2, DIALOG\r
-    BEGIN\r
-        LEFTMARGIN, 7\r
-        RIGHTMARGIN, 255\r
-        TOPMARGIN, 7\r
-        BOTTOMMARGIN, 133\r
-    END\r
-\r
-    IDR_SECRET, DIALOG\r
-    BEGIN\r
-        LEFTMARGIN, 7\r
-        RIGHTMARGIN, 244\r
-        TOPMARGIN, 7\r
-        BOTTOMMARGIN, 83\r
-    END\r
-\r
-    IDR_APPLET_PAGE3, DIALOG\r
-    BEGIN\r
-        LEFTMARGIN, 7\r
-        RIGHTMARGIN, 255\r
-        TOPMARGIN, 7\r
-        BOTTOMMARGIN, 133\r
-    END\r
-\r
-       IDR_POWER_MANAGEMENT_WARNING, DIALOG\r
-       BEGIN\r
-               LEFTMARGIN, 7\r
-               RIGHTMARGIN, 223\r
-               TOPMARGIN, 7,\r
-               BOTTOMMARGIN, 88\r
-       END\r
-\r
-    IDR_ADD_BROWSE_DOMAIN, DIALOG\r
-    BEGIN\r
-        LEFTMARGIN, 7\r
-        RIGHTMARGIN, 223\r
-        TOPMARGIN, 7\r
-        BOTTOMMARGIN, 88\r
-    END\r
-END\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// String Table\r
-//\r
-\r
-STRINGTABLE \r
-BEGIN\r
-    IDR_APPLET              "Bonjour"\r
-       IDS_APPLET_NAME                 "Bonjour"\r
-    IDS_APPLET_DESCRIPTION  "Bonjour"\r
-       IDS_APPLET_TOOLTIP              "Change Bonjour settings for this computer."\r
-END\r
-\r
-#endif    // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc"     // Standard components\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif    // not APSTUDIO_INVOKED\r
-\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj b/mDNSWindows/ControlPanel/ControlPanelLocRes.vcproj
deleted file mode 100755 (executable)
index cdcee9b..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="ControlPanelLocRes"\r
-       ProjectGUID="{4490229E-025A-478F-A2CF-51154DA83E39}"\r
-       RootNamespace="ControlPanelLocRes"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".."\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Debug/"\r
-                               ObjectFile=".\Debug/"\r
-                               ProgramDataBaseFileName=".\Debug/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               AdditionalDependencies=""\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
-                               SubSystem="2"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="3"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".."\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Debug/"\r
-                               ObjectFile=".\Debug/"\r
-                               ProgramDataBaseFileName=".\Debug/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               AdditionalDependencies=""\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
-                               SubSystem="2"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="2"\r
-                               FavorSizeOrSpeed="2"\r
-                               OmitFramePointers="true"\r
-                               AdditionalIncludeDirectories=".."\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               RuntimeLibrary="0"\r
-                               BufferSecurityCheck="false"\r
-                               EnableFunctionLevelLinking="false"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Release/"\r
-                               ObjectFile=".\Release/"\r
-                               ProgramDataBaseFileName=".\Release/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               AdditionalDependencies=""\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               ProgramDatabaseFile=""\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="3"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="2"\r
-                               FavorSizeOrSpeed="2"\r
-                               OmitFramePointers="true"\r
-                               AdditionalIncludeDirectories=".."\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               RuntimeLibrary="0"\r
-                               BufferSecurityCheck="false"\r
-                               EnableFunctionLevelLinking="false"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Release/"\r
-                               ObjectFile=".\Release/"\r
-                               ProgramDataBaseFileName=".\Release/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;if not exist $(OutDir)\ControlPanel.Resources\en.lproj mkdir $(OutDir)\ControlPanel.Resources\en.lproj&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               AdditionalDependencies=""\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\en.lproj\ControlPanelLocalized.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               ProgramDatabaseFile=""\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                                          &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources\en.lproj&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc"\r
-                       >\r
-                       <File\r
-                               RelativePath="resource_loc_res.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"\r
-                       >\r
-                       <File\r
-                               RelativePath="ControlPanelLocRes.rc"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-               <Global\r
-                       Name="RESOURCE_FILE"\r
-                       Value="ControlPanelLocRes.rc"\r
-               />\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.vcxproj b/mDNSWindows/ControlPanel/ControlPanelLocRes.vcxproj
deleted file mode 100755 (executable)
index bc51708..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Template|Win32">\r
-      <Configuration>Template</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Template|x64">\r
-      <Configuration>Template</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{4490229E-025A-478F-A2CF-51154DA83E39}</ProjectGuid>\r
-    <RootNamespace>ControlPanelLocRes</RootNamespace>\r
-    <ProjectName>ControlPanelLocRes</ProjectName>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\en.lproj\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ControlPanelLocalized</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ControlPanelLocalized</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">ControlPanelLocalized</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ControlPanelLocalized</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ControlPanelLocalized</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|x64'">ControlPanelLocalized</TargetName>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.dll</TargetExt>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.dll</TargetExt>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">.dll</TargetExt>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.dll</TargetExt>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.dll</TargetExt>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|x64'">.dll</TargetExt>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Debug/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Debug/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
-      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
-      <OmitFramePointers>true</OmitFramePointers>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <BufferSecurityCheck>false</BufferSecurityCheck>\r
-      <FunctionLevelLinking>false</FunctionLevelLinking>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Release/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <ProgramDatabaseFile>\r
-      </ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"   mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-xcopy /I/Y "$(TargetPath)"                                                                                                                          "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
-      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
-      <OmitFramePointers>true</OmitFramePointers>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <BufferSecurityCheck>false</BufferSecurityCheck>\r
-      <FunctionLevelLinking>false</FunctionLevelLinking>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Release/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-if not exist $(OutDir)ControlPanel.Resources\en.lproj mkdir $(OutDir)ControlPanel.Resources\en.lproj\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)ControlPanelLocalized.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <ProgramDatabaseFile>\r
-      </ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"   mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-xcopy /I/Y "$(TargetPath)"                                                                                                                          "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources\en.lproj"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="resource_loc_res.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="ControlPanelLocRes.rc" />\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-  <ProjectExtensions>\r
-    <VisualStudio>\r
-      <UserProperties RESOURCE_FILE="ControlPanelLocRes.rc" />\r
-    </VisualStudio>\r
-  </ProjectExtensions>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/ControlPanel/ControlPanelLocRes.vcxproj.filters b/mDNSWindows/ControlPanel/ControlPanelLocRes.vcxproj.filters
deleted file mode 100755 (executable)
index 7398ead..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{acc11657-b2ba-42ef-9f3e-c4c55cb6d9e9}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{7625f01d-dd41-4ede-9371-d3993f0779ac}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="resource_loc_res.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="ControlPanelLocRes.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.rc b/mDNSWindows/ControlPanel/ControlPanelRes.rc
deleted file mode 100755 (executable)
index b74c59b..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
-    "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
-    "#include ""afxres.h""\r\n"\r
-    "#include ""WinVersRes.h""\r\n"\r
-    "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
-    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"\r
-    "#define _AFX_NO_OLE_RESOURCES\r\n"\r
-    "#define _AFX_NO_TRACKER_RESOURCES\r\n"\r
-    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"\r
-    "\r\n"\r
-    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"\r
-    "LANGUAGE 9, 1\r\n"\r
-    "#pragma code_page(1252)\r\n"\r
-    "#include ""afxres.rc""     // Standard components\r\n"\r
-    "#endif\r\n"\r
-    "\0"\r
-END\r
-\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
-    BLOCK "StringFileInfo"\r
-    BEGIN\r
-        BLOCK "040904b0"\r
-        BEGIN\r
-            VALUE "CompanyName", MASTER_COMPANY_NAME\r
-            VALUE "FileDescription", "Bonjour Resource Module"\r
-            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
-            VALUE "InternalName", "ControlPanelResources.dll"\r
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
-            VALUE "OriginalFilename", "ControlPanelResources.dll"\r
-            VALUE "ProductName", MASTER_PROD_NAME\r
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
-        END\r
-    END\r
-    BLOCK "VarFileInfo"\r
-    BEGIN\r
-        VALUE "Translation", 0x409, 1200\r
-    END\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Icon\r
-//\r
-\r
-// Icon with lowest ID value placed first to ensure application icon\r
-// remains consistent on all systems.\r
-IDR_APPLET              ICON                    "res\\controlpanel.ico"\r
-IDI_FAILURE             ICON                    "res\\failure.ico"\r
-IDI_SUCCESS             ICON                    "res\\success.ico"\r
-IDI_ENERGY_SAVER       ICON                    "res\\EnergySaver.ico"\r
-#endif    // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-#define _AFX_NO_SPLITTER_RESOURCES\r
-#define _AFX_NO_OLE_RESOURCES\r
-#define _AFX_NO_TRACKER_RESOURCES\r
-#define _AFX_NO_PROPERTY_RESOURCES\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-LANGUAGE 9, 1\r
-#pragma code_page(1252)\r
-#include "afxres.rc"     // Standard components\r
-#endif\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif    // not APSTUDIO_INVOKED\r
-\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.vcproj b/mDNSWindows/ControlPanel/ControlPanelRes.vcproj
deleted file mode 100755 (executable)
index 3e36161..0000000
+++ /dev/null
@@ -1,518 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="ControlPanelRes"\r
-       ProjectGUID="{5254AA9C-3D2E-4539-86D9-5EB0F4151215}"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".."\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Debug/"\r
-                               ObjectFile=".\Debug/"\r
-                               ProgramDataBaseFileName=".\Debug/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
-                               SubSystem="2"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="3"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".."\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Debug/"\r
-                               ObjectFile=".\Debug/"\r
-                               ProgramDataBaseFileName=".\Debug/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/$(ProjectName).pdb"\r
-                               SubSystem="2"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(OutDir)/$(ProjectName).lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="1"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="2"\r
-                               FavorSizeOrSpeed="2"\r
-                               OmitFramePointers="true"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;.."\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               RuntimeLibrary="0"\r
-                               BufferSecurityCheck="false"\r
-                               EnableFunctionLevelLinking="false"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Release/"\r
-                               ObjectFile=".\Release/"\r
-                               ProgramDataBaseFileName=".\Release/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               ProgramDatabaseFile=""\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       UseOfMFC="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="true"\r
-                               SuppressStartupBanner="true"\r
-                               TargetEnvironment="3"\r
-                               TypeLibraryName="$(OutDir)/$(ProjectName).tlb"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               InlineFunctionExpansion="2"\r
-                               FavorSizeOrSpeed="2"\r
-                               OmitFramePointers="true"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;.."\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WINVER=0x0400"\r
-                               StringPooling="true"\r
-                               RuntimeLibrary="0"\r
-                               BufferSecurityCheck="false"\r
-                               EnableFunctionLevelLinking="false"\r
-                               ForceConformanceInForLoopScope="true"\r
-                               UsePrecompiledHeader="0"\r
-                               PrecompiledHeaderFile=""\r
-                               AssemblerListingLocation=".\Release/"\r
-                               ObjectFile=".\Release/"\r
-                               ProgramDataBaseFileName=".\Release/"\r
-                               BrowseInformation="1"\r
-                               WarningLevel="4"\r
-                               WarnAsError="false"\r
-                               SuppressStartupBanner="true"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               CompileAs="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories=".."\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                               Description="Building Output Directories"\r
-                               CommandLine="if not exist $(OutDir)\ControlPanel.Resources mkdir $(OutDir)\ControlPanel.Resources&#x0D;&#x0A;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089 "\r
-                               OutputFile="$(OutDir)\ControlPanel.Resources\ControlPanelResources.dll"\r
-                               LinkIncremental="1"\r
-                               SuppressStartupBanner="true"\r
-                               IgnoreDefaultLibraryNames=""\r
-                               ModuleDefinitionFile=""\r
-                               ProgramDatabaseFile=""\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               ResourceOnlyDLL="true"\r
-                               ImportLibrary="$(IntDir)/$(ProjectName).lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                                            &quot;$(DSTROOT)\Program Files\Bonjour SDK\bin\$(PlatformName)\ControlPanel.Resources&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc"\r
-                       >\r
-                       <File\r
-                               RelativePath="resource_res.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest"\r
-                       >\r
-                       <File\r
-                               RelativePath="res\about.bmp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\about.bmp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\button-2k.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\button-xp.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\res\cold.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="ControlPanelRes.rc"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\hot.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="res\logo.bmp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\logo.bmp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="Web.ico"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-               <Global\r
-                       Name="RESOURCE_FILE"\r
-                       Value="ControlPanelRes.rc"\r
-               />\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.vcxproj b/mDNSWindows/ControlPanel/ControlPanelRes.vcxproj
deleted file mode 100755 (executable)
index 321e5ee..0000000
+++ /dev/null
@@ -1,393 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Template|Win32">\r
-      <Configuration>Template</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Template|x64">\r
-      <Configuration>Template</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{5254AA9C-3D2E-4539-86D9-5EB0F4151215}</ProjectGuid>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>Static</UseOfMfc>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">ControlPanelResources</TargetName>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.dll</TargetExt>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">ControlPanelResources</TargetName>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.dll</TargetExt>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">ControlPanelResources</TargetName>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">.dll</TargetExt>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">ControlPanelResources</TargetName>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">.dll</TargetExt>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">ControlPanelResources</TargetName>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Release|x64'">.dll</TargetExt>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\ControlPanel.Resources\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Template|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Template|x64'">ControlPanelResources</TargetName>\r
-    <TargetExt Condition="'$(Configuration)|$(Platform)'=='Template|x64'">.dll</TargetExt>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Debug/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;DEBUG=1;ENABLE_DOT_LOCAL_NAMES;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Debug/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(OutDir)$(ProjectName).lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
-      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
-      <OmitFramePointers>true</OmitFramePointers>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <BufferSecurityCheck>false</BufferSecurityCheck>\r
-      <FunctionLevelLinking>false</FunctionLevelLinking>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Release/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <ProgramDatabaseFile>\r
-      </ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"   mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-xcopy /I/Y "$(TargetPath)"                                                                                                            "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>true</MkTypLibCompatible>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-      <TypeLibraryName>$(OutDir)$(ProjectName).tlb</TypeLibraryName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>\r
-      <FavorSizeOrSpeed>Size</FavorSizeOrSpeed>\r
-      <OmitFramePointers>true</OmitFramePointers>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;WINVER=0x0400;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <BufferSecurityCheck>false</BufferSecurityCheck>\r
-      <FunctionLevelLinking>false</FunctionLevelLinking>\r
-      <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-      <AssemblerListingLocation>.\Release/</AssemblerListingLocation>\r
-      <ObjectFileName>.\Release/</ObjectFileName>\r
-      <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>\r
-      <BrowseInformation>true</BrowseInformation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <TreatWarningAsError>false</TreatWarningAsError>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <CompileAs>Default</CompileAs>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <PreLinkEvent>\r
-      <Message>Building Output Directories</Message>\r
-      <Command>if not exist $(OutDir)ControlPanel.Resources mkdir $(OutDir)ControlPanel.Resources\r
-</Command>\r
-    </PreLinkEvent>\r
-    <Link>\r
-      <AdditionalOptions>/MACHINE:I386 /IGNORE:4089  %(AdditionalOptions)</AdditionalOptions>\r
-      <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
-      <SuppressStartupBanner>true</SuppressStartupBanner>\r
-      <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\r
-      <ModuleDefinitionFile>\r
-      </ModuleDefinitionFile>\r
-      <ProgramDatabaseFile>\r
-      </ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <NoEntryPoint>true</NoEntryPoint>\r
-      <ImportLibrary>$(IntDir)$(ProjectName).lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"   mkdir "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-xcopy /I/Y "$(TargetPath)"                                                                                                            "$(DSTROOT)\Program Files\Bonjour SDK\bin\$(Platform)\ControlPanel.Resources"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Template|Win32'">\r
-    <Link>\r
-      <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Template|x64'">\r
-    <Link>\r
-      <OutputFile>$(OutDir)ControlPanelResources.dll</OutputFile>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="resource_res.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="res\about.bmp" />\r
-    <None Include="about.bmp" />\r
-    <None Include="res\button-2k.ico" />\r
-    <None Include="res\button-xp.ico" />\r
-    <None Include="res\cold.ico" />\r
-    <None Include="hot.ico" />\r
-    <None Include="res\logo.bmp" />\r
-    <None Include="logo.bmp" />\r
-    <None Include="Web.ico" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="ControlPanelRes.rc" />\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-  <ProjectExtensions>\r
-    <VisualStudio>\r
-      <UserProperties RESOURCE_FILE="ControlPanelRes.rc" />\r
-    </VisualStudio>\r
-  </ProjectExtensions>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/ControlPanel/ControlPanelRes.vcxproj.filters b/mDNSWindows/ControlPanel/ControlPanelRes.vcxproj.filters
deleted file mode 100755 (executable)
index 42f1392..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{46e7bad9-15a3-43d9-ad60-c91ea9693b5d}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{6f549e07-210f-4cd6-96ae-8eda3aaae73b}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;jpg;jpeg;jpe;manifest</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="resource_res.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="res\about.bmp">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="about.bmp">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\button-2k.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\button-xp.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\cold.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="hot.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="res\logo.bmp">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="logo.bmp">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="Web.ico">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="ControlPanelRes.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/ControlPanel/FourthPage.cpp b/mDNSWindows/ControlPanel/FourthPage.cpp
deleted file mode 100755 (executable)
index 7ded08f..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "FourthPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-#include "SharedSecret.h"
-
-#include <WinServices.h>
-    
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CFourthPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::CFourthPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CFourthPage::CFourthPage()
-:
-       CPropertyPage(CFourthPage::IDD)
-{
-       //{{AFX_DATA_INIT(CFourthPage)
-       //}}AFX_DATA_INIT
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::~CFourthPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CFourthPage::~CFourthPage()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CFourthPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CFourthPage)
-       //}}AFX_DATA_MAP
-       DDX_Control(pDX, IDC_POWER_MANAGEMENT, m_checkBox);
-}
-
-BEGIN_MESSAGE_MAP(CFourthPage, CPropertyPage)
-       //{{AFX_MSG_MAP(CFourthPage)
-       //}}AFX_MSG_MAP
-
-       ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CFourthPage::OnBnClickedPowerManagement)
-
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CFourthPage::SetModified( BOOL bChanged )
-{
-       m_modified = bChanged;
-
-       CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CFourthPage::OnSetActive()
-{
-       CConfigPropertySheet    *       psheet;
-       HKEY                                            key = NULL;
-       DWORD                                           dwSize;
-       DWORD                                           enabled;
-       DWORD                                           err;
-       BOOL                                            b = CPropertyPage::OnSetActive();
-
-       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
-       require_quiet( psheet, exit );
-
-       m_checkBox.SetCheck( 0 );
-
-       // Now populate the browse domain box
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
-                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       dwSize = sizeof( DWORD );
-       err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-       require_noerr( err, exit );
-
-       m_checkBox.SetCheck( enabled );
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CFourthPage::OnOK()
-{
-       if ( m_modified )
-       {
-               Commit();
-       }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CFourthPage::Commit()
-{
-       HKEY            key             = NULL;
-       DWORD           enabled;
-       DWORD           err;
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
-                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       enabled = m_checkBox.GetCheck();
-       err = RegSetValueEx( key, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
-       require_noerr( err, exit );
-       
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage::OnBnClickedRemoveBrowseDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-
-
-void CFourthPage::OnBnClickedPowerManagement()
-
-{
-
-       char buf[ 256 ];
-
-
-
-       snprintf( buf, sizeof( buf ), "check box: %d", m_checkBox.GetCheck() );
-
-       OutputDebugStringA( buf );
-
-       // TODO: Add your control notification handler code here
-
-
-
-       SetModified( TRUE );
-
-}
-
diff --git a/mDNSWindows/ControlPanel/FourthPage.h b/mDNSWindows/ControlPanel/FourthPage.h
deleted file mode 100755 (executable)
index d595291..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-#include "afxcmn.h"
-
-#include "afxwin.h"
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CFourthPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CFourthPage : public CPropertyPage
-{
-public:
-       CFourthPage();
-       ~CFourthPage();
-
-protected:
-
-       //{{AFX_DATA(CFourthPage)
-       enum { IDD = IDR_APPLET_PAGE4 };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CFourthPage)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CFourthPage)
-
-       //{{AFX_MSG(CFourthPage)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-       
-private:
-       
-       typedef std::list<CString> StringList;
-
-       afx_msg BOOL
-       OnSetActive();
-       
-       afx_msg void
-       OnOK();
-       
-       void
-       SetModified( BOOL bChanged = TRUE );
-       
-       void
-       Commit();
-
-       BOOL                    m_modified;
-
-public:
-private:
-
-       CButton m_checkBox;
-
-public:
-
-
-       afx_msg void OnBnClickedPowerManagement();
-
-};
diff --git a/mDNSWindows/ControlPanel/RegistrationPage.cpp b/mDNSWindows/ControlPanel/RegistrationPage.cpp
deleted file mode 100755 (executable)
index 55755f0..0000000
+++ /dev/null
@@ -1,387 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <Secret.h>
-#include "RegistrationPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-extern "C"
-{
-#include <ClientCommon.h>
-}
-#include <WinServices.h>
-
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CRegistrationPage, CPropertyPage)
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::CRegistrationPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CRegistrationPage::CRegistrationPage()
-:
-       CPropertyPage(CRegistrationPage::IDD),
-       m_ignoreChanges( false ),
-       m_hostnameSetupKey( NULL ),
-       m_registrationSetupKey( NULL ),
-       m_statusKey( NULL )
-{
-       //{{AFX_DATA_INIT(CRegistrationPage)
-       //}}AFX_DATA_INIT
-
-       OSStatus err;
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\Hostnames", 0,
-                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_hostnameSetupKey, NULL );
-       check_noerr( err );
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, 0,
-                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_registrationSetupKey, NULL );
-       check_noerr( err );
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\State\\Hostnames", 0,
-                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_statusKey, NULL );
-       check_noerr( err );
-
-       
-}
-
-CRegistrationPage::~CRegistrationPage()
-{
-       if ( m_hostnameSetupKey )
-       {
-               RegCloseKey( m_hostnameSetupKey );
-               m_hostnameSetupKey = NULL;
-       }
-
-       if ( m_registrationSetupKey )
-       {
-               RegCloseKey( m_registrationSetupKey );
-               m_registrationSetupKey = NULL;
-       }
-
-       if ( m_statusKey )
-       {
-               RegCloseKey( m_statusKey );
-               m_statusKey = NULL;
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CRegistrationPage)
-       //}}AFX_DATA_MAP
-       DDX_Control(pDX, IDC_HOSTNAME, m_hostnameControl);
-       DDX_Control(pDX, IDC_USERNAME, m_usernameControl);
-       DDX_Control(pDX, IDC_PASSWORD, m_passwordControl);
-       DDX_Control(pDX, IDC_ADVERTISE_SERVICES, m_advertiseServices);
-}
-
-BEGIN_MESSAGE_MAP(CRegistrationPage, CPropertyPage)
-       //{{AFX_MSG_MAP(CRegistrationPage)
-       //}}AFX_MSG_MAP
-       ON_EN_CHANGE(IDC_HOSTNAME, OnEnChangeHostname)
-       ON_EN_CHANGE(IDC_USERNAME, OnEnChangeUsername)
-       ON_EN_CHANGE(IDC_PASSWORD, OnEnChangePassword)
-       ON_BN_CLICKED(IDC_ADVERTISE_SERVICES, OnBnClickedAdvertiseServices)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::OnEnChangedHostname
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnEnChangeHostname()
-{
-       if ( !m_ignoreChanges )
-       {
-               SetModified( TRUE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::OnEnChangedUsername
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnEnChangeUsername()
-{
-       if ( !m_ignoreChanges )
-       {
-               SetModified( TRUE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::OnEnChangedPassword
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnEnChangePassword()
-{
-       if ( !m_ignoreChanges )
-       {
-               SetModified( TRUE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::OnBnClickedAdvertiseServices
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::OnBnClickedAdvertiseServices()
-{
-       if ( !m_ignoreChanges )
-       {
-               SetModified( TRUE );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CRegistrationPage::SetModified( BOOL bChanged )
-{
-       m_modified = bChanged ? true : false;
-
-       CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CRegistrationPage::OnSetActive()
-{
-       TCHAR   name[kDNSServiceMaxDomainName + 1];
-       DWORD   nameLen = ( kDNSServiceMaxDomainName + 1 ) * sizeof( TCHAR );
-       DWORD   err;
-
-       BOOL b = CPropertyPage::OnSetActive();
-
-       m_ignoreChanges = true;
-       m_modified = FALSE;
-       
-       if ( m_hostnameSetupKey )
-       {
-               err = RegQueryValueEx( m_hostnameSetupKey, L"", NULL, NULL, (LPBYTE) name, &nameLen );
-
-               if ( !err )
-               {
-                       char    hostnameUTF8[ 256 ];
-                       char    outDomain[ 256 ];
-                       char    outUsername[ 256 ];
-                       char    outPassword[ 256 ];
-                       CString hostname = name;
-                       CString username;
-                       CString password;
-
-                       m_hostnameControl.SetWindowText( hostname );
-
-                       StringObjectToUTF8String( hostname, hostnameUTF8, sizeof( hostnameUTF8 ) );
-
-                       if ( LsaGetSecret( hostnameUTF8, outDomain, sizeof( outDomain ) / sizeof( TCHAR ), outUsername, sizeof( outUsername ) / sizeof( TCHAR ), outPassword, sizeof( outPassword ) / sizeof( TCHAR ) ) )
-                       {
-                               username = outUsername;
-                               m_usernameControl.SetWindowText( username );
-
-                               password = outPassword;
-                               m_passwordControl.SetWindowText( password );
-                       }
-               }
-       }
-
-       m_advertiseServices.SetCheck( 0 );
-
-       if ( m_registrationSetupKey )
-       {
-               HKEY            subKey = NULL;
-               DWORD           dwSize;
-               DWORD           enabled = 0;
-               TCHAR           subKeyName[MAX_KEY_LENGTH];
-               DWORD           cSubKeys = 0;
-               DWORD           cbMaxSubKey;
-               DWORD           cchMaxClass;
-               OSStatus        err;
-
-               err = RegQueryInfoKey( m_registrationSetupKey, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-               if ( !err )
-               {
-                       if ( cSubKeys > 0 )
-                       {       
-                               dwSize = MAX_KEY_LENGTH;
-                   
-                               err = RegEnumKeyEx( m_registrationSetupKey, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-                               if ( !err )
-                               {
-                                       err = RegOpenKey( m_registrationSetupKey, subKeyName, &subKey );
-                                       if ( !err )
-                                       {
-                                               dwSize = sizeof( DWORD );
-                                               err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-                                               if ( !err && enabled )
-                                               {
-                                                       m_advertiseServices.SetCheck( enabled );
-                                               }
-
-                                               RegCloseKey( subKey );
-                                               subKey = NULL;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       m_ignoreChanges = false;
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CRegistrationPage::OnOK()
-{
-       if ( m_modified )
-       {
-               Commit();
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CRegistrationPage::Commit()
-{
-       CString hostname;
-       char    hostnameUTF8[ 256 ];
-       CString username;
-       char    usernameUTF8[ 256 ];
-       CString password;
-       char    passwordUTF8[ 256 ];
-       DWORD   enabled = 1;
-       BOOL    secret = FALSE;
-       DWORD   err;
-
-       m_hostnameControl.GetWindowText( hostname );
-       hostname.MakeLower();
-       hostname.TrimRight( '.' );
-       StringObjectToUTF8String( hostname, hostnameUTF8, sizeof( hostnameUTF8 ) );
-       
-       m_usernameControl.GetWindowText( username );
-       m_passwordControl.GetWindowText( password );
-       
-       if ( username.GetLength() && password.GetLength() )
-       {
-               StringObjectToUTF8String( username, usernameUTF8, sizeof( usernameUTF8 ) );     
-               StringObjectToUTF8String( password, passwordUTF8, sizeof( passwordUTF8 ) );
-               secret = TRUE;
-       }
-
-       if ( m_hostnameSetupKey != NULL )
-       {
-               err = RegSetValueEx( m_hostnameSetupKey, L"", 0, REG_SZ, (LPBYTE) (LPCTSTR) hostname, ( hostname.GetLength() + 1 ) * sizeof( TCHAR ) );
-               require_noerr( err, exit );
-               
-               err = RegSetValueEx( m_hostnameSetupKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
-               require_noerr( err, exit );
-
-               if ( secret )
-               {
-                       LsaSetSecret( hostnameUTF8, usernameUTF8, passwordUTF8 );
-               }
-       }
-
-       if ( m_registrationSetupKey != NULL )
-       {
-               TCHAR           subKeyName[MAX_KEY_LENGTH];
-               DWORD           cSubKeys = 0;
-               DWORD           cbMaxSubKey;
-               DWORD           cchMaxClass;
-               DWORD           dwSize;
-               int                     i;
-               OSStatus        err = kNoErr;
-
-               // First, remove all the entries that are there
-
-               err = RegQueryInfoKey( m_registrationSetupKey, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-               if ( !err )
-               {
-                       for ( i = 0; i < (int) cSubKeys; i++ )
-                       {       
-                               dwSize = MAX_KEY_LENGTH;
-                           
-                               err = RegEnumKeyEx( m_registrationSetupKey, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-                               require_noerr( err, exit );
-                                       
-                               err = RegDeleteKey( m_registrationSetupKey, subKeyName );
-                               require_noerr( err, exit );
-                       }
-               }
-
-               if ( m_advertiseServices.GetCheck() )
-               {
-                       const char      * domainUTF8;
-                       CString           domain;
-                       char              label[ 64 ];
-                       HKEY              subKey = NULL;
-
-                       domainUTF8      = GetNextLabel( hostnameUTF8, label );
-                       domain          = domainUTF8;
-
-                       err = RegCreateKeyEx( m_registrationSetupKey, domain, 0,
-                                                                        NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &subKey, NULL );
-                       if ( !err )
-                       {
-                               err = RegSetValueEx( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
-                               check_noerr( err );
-
-                               RegCloseKey( subKey );
-                               subKey = NULL;
-                       }
-
-                       if ( secret )
-                       {
-                               LsaSetSecret( domainUTF8, usernameUTF8, passwordUTF8 );
-                       }
-               }
-       }
-
-exit:
-
-       return;
-}
diff --git a/mDNSWindows/ControlPanel/RegistrationPage.h b/mDNSWindows/ControlPanel/RegistrationPage.h
deleted file mode 100755 (executable)
index 935a418..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-#include <DebugServices.h>
-#include "afxwin.h"
-
-    
-//---------------------------------------------------------------------------------------------------------------------------
-//     CRegistrationPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CRegistrationPage : public CPropertyPage
-{
-public:
-       CRegistrationPage();
-       ~CRegistrationPage();
-
-protected:
-       //{{AFX_DATA(CRegistrationPage)
-       enum { IDD = IDR_APPLET_PAGE1 };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CRegistrationPage)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CRegistrationPage)
-
-       //{{AFX_MSG(CRegistrationPage)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-
-private:
-
-       afx_msg BOOL    OnSetActive();
-       afx_msg void    OnOK();
-
-       void                    SetModified( BOOL bChanged = TRUE );
-       void                    Commit();
-
-       CEdit                   m_hostnameControl;
-       CEdit                   m_usernameControl;
-       CEdit                   m_passwordControl;
-       CButton                 m_advertiseServices;
-       bool                    m_ignoreChanges;
-       bool                    m_modified;
-       HKEY                    m_hostnameSetupKey;
-       HKEY                    m_registrationSetupKey;
-       HKEY                    m_statusKey;
-       
-public:
-       
-       afx_msg void OnEnChangeHostname();
-       afx_msg void OnEnChangeUsername();
-       afx_msg void OnEnChangePassword();
-       afx_msg void OnBnClickedAdvertiseServices();
-};
diff --git a/mDNSWindows/ControlPanel/SecondPage.cpp b/mDNSWindows/ControlPanel/SecondPage.cpp
deleted file mode 100755 (executable)
index b6cf4ff..0000000
+++ /dev/null
@@ -1,544 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "SecondPage.h"
-#include "resource.h"
-
-#include "ConfigPropertySheet.h"
-#include "SharedSecret.h"
-
-#include <WinServices.h>
-    
-#define MAX_KEY_LENGTH 255
-
-IMPLEMENT_DYNCREATE(CSecondPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::CSecondPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSecondPage::CSecondPage()
-:
-       CPropertyPage(CSecondPage::IDD),
-       m_setupKey( NULL )
-{
-       //{{AFX_DATA_INIT(CSecondPage)
-       //}}AFX_DATA_INIT
-
-       OSStatus err;
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\DynDNS\\Setup\\" kServiceDynDNSRegistrationDomains, 0,
-                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &m_setupKey, NULL );
-       check_noerr( err );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::~CSecondPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSecondPage::~CSecondPage()
-{
-       if ( m_setupKey )
-       {
-               RegCloseKey( m_setupKey );
-               m_setupKey = NULL;
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CSecondPage)
-       //}}AFX_DATA_MAP
-       DDX_Control(pDX, IDC_CHECK1, m_advertiseServicesButton);
-       DDX_Control(pDX, IDC_BUTTON1, m_sharedSecretButton);
-       DDX_Control(pDX, IDC_COMBO2, m_regDomainsBox);
-}
-
-BEGIN_MESSAGE_MAP(CSecondPage, CPropertyPage)
-       //{{AFX_MSG_MAP(CSecondPage)
-       //}}AFX_MSG_MAP
-       ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedSharedSecret)
-       ON_BN_CLICKED(IDC_CHECK1, OnBnClickedAdvertise)
-       ON_CBN_SELCHANGE(IDC_COMBO1, OnCbnSelChange)
-       ON_CBN_EDITCHANGE(IDC_COMBO1, OnCbnEditChange)
-       ON_CBN_EDITCHANGE(IDC_COMBO2, OnCbnEditChange)
-       ON_CBN_SELCHANGE(IDC_COMBO2, OnCbnSelChange)
-       
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::SetModified( BOOL bChanged )
-{
-       m_modified = bChanged;
-
-       CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CSecondPage::OnSetActive()
-{
-       CConfigPropertySheet    *       psheet;
-       DWORD                                           err;
-       BOOL                                            b = CPropertyPage::OnSetActive();
-
-       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
-       require_quiet( psheet, exit );
-       
-       m_modified = FALSE;
-
-       // Clear out what's there
-
-       EmptyComboBox( m_regDomainsBox );
-
-       // Now populate the registration domain box
-
-       err = Populate( m_regDomainsBox, m_setupKey, psheet->m_regDomains );
-       check_noerr( err );
-
-exit:
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::OnOK()
-{
-       if ( m_modified )
-       {
-               Commit();
-       }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::Commit()
-{
-       DWORD err;
-
-       if ( m_setupKey != NULL )
-       {
-               err = Commit( m_regDomainsBox, m_setupKey, m_advertiseServicesButton.GetCheck() == BST_CHECKED );
-               check_noerr( err );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::Commit( CComboBox & box, HKEY key, DWORD enabled )
-{
-       CString         selected;
-       HKEY            subKey  = NULL;
-       TCHAR           subKeyName[MAX_KEY_LENGTH];
-       DWORD           cSubKeys = 0;
-       DWORD           cbMaxSubKey;
-       DWORD           cchMaxClass;
-       DWORD           dwSize;
-       int                     i;
-       OSStatus        err = kNoErr;
-
-       // First, remove all the entries that are there
-
-    err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-       require_noerr( err, exit );
-
-       for ( i = 0; i < (int) cSubKeys; i++ )
-       {       
-               dwSize = MAX_KEY_LENGTH;
-            
-               err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-               require_noerr( err, exit );
-                       
-               err = RegDeleteKey( key, subKeyName );
-               require_noerr( err, exit );
-       }
-
-       // Get selected text
-       
-       box.GetWindowText( selected );
-       
-       // If we haven't seen this string before, add the string to the box and
-       // the registry
-       
-       if ( ( selected.GetLength() > 0 ) && ( box.FindStringExact( -1, selected ) == CB_ERR ) )
-       {
-               CString string;
-
-               box.AddString( selected );
-
-               err = RegQueryString( key, L"UserDefined", string );
-               check_noerr( err );
-
-               if ( string.GetLength() )
-               {
-                       string += L"," + selected;
-               }
-               else
-               {
-                       string = selected;
-               }
-
-               err = RegSetValueEx( key, L"UserDefined", 0, REG_SZ, (LPBYTE) (LPCTSTR) string, ( string.GetLength() + 1) * sizeof( TCHAR ) );
-               check_noerr ( err );
-       }
-
-       // Save selected text in registry.  This will trigger mDNSResponder to setup
-       // DynDNS config again
-
-       err = RegCreateKeyEx( key, selected, 0,
-                             NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &subKey, NULL );
-       require_noerr( err, exit );
-
-       err = RegSetValueEx( subKey, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
-       check_noerr( err );
-
-exit:
-
-       if ( subKey )
-       {
-               RegCloseKey( subKey );
-               subKey = NULL;
-       }
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnBnClickedSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnBnClickedSharedSecret()
-{
-       CString name;
-
-       m_regDomainsBox.GetWindowText( name );
-
-       CSharedSecret dlg;
-
-       dlg.Load( name );
-
-       if ( dlg.DoModal() == IDOK )
-       {
-               DWORD           wakeup = 0;
-               DWORD           dwSize = sizeof( DWORD );
-               OSStatus        err;
-
-               dlg.Commit( name );
-
-               // We have now updated the secret, however the system service
-               // doesn't know about it yet.  So we're going to update the
-               // registry with a dummy value which will cause the system
-               // service to re-initialize it's DynDNS setup
-               //
-
-               RegQueryValueEx( m_setupKey, L"Wakeup", NULL, NULL, (LPBYTE) &wakeup, &dwSize );      
-
-               wakeup++;
-               
-               err = RegSetValueEx( m_setupKey, L"Wakeup", 0, REG_DWORD, (LPBYTE) &wakeup, sizeof( DWORD ) );
-               require_noerr( err, exit );
-       }
-
-exit:
-
-       return;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnBnClickedAdvertise
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnBnClickedAdvertise()
-{
-       int state;
-
-       state = m_advertiseServicesButton.GetCheck();
-
-       m_regDomainsBox.EnableWindow( state );
-       m_sharedSecretButton.EnableWindow( state );
-
-       SetModified( TRUE );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnCbnSelChange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnCbnSelChange()
-{
-       SetModified( TRUE );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnCbnEditChange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSecondPage::OnCbnEditChange()
-{
-       SetModified( TRUE );
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnAddRegistrationDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::OnAddRegistrationDomain( CString & domain )
-{
-       int index = m_regDomainsBox.FindStringExact( -1, domain );
-
-       if ( index == CB_ERR )
-       {
-               m_regDomainsBox.AddString( domain );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::OnRemoveRegistrationDomain
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::OnRemoveRegistrationDomain( CString & domain )
-{
-       int index = m_regDomainsBox.FindStringExact( -1, domain );
-
-       if ( index != CB_ERR )
-       {
-               m_regDomainsBox.DeleteString( index );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::EmptyComboBox
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSecondPage::EmptyComboBox( CComboBox & box )
-{
-       while ( box.GetCount() > 0 )
-       {
-               box.DeleteString( 0 );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::Populate
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::Populate( CComboBox & box, HKEY key, StringList & l )
-{
-       CString         string;
-       HKEY            subKey = NULL;
-       DWORD           dwSize;
-       DWORD           enabled = 0;
-       TCHAR           subKeyName[MAX_KEY_LENGTH];
-       DWORD           cSubKeys = 0;
-       DWORD           cbMaxSubKey;
-       DWORD           cchMaxClass;
-       OSStatus        err;
-
-       err = RegQueryString( key, L"UserDefined", string );
-
-       if ( !err && string.GetLength() )
-       {
-               bool done = false;
-
-               while ( !done )
-               {
-                       CString tok;
-
-                       tok = string.SpanExcluding( L"," );
-
-                       box.AddString( tok );
-
-                       if ( tok != string )
-                       {
-                               // Get rid of that string and comma
-
-                               string = string.Right( string.GetLength() - tok.GetLength() - 1 );
-                       }
-                       else
-                       {
-                               done = true;
-                       }
-               }
-       }
-
-       StringList::iterator it;
-
-       for ( it = l.begin(); it != l.end(); it++ )
-       {
-               if ( box.FindStringExact( -1, *it ) == CB_ERR )
-               {
-                       box.AddString( *it );
-               }
-       }
-
-       err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-       require_noerr( err, exit );
-
-       if ( cSubKeys > 0 )
-       {       
-               dwSize = MAX_KEY_LENGTH;
-            
-               err = RegEnumKeyEx( key, 0, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-               require_noerr( err, exit );
-
-               err = RegOpenKey( key, subKeyName, &subKey );
-               require_noerr( err, exit );
-
-               dwSize = sizeof( DWORD );
-               err = RegQueryValueEx( subKey, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-               require_noerr( err, exit );
-
-               // See if it's there
-
-               if ( box.SelectString( -1, subKeyName ) == CB_ERR )
-               {
-                       // If not, add it
-
-                       box.AddString( subKeyName );
-               }
-
-               box.SelectString( -1, subKeyName );
-
-               RegCloseKey( subKey );
-               subKey = NULL;
-       }
-
-exit:
-
-       m_advertiseServicesButton.SetCheck( ( !err && enabled ) ? BST_CHECKED : BST_UNCHECKED );
-       m_regDomainsBox.EnableWindow( ( !err && enabled ) );
-       m_sharedSecretButton.EnableWindow( (!err && enabled ) );
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::CreateKey
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::CreateKey( CString & name, DWORD enabled )
-{
-       HKEY            key = NULL;
-       OSStatus        err;
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, (LPCTSTR) name, 0,
-                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       err = RegSetValueEx( key, L"Enabled", 0, REG_DWORD, (LPBYTE) &enabled, sizeof( DWORD ) );
-       check_noerr( err );
-
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       return err;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage::RegQueryString
-//---------------------------------------------------------------------------------------------------------------------------
-
-OSStatus
-CSecondPage::RegQueryString( HKEY key, CString valueName, CString & value )
-{
-       TCHAR   *       string;
-       DWORD           stringLen;
-       int                     i;
-       OSStatus        err;
-
-       stringLen       = 1024;
-       string          = NULL;
-       i                       = 0;
-
-       do
-       {
-               if ( string )
-               {
-                       free( string );
-               }
-
-               string = (TCHAR*) malloc( stringLen );
-               require_action( string, exit, err = kUnknownErr );
-               *string = '\0';
-
-               err = RegQueryValueEx( key, valueName, 0, NULL, (LPBYTE) string, &stringLen );
-
-               i++;
-       }
-       while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
-
-       value = string;
-
-exit:
-
-       if ( string )
-       {
-               free( string );
-       }
-
-       return err;
-}
diff --git a/mDNSWindows/ControlPanel/SecondPage.h b/mDNSWindows/ControlPanel/SecondPage.h
deleted file mode 100755 (executable)
index 3bd9e74..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSecondPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CSecondPage : public CPropertyPage
-{
-public:
-       CSecondPage();
-       ~CSecondPage();
-
-protected:
-
-       //{{AFX_DATA(CSecondPage)
-       enum { IDD = IDR_APPLET_PAGE2 };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CSecondPage)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CSecondPage)
-
-       //{{AFX_MSG(CSecondPage)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-public:
-       
-       afx_msg void    OnBnClickedSharedSecret();
-       afx_msg void    OnBnClickedAdvertise();
-
-       void                    OnAddRegistrationDomain( CString & domain );
-       void                    OnRemoveRegistrationDomain( CString & domain );
-       
-private:
-       
-       typedef std::list<CString> StringList;
-
-       afx_msg BOOL
-       OnSetActive();
-       
-       afx_msg void
-       OnOK();
-
-       void
-       EmptyComboBox
-                       (
-                       CComboBox       &       box
-                       );
-
-       OSStatus
-       Populate(
-                       CComboBox       &       box,
-                       HKEY                    key,
-                       StringList      &       l
-                       );
-       
-       void
-       SetModified( BOOL bChanged = TRUE );
-       
-       void
-       Commit();
-
-       OSStatus
-       Commit( CComboBox & box, HKEY key, DWORD enabled );
-
-       OSStatus
-       CreateKey( CString & name, DWORD enabled );
-
-       OSStatus
-       RegQueryString( HKEY key, CString valueName, CString & value );
-
-       CComboBox               m_regDomainsBox;
-       CButton                 m_advertiseServicesButton;
-       CButton                 m_sharedSecretButton;
-       BOOL                    m_modified;
-       HKEY                    m_setupKey;
-
-public:
-       afx_msg void OnCbnSelChange();
-       afx_msg void OnCbnEditChange();
-}; 
diff --git a/mDNSWindows/ControlPanel/ServicesPage.cpp b/mDNSWindows/ControlPanel/ServicesPage.cpp
deleted file mode 100755 (executable)
index 4269fa6..0000000
+++ /dev/null
@@ -1,273 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ServicesPage.h"
-#include "resource.h"
-
-#include "ControlPanelExe.h"
-#include "ConfigPropertySheet.h"
-
-#include <WinServices.h>
-    
-#define MAX_KEY_LENGTH 255
-
-
-IMPLEMENT_DYNCREATE(CServicesPage, CPropertyPage)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::CServicesPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CServicesPage::CServicesPage()
-:
-       CPropertyPage(CServicesPage::IDD)
-{
-       //{{AFX_DATA_INIT(CServicesPage)
-       //}}AFX_DATA_INIT
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::~CServicesPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-CServicesPage::~CServicesPage()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::DoDataExchange(CDataExchange* pDX)
-{
-       CPropertyPage::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(CServicesPage)
-       //}}AFX_DATA_MAP
-       DDX_Control(pDX, IDC_ADVERTISE_SMB, m_SMBCheckBox);
-       DDX_Control(pDX, IDC_POWER_MANAGEMENT, m_powerManagementCheckBox);
-}
-
-BEGIN_MESSAGE_MAP(CServicesPage, CPropertyPage)
-       //{{AFX_MSG_MAP(CServicesPage)
-       //}}AFX_MSG_MAP
-
-       ON_BN_CLICKED(IDC_ADVERTISE_SMB, &CServicesPage::OnBnClickedAdvertiseSMB)
-       ON_BN_CLICKED(IDC_POWER_MANAGEMENT, &CServicesPage::OnBnClickedPowerManagement)
-
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::SetModified
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::SetModified( BOOL bChanged )
-{
-       m_modified = bChanged;
-
-       CPropertyPage::SetModified( bChanged );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::OnSetActive
-//---------------------------------------------------------------------------------------------------------------------------
-
-BOOL
-CServicesPage::OnSetActive()
-{
-       CConfigPropertySheet    *       psheet;
-       HKEY                                            key = NULL;
-       DWORD                                           dwSize;
-       DWORD                                           enabled;
-       DWORD                                           err;
-       BOOL                                            b = CPropertyPage::OnSetActive();
-
-       psheet = reinterpret_cast<CConfigPropertySheet*>(GetParent());
-       require_quiet( psheet, exit );
-
-       m_SMBCheckBox.SetCheck( 0 );
-
-       // Now populate the browse domain box
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", 0,
-                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       dwSize = sizeof( DWORD );
-       err = RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-       require_noerr( err, exit );
-
-       m_SMBCheckBox.SetCheck( enabled );
-
-       RegCloseKey( key );
-       key = NULL;
-
-       m_powerManagementCheckBox.SetCheck( 0 );
-
-       // Now populate the browse domain box
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
-                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       dwSize = sizeof( DWORD );
-       err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-       require_noerr( err, exit );
-
-       m_powerManagementCheckBox.SetCheck( enabled );
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       return b;
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::OnOK
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CServicesPage::OnOK()
-{
-       if ( m_modified )
-       {
-               Commit();
-       }
-}
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CServicesPage::Commit()
-{
-       HKEY            key             = NULL;
-       DWORD           enabled;
-       DWORD           err;
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", 0,
-                               NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       enabled = m_SMBCheckBox.GetCheck();
-       err = RegSetValueEx( key, L"Advertise", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
-       require_noerr( err, exit );
-
-       RegCloseKey( key );
-       key = NULL;
-
-       err = RegCreateKeyEx( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", 0,
-                                 NULL, REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &key, NULL );
-       require_noerr( err, exit );
-
-       enabled = m_powerManagementCheckBox.GetCheck();
-       err = RegSetValueEx( key, L"Enabled", NULL, REG_DWORD, (LPBYTE) &enabled, sizeof( enabled ) );
-       require_noerr( err, exit );
-       
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::OnBnClickedAdvertiseSMB
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::OnBnClickedAdvertiseSMB()
-{
-       SetModified( TRUE );
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage::OnBnClickedPowerManagement
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CServicesPage::OnBnClickedPowerManagement()
-{
-       SetModified( TRUE );
-
-       if ( m_powerManagementCheckBox.GetCheck() )
-       {
-               CPowerManagementWarning dlg( GetParent() );
-
-               dlg.DoModal();
-       }
-}
-
-
-// CPowerManagementWarning dialog
-
-IMPLEMENT_DYNAMIC(CPowerManagementWarning, CDialog)
-CPowerManagementWarning::CPowerManagementWarning(CWnd* pParent /*=NULL*/)
-       : CDialog(CPowerManagementWarning::IDD, pParent)
-{
-}
-
-CPowerManagementWarning::~CPowerManagementWarning()
-{
-}
-
-void CPowerManagementWarning::DoDataExchange(CDataExchange* pDX)
-{
-       CDialog::DoDataExchange(pDX);
-       DDX_Control(pDX, IDC_ENERGY_SAVER, m_energySaverIcon);
-}
-
-
-BOOL
-CPowerManagementWarning::OnInitDialog()
-{      
-       BOOL b = CDialog::OnInitDialog();
-
-       const HICON hIcon = ( HICON ) ::LoadImage( GetNonLocalizedResources(), MAKEINTRESOURCE( IDI_ENERGY_SAVER ), IMAGE_ICON, 0, 0, 0);
-       
-       if ( hIcon )
-       {
-               m_energySaverIcon.SetIcon( hIcon );
-       }
-
-       return b;
-}
-
-
-void
-CPowerManagementWarning::OnOK()
-{
-       CDialog::OnOK();
-}
-
-
-BEGIN_MESSAGE_MAP(CPowerManagementWarning, CDialog)
-END_MESSAGE_MAP()
-
diff --git a/mDNSWindows/ControlPanel/ServicesPage.h b/mDNSWindows/ControlPanel/ServicesPage.h
deleted file mode 100755 (executable)
index d593a72..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "stdafx.h"
-#include "resource.h"
-
-#include <DebugServices.h>
-#include <list>
-#include "afxcmn.h"
-
-#include "afxwin.h"
-
-
-
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CServicesPage
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CServicesPage : public CPropertyPage
-{
-public:
-       CServicesPage();
-       ~CServicesPage();
-
-protected:
-
-       //{{AFX_DATA(CServicesPage)
-       enum { IDD = IDR_APPLET_PAGE5 };
-       //}}AFX_DATA
-
-       //{{AFX_VIRTUAL(CServicesPage)
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-       //}}AFX_VIRTUAL
-
-       DECLARE_DYNCREATE(CServicesPage)
-
-       //{{AFX_MSG(CServicesPage)
-       //}}AFX_MSG
-       DECLARE_MESSAGE_MAP()
-       
-private:
-       
-       typedef std::list<CString> StringList;
-
-       afx_msg BOOL
-       OnSetActive();
-       
-       afx_msg void
-       OnOK();
-       
-       void
-       SetModified( BOOL bChanged = TRUE );
-       
-       void
-       Commit();
-
-       BOOL                    m_modified;
-
-public:
-private:
-
-       CButton m_SMBCheckBox;
-       CButton m_powerManagementCheckBox;
-
-public:
-
-
-       afx_msg void OnBnClickedAdvertiseSMB();
-       afx_msg void OnBnClickedPowerManagement();
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CPowerManagementWarning
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CPowerManagementWarning : public CDialog
-{
-       DECLARE_DYNAMIC(CPowerManagementWarning)
-
-public:
-
-       CPowerManagementWarning(CWnd* pParent = NULL);   // standard constructor
-
-       virtual ~CPowerManagementWarning();
-
-// Dialog Data
-
-       enum { IDD = IDR_POWER_MANAGEMENT_WARNING };
-
-protected:
-
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-
-       virtual BOOL OnInitDialog();
-
-       virtual void OnOK();
-
-       DECLARE_MESSAGE_MAP()
-
-public:
-
-       CStatic m_energySaverIcon;
-};
-
diff --git a/mDNSWindows/ControlPanel/SharedSecret.cpp b/mDNSWindows/ControlPanel/SharedSecret.cpp
deleted file mode 100644 (file)
index 3d19295..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-    
-// SharedSecret.cpp : implementation file
-//
-
-
-#include <Secret.h>
-#include "stdafx.h"
-#include "SharedSecret.h"
-#include <WinServices.h>
-
-#include <DebugServices.h>
-
-
-// SharedSecret dialog
-
-IMPLEMENT_DYNAMIC(CSharedSecret, CDialog)
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSharedSecret::CSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSharedSecret::CSharedSecret(CWnd* pParent /*=NULL*/)
-       : CDialog(CSharedSecret::IDD, pParent)
-       , m_key(_T(""))
-       , m_secret(_T(""))
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSharedSecret::~CSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-CSharedSecret::~CSharedSecret()
-{
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSharedSecret::DoDataExchange
-//---------------------------------------------------------------------------------------------------------------------------
-
-void CSharedSecret::DoDataExchange(CDataExchange* pDX)
-{
-       CDialog::DoDataExchange(pDX);
-       DDX_Text(pDX, IDC_KEY, m_key );
-       DDX_Text(pDX, IDC_SECRET, m_secret );
-}
-
-
-BEGIN_MESSAGE_MAP(CSharedSecret, CDialog)
-END_MESSAGE_MAP()
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSharedSecret::Load
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSharedSecret::Load( CString zone )
-{
-       char    zoneUTF8[ 256 ];
-       char    outDomain[ 256 ];
-       char    outKey[ 256 ];
-       char    outSecret[ 256 ];
-
-       StringObjectToUTF8String( zone, zoneUTF8, sizeof( zoneUTF8 ) );
-
-       if ( LsaGetSecret( zoneUTF8, outDomain, sizeof( outDomain ) / sizeof( TCHAR ), outKey, sizeof( outKey ) / sizeof( TCHAR ), outSecret, sizeof( outSecret ) / sizeof( TCHAR ) ) )
-       {
-               m_key           = outKey;
-               m_secret        = outSecret;
-       }
-       else
-       {
-               m_key = zone;
-       }
-}
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSharedSecret::Commit
-//---------------------------------------------------------------------------------------------------------------------------
-
-void
-CSharedSecret::Commit( CString zone )
-{
-       char    zoneUTF8[ 256 ];
-       char    keyUTF8[ 256 ];
-       char    secretUTF8[ 256 ];
-
-       StringObjectToUTF8String( zone, zoneUTF8, sizeof( zoneUTF8 ) );
-       StringObjectToUTF8String( m_key, keyUTF8, sizeof( keyUTF8 ) );
-       StringObjectToUTF8String( m_secret, secretUTF8, sizeof( secretUTF8 ) );
-
-       LsaSetSecret( zoneUTF8, keyUTF8, secretUTF8 );
-}
diff --git a/mDNSWindows/ControlPanel/SharedSecret.h b/mDNSWindows/ControlPanel/SharedSecret.h
deleted file mode 100644 (file)
index be82d8b..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-    
-#pragma once
-
-#include "resource.h"
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-//     CSharedSecret
-//---------------------------------------------------------------------------------------------------------------------------
-
-class CSharedSecret : public CDialog
-{
-       DECLARE_DYNAMIC(CSharedSecret)
-
-public:
-       CSharedSecret(CWnd* pParent = NULL);   // standard constructor
-       virtual ~CSharedSecret();
-
-// Dialog Data
-       enum { IDD = IDR_SECRET };
-
-       void
-       Load( CString zone );
-
-       void
-       Commit( CString zone );
-
-protected:
-       virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-
-       DECLARE_MESSAGE_MAP()
-
-public:
-
-       CString m_key;
-       CString m_secret;
-};
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest b/mDNSWindows/ControlPanel/res/ControlPanel.dll.manifest
deleted file mode 100644 (file)
index 903b02b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-<?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
deleted file mode 100644 (file)
index 4879215..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-       <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
-       <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
-       <dependency>
-               <dependentAssembly>
-                       <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
-               </dependentAssembly>
-       </dependency>
-       <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
-               <security>
-                       <requestedPrivileges>
-                               <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
-                       </requestedPrivileges>
-               </security>
-       </trustInfo>
-</assembly>
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel.manifest b/mDNSWindows/ControlPanel/res/ControlPanel.manifest
deleted file mode 100644 (file)
index 4879215..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-       <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
-       <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
-       <dependency>
-               <dependentAssembly>
-                       <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="X86" publicKeyToken="6595b64144ccf1df" language="*" />
-               </dependentAssembly>
-       </dependency>
-       <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
-               <security>
-                       <requestedPrivileges>
-                               <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
-                       </requestedPrivileges>
-               </security>
-       </trustInfo>
-</assembly>
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel.rc2 b/mDNSWindows/ControlPanel/res/ControlPanel.rc2
deleted file mode 100755 (executable)
index e3f7422..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-//\r
-// CPL_PP.RC2 - resources Microsoft Visual C++ does not edit directly\r
-//\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-       #error this file is not editable by Microsoft Visual C++\r
-#endif //APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// Add manually edited resources here...\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
diff --git a/mDNSWindows/ControlPanel/res/ControlPanel64.manifest b/mDNSWindows/ControlPanel/res/ControlPanel64.manifest
deleted file mode 100644 (file)
index a47a4e2..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-       <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
-       <description>Control Panel applet for configuring Wide-Area Bonjour.</description>
-       <dependency>
-               <dependentAssembly>
-                       <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="amd64" publicKeyToken="6595b64144ccf1df" language="*" />
-               </dependentAssembly>
-       </dependency>
-       <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
-               <security>
-                       <requestedPrivileges>
-                               <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
-                       </requestedPrivileges>
-               </security>
-       </trustInfo>
-</assembly>
diff --git a/mDNSWindows/ControlPanel/res/EnergySaver.ico b/mDNSWindows/ControlPanel/res/EnergySaver.ico
deleted file mode 100755 (executable)
index c2b935b..0000000
Binary files a/mDNSWindows/ControlPanel/res/EnergySaver.ico and /dev/null differ
diff --git a/mDNSWindows/ControlPanel/res/controlpanel.ico b/mDNSWindows/ControlPanel/res/controlpanel.ico
deleted file mode 100755 (executable)
index 7ef6ebb..0000000
Binary files a/mDNSWindows/ControlPanel/res/controlpanel.ico and /dev/null differ
diff --git a/mDNSWindows/ControlPanel/res/failure.ico b/mDNSWindows/ControlPanel/res/failure.ico
deleted file mode 100755 (executable)
index f0b8f2b..0000000
Binary files a/mDNSWindows/ControlPanel/res/failure.ico and /dev/null differ
diff --git a/mDNSWindows/ControlPanel/res/success.ico b/mDNSWindows/ControlPanel/res/success.ico
deleted file mode 100755 (executable)
index 9b97584..0000000
Binary files a/mDNSWindows/ControlPanel/res/success.ico and /dev/null differ
diff --git a/mDNSWindows/ControlPanel/resource.h b/mDNSWindows/ControlPanel/resource.h
deleted file mode 100644 (file)
index fec673f..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by ControlPanel.rc
-//
-#define IDR_APPLET                      131
-#define IDR_APPLET_PAGE1                131
-#define IDS_APPLET_DESCRIPTION          132
-#define IDR_APPLET_PAGE2                132
-#define IDR_SECRET                      133
-#define IDR_APPLET_PAGE3                134
-#define IDR_APPLET_PAGE4                135
-#define IDR_APPLET_PAGE5                136
-#define IDI_FAILURE                     140
-#define IDI_SUCCESS                     141
-#define IDI_ENERGY_SAVER                               142
-#define IDR_ADD_BROWSE_DOMAIN           143
-#define IDR_POWER_MANAGEMENT_WARNING   144
-#define IDS_REINSTALL                                  145
-#define IDS_REINSTALL_CAPTION                  146
-#define IDS_APPLET_NAME                                        147
-#define IDS_APPLET_TOOLTIP                             148
-#define IDC_HOSTNAME                    1000
-#define IDC_USERNAME                                   1001
-#define IDC_PASSWORD                                   1002
-#define IDC_ADVERTISE_SERVICES                 1003
-#define IDC_BUTTON1                     1004
-#define IDC_COMBO1                      1005
-#define IDC_CHECK1                      1006
-#define IDC_COMBO2                      1007
-#define IDC_EDIT2                       1008
-#define IDC_SECRET                      1009
-#define IDC_COMBO3                      1010
-#define IDC_FAILURE                     1011
-#define IDC_SUCCESS                     1012
-#define IDC_SECRET_NAME                 1013
-#define IDC_NAME                        1014
-#define IDC_KEY                         1015
-#define IDC_LIST1                       1016
-#define IDC_BROWSE_LIST                 1017
-#define IDC_BUTTON2                     1018
-#define IDC_REMOVE_BROWSE_DOMAIN        1019
-#define IDC_ADD_BROWSE_DOMAIN           1020
-#define IDC_POWER_MANAGEMENT            1021
-#define IDC_ADVERTISE_SMB                  1022
-#define IDC_ENERGY_SAVER                               1023
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        149
-#define _APS_NEXT_COMMAND_VALUE         32771
-#define _APS_NEXT_CONTROL_VALUE         1024
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/mDNSWindows/ControlPanel/stdafx.cpp b/mDNSWindows/ControlPanel/stdafx.cpp
deleted file mode 100755 (executable)
index e05ec3d..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- 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.
- */
-
-#include "stdafx.h"
-
-
diff --git a/mDNSWindows/ControlPanel/stdafx.h b/mDNSWindows/ControlPanel/stdafx.h
deleted file mode 100755 (executable)
index 246752e..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- 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.
- */
-
-#pragma once
-
-#ifndef VC_EXTRALEAN
-#define VC_EXTRALEAN           // Exclude rarely-used stuff from Windows headers
-#endif
-
-// Modify the following defines if you have to target a platform prior to the ones specified below.
-// Refer to MSDN for the latest info on corresponding values for different platforms.
-#ifndef WINVER                         // Allow use of features specific to Windows 95 and Windows NT 4 or later.
-#define WINVER 0x0400          // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
-#endif
-
-#ifndef _WIN32_WINNT           // Allow use of features specific to Windows NT 4 or later.
-#define _WIN32_WINNT 0x0400    // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
-#endif                                         
-
-#ifndef _WIN32_WINDOWS         // Allow use of features specific to Windows 98 or later.
-#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
-#endif
-
-// Step 3: We want to see one image, but not a tile
-#ifndef _WIN32_IE                      // Allow use of features specific to IE 4.0 or later.
-#define _WIN32_IE 0x0500       // Change this to the appropriate value to target IE 5.0 or later.
-#endif
-
-#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS     // some CString constructors will be explicit
-
-// turns off MFC's hiding of some common and often safely ignored warning messages
-#define _AFX_ALL_WARNINGS
-
-#if !defined(_WSPIAPI_COUNTOF)
-#      define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
-#endif
-
-#include <afxwin.h>         // MFC core and standard components
-#include <afxext.h>         // MFC extensions
-#include <afxdisp.h>        // MFC Automation classes
-
-#include <afxdtctl.h>          // MFC support for Internet Explorer 4 Common Controls
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-#include <afxcmn.h>                    // MFC support for Windows Common Controls
-#endif // _AFX_NO_AFXCMN_SUPPORT
-#include <afxdlgs.h>
-
-#include <cpl.h>            // Control Panel Applet functions and defines
-
-#include <afxtempl.h>       // MFC Template support
diff --git a/mDNSWindows/DLL.NET/AssemblyInfo.cpp b/mDNSWindows/DLL.NET/AssemblyInfo.cpp
deleted file mode 100755 (executable)
index 40f0b5d..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-    
-#include "stdafx.h"
-#include "WinVersRes.h"
-
-using namespace System;
-using namespace System::Reflection;
-using namespace System::Runtime::CompilerServices;
-using namespace System::Runtime::InteropServices;
-using namespace System::Security::Permissions;
-
-//
-// General Information about an assembly is controlled through the following 
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-//
-[assembly:AssemblyTitleAttribute("dnssd.NET")];
-[assembly:AssemblyDescriptionAttribute(".NET wrapper for DNS-SD services")];
-[assembly:AssemblyConfigurationAttribute("")];
-[assembly:AssemblyCompanyAttribute("Apple Inc.")];
-[assembly:AssemblyProductAttribute("")];
-[assembly:AssemblyCopyrightAttribute("Apple Inc.")];
-[assembly:AssemblyTrademarkAttribute("")];
-[assembly:AssemblyCultureAttribute("")];               
-
-//
-// Version information for an assembly consists of the following four values:
-//
-//      Major Version
-//      Minor Version 
-//      Build Number
-//      Revision
-//
-// You can specify all the value or you can default the Revision and Build Numbers 
-// by using the '*' as shown below:
-
-[assembly:AssemblyVersionAttribute(MASTER_PROD_VERS_STR2)];
-
-//
-// In order to sign your assembly you must specify a key to use. Refer to the
-// Microsoft .NET Framework documentation for more information on assembly
-// signing.
-//
-// Use the attributes below to control which key is used for signing.
-//
-// Notes:
-//   (*) If no key is specified, the assembly is not signed.
-//   (*) KeyName refers to a key that has been installed in the Crypto Service
-//       Provider (CSP) on your machine. KeyFile refers to a file which contains
-//       a key.
-//   (*) If the KeyFile and the KeyName values are both specified, the
-//       following processing occurs:
-//       (1) If the KeyName can be found in the CSP, that key is used.
-//       (2) If the KeyName does not exist and the KeyFile does exist, the key
-//           in the KeyFile is installed into the CSP and used.
-//   (*) In order to create a KeyFile, you can use the sn.exe (Strong Name)
-//       utility
-//        When specifying the KeyFile, the location of the KeyFile should be
-//        relative to the project directory.
-//   (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
-//       documentation for more information on this.
-//
-[assembly:AssemblyDelaySignAttribute(false)];
-[assembly:AssemblyKeyFileAttribute("dnssd_NET.snk")];
-[assembly:AssemblyKeyNameAttribute("")];
-
-[assembly:ComVisible(false)];
-[assembly:CLSCompliantAttribute(true)];
-[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
diff --git a/mDNSWindows/DLL.NET/PString.h b/mDNSWindows/DLL.NET/PString.h
deleted file mode 100755 (executable)
index 0249c05..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-    
-#pragma once
-
-using namespace System;
-using namespace System::Text;
-
-namespace Apple
-{
-       __gc class PString
-       {
-       public:
-
-               PString(String* string)
-               {
-                       if (string != NULL)
-                       {
-                               Byte unicodeBytes[] = Encoding::Unicode->GetBytes(string);
-                               Byte utf8Bytes[] = Encoding::Convert(Encoding::Unicode, Encoding::UTF8, unicodeBytes);
-                               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);
-                               hBytes[utf8Bytes->Length] = '\0';
-                       }
-                       else
-                       {
-                               m_p = NULL;
-                       }
-               }
-
-               ~PString()
-               {
-                       Marshal::FreeHGlobal(m_p);
-               }
-
-               const char*
-               c_str()
-               {
-                       if (m_p != NULL)
-                       {
-                               return static_cast<const char*>(m_p.ToPointer());
-                       }
-                       else
-                       {
-                               return NULL;
-                       }
-               }
-               
-       protected:
-
-               IntPtr m_p;
-       };
-}
diff --git a/mDNSWindows/DLL.NET/Stdafx.cpp b/mDNSWindows/DLL.NET/Stdafx.cpp
deleted file mode 100755 (executable)
index ef03e21..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-    
-// stdafx.cpp : source file that includes just the standard includes
-// dotNET.pch will be the pre-compiled header
-// stdafx.obj will contain the pre-compiled type information
-
-#include "stdafx.h"
diff --git a/mDNSWindows/DLL.NET/Stdafx.h b/mDNSWindows/DLL.NET/Stdafx.h
deleted file mode 100755 (executable)
index d2e5c1a..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-    
-// stdafx.h : include file for standard system include files,
-// or project specific include files that are used frequently,
-// but are changed infrequently
-
-#pragma once
-
-#if !defined(_WSPIAPI_COUNTOF)
-#      define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
-#endif
-
-#using <mscorlib.dll>
-#using <System.dll>
-
-struct _DNSServiceRef_t {};
-struct _DNSRecordRef_t {};
-
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.cpp b/mDNSWindows/DLL.NET/dnssd_NET.cpp
deleted file mode 100755 (executable)
index 3e22146..0000000
+++ /dev/null
@@ -1,1234 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-    
-// This is the main DLL file.
-
-#include "stdafx.h"
-
-#include "dnssd_NET.h"
-#include "DebugServices.h"
-#include "PString.h"
-
-
-using namespace System::Net::Sockets;
-using namespace System::Diagnostics;
-using namespace Apple;
-using namespace Apple::DNSSD;
-
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#define        DEBUG_NAME      "[dnssd.NET] "
-
-//
-// ConvertToString
-//
-static String*
-ConvertToString(const char * utf8String)
-{
-       return __gc new String(utf8String, 0, strlen(utf8String), __gc new UTF8Encoding(true, true));
-}
-
-
-//
-// class ServiceRef
-//
-// ServiceRef serves as the base class for all DNSService operations.
-//
-// It manages the DNSServiceRef, and implements processing the
-// result
-//
-ServiceRef::ServiceRef(Object * callback)
-:
-       m_bDisposed(false),
-       m_callback(callback),
-       m_thread(NULL)
-{
-       m_impl = new ServiceRefImpl(this);
-}
-
-
-ServiceRef::~ServiceRef()
-{
-}
-
-
-//
-// StartThread
-//
-// Starts the main processing thread
-//
-void
-ServiceRef::StartThread()
-{
-       check( m_impl != NULL );
-
-       m_impl->SetupEvents();
-
-       m_thread                =       new Thread(new ThreadStart(this, &Apple::DNSSD::ServiceRef::ProcessingThread));
-       m_thread->Name  =       S"DNSService Thread";
-       m_thread->IsBackground = true;
-       
-       m_thread->Start();
-}
-
-
-//
-// ProcessingThread
-//
-// The Thread class can only invoke methods in MC++ types.  So we
-// make a ProcessingThread method that forwards to the impl
-//
-void
-ServiceRef::ProcessingThread()
-{
-       m_impl->ProcessingThread();
-}
-
-
-//
-// Dispose
-//
-// Calls impl-Dispose().  This ultimately will call DNSServiceRefDeallocate()
-//
-void
-ServiceRef::Dispose()
-{
-       check(m_impl != NULL);
-       check(m_bDisposed == false);
-
-       if (!m_bDisposed)
-       {
-               m_bDisposed = true;
-
-               //
-               // Call Dispose.  This won't call DNSServiceRefDeallocate()
-               // necessarily. It depends on what thread this is being
-               // called in.
-               //
-               m_impl->Dispose();
-               m_impl = NULL;
-
-               m_thread = NULL;
-
-               GC::SuppressFinalize(this);  
-       }
-}
-
-
-//
-// EnumerateDomainsDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::EnumerateDomainsDispatch
-                                               (
-                                               ServiceFlags    flags,
-                                               int                             interfaceIndex,
-                                               ErrorCode               errorCode,
-                                               String          *       replyDomain
-                                               )
-{
-       if ((m_callback != NULL) && (m_impl != NULL))
-       {
-               DNSService::EnumerateDomainsReply * OnEnumerateDomainsReply = static_cast<DNSService::EnumerateDomainsReply*>(m_callback);
-               OnEnumerateDomainsReply(this, flags, interfaceIndex, errorCode, replyDomain);
-       }
-}
-
-
-//
-// RegisterDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::RegisterDispatch
-                               (
-                               ServiceFlags    flags,
-                               ErrorCode               errorCode,
-                               String          *       name,
-                               String          *       regtype,
-                               String          *       domain
-                               )
-{
-       if ((m_callback != NULL) && (m_impl != NULL))
-       {
-               DNSService::RegisterReply * OnRegisterReply = static_cast<DNSService::RegisterReply*>(m_callback);
-               OnRegisterReply(this, flags, errorCode, name, regtype, domain);
-       }
-}
-
-
-//
-// BrowseDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::BrowseDispatch
-                       (
-                       ServiceFlags    flags,
-                       int                             interfaceIndex,
-                       ErrorCode               errorCode,
-                       String          *       serviceName,
-                       String          *       regtype,
-                       String          *       replyDomain
-                       )
-{
-       if ((m_callback != NULL) && (m_impl != NULL))
-       {
-               DNSService::BrowseReply * OnBrowseReply = static_cast<DNSService::BrowseReply*>(m_callback);
-               OnBrowseReply(this, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain);
-       }
-}
-
-
-//
-// ResolveDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::ResolveDispatch
-                       (
-                       ServiceFlags    flags,
-                       int                             interfaceIndex,
-                       ErrorCode               errorCode,
-                       String          *       fullname,
-                       String          *       hosttarget,
-                       int                             port,
-                       Byte                    txtRecord[]
-                       )
-{
-       if ((m_callback != NULL) && (m_impl != NULL))
-       {
-               DNSService::ResolveReply * OnResolveReply = static_cast<DNSService::ResolveReply*>(m_callback);
-               OnResolveReply(this, flags, interfaceIndex, errorCode, fullname, hosttarget, port, txtRecord);
-       }
-}
-
-
-//
-// RegisterRecordDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::RegisterRecordDispatch
-                               (
-                               ServiceFlags    flags,
-                               ErrorCode               errorCode,
-                               RecordRef       *       record
-                               )
-{
-       if ((m_callback != NULL) && (m_impl != NULL))
-       {
-               DNSService::RegisterRecordReply * OnRegisterRecordReply = static_cast<DNSService::RegisterRecordReply*>(m_callback);
-               OnRegisterRecordReply(this, flags, errorCode, record);
-       }
-}
-
-
-//
-// QueryRecordDispatch
-//
-// Dispatch a reply to the delegate.
-//
-void
-ServiceRef::QueryRecordDispatch
-                                       (
-                                       ServiceFlags    flags,
-                                       int                             interfaceIndex,
-                                       ErrorCode               errorCode,
-                                       String          *       fullname,
-                                       int                             rrtype,
-                                       int                             rrclass,
-                                       Byte                    rdata[],
-                                       int                             ttl
-                                       )
-{
-       if ((m_callback != NULL) && (m_impl != NULL))
-       {
-               DNSService::QueryRecordReply * OnQueryRecordReply = static_cast<DNSService::QueryRecordReply*>(m_callback);
-               OnQueryRecordReply(this, flags, interfaceIndex, errorCode, fullname, rrtype, rrclass, rdata, ttl);
-       }
-}
-
-
-//
-// ServiceRefImpl::ServiceRefImpl()
-//
-// Constructs a new ServiceRefImpl.  We save the pointer to our enclosing
-// class in a gcroot handle.  This satisfies the garbage collector as
-// the outer class is a managed type
-//
-ServiceRef::ServiceRefImpl::ServiceRefImpl(ServiceRef * outer)
-:
-       m_socketEvent(NULL),
-       m_stopEvent(NULL),
-       m_disposed(false),
-       m_outer(outer),
-       m_ref(NULL)
-{
-       m_threadId = GetCurrentThreadId();
-}
-
-
-//
-// ServiceRefImpl::~ServiceRefImpl()
-//
-// Deallocate all resources associated with the ServiceRefImpl
-//
-ServiceRef::ServiceRefImpl::~ServiceRefImpl()
-{
-       if (m_socketEvent != NULL)
-       {
-               CloseHandle(m_socketEvent);
-               m_socketEvent = NULL;
-       }
-
-       if (m_stopEvent != NULL)
-       {
-               CloseHandle(m_stopEvent);
-               m_stopEvent = NULL;
-       }
-
-       if (m_ref != NULL)
-       {
-               DNSServiceRefDeallocate(m_ref);
-               m_ref = NULL;
-       }
-}
-
-
-//
-// ServiceRefImpl::SetupEvents()
-//
-// Setup the events necessary to manage multi-threaded dispatch
-// of DNSService Events
-//
-void
-ServiceRef::ServiceRefImpl::SetupEvents()
-{
-       check(m_ref != NULL);
-
-       m_socket                =       (SOCKET) DNSServiceRefSockFD(m_ref);
-       check(m_socket != INVALID_SOCKET);
-
-       m_socketEvent   =       CreateEvent(NULL, 0, 0, NULL);
-
-       if (m_socketEvent == NULL)
-       {
-               throw new DNSServiceException(Unknown);
-       }
-
-       int err = WSAEventSelect(m_socket, m_socketEvent, FD_READ|FD_CLOSE);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(Unknown);
-       }
-
-       m_stopEvent = CreateEvent(NULL, 0, 0, NULL);
-
-       if (m_stopEvent == NULL)
-       {
-               throw new DNSServiceException(Unknown);
-       }
-}
-
-
-//
-// ServiceRefImpl::ProcessingThread()
-//
-// Wait for socket events on the DNSServiceRefSockFD().  Also wait
-// for stop events
-//
-void
-ServiceRef::ServiceRefImpl::ProcessingThread()
-{
-       check( m_socketEvent != NULL );
-       check( m_stopEvent != NULL );
-       check( m_ref != NULL );
-       
-       HANDLE handles[2];
-
-       handles[0] = m_socketEvent;
-       handles[1] = m_stopEvent;
-
-       while (m_disposed == false)
-       {
-               int ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
-
-               //
-               // it's a socket event
-               //
-               if (ret == WAIT_OBJECT_0)
-               {
-                       DNSServiceProcessResult(m_ref);
-               }
-               //
-               // else it's a stop event
-               //
-               else if (ret == WAIT_OBJECT_0 + 1)
-               {
-                       break;
-               }
-               else
-               {
-                       //
-                       // unexpected wait result
-                       //
-                       dlog( kDebugLevelWarning, DEBUG_NAME "%s: unexpected wait result (result=0x%08X)\n", __ROUTINE__, ret );
-               }
-       }
-
-       delete this;
-}
-
-
-//
-// ServiceRefImpl::Dispose()
-//
-// Calls DNSServiceRefDeallocate()
-//
-void
-ServiceRef::ServiceRefImpl::Dispose()
-{
-       OSStatus        err;
-       BOOL            ok;
-
-       check(m_disposed == false);
-
-       m_disposed = true;
-
-       ok = SetEvent(m_stopEvent);
-       err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-exit:
-
-       return;
-}
-
-
-//
-// ServiceRefImpl::EnumerateDomainsCallback()
-//
-// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::EnumerateDomainsCallback
-                                                                                       (
-                                                                                       DNSServiceRef                   sdRef,
-                                                                                       DNSServiceFlags                 flags,
-                                                                                       uint32_t                                interfaceIndex,
-                                                                                       DNSServiceErrorType             errorCode,
-                                                                                       const char                      *       replyDomain,
-                                                                                       void                            *       context
-                                                                                       )
-{
-       ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
-       check( self != NULL );
-       check( self->m_outer != NULL );
-
-       if (self->m_disposed == false)
-       {
-               self->m_outer->EnumerateDomainsDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(replyDomain));
-       }
-}
-
-
-//
-// ServiceRefImpl::RegisterCallback()
-//
-// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::RegisterCallback
-                                                       (
-                                                       DNSServiceRef                   sdRef,
-                                                       DNSServiceFlags                 flags,
-                                                       DNSServiceErrorType             errorCode,
-                                                       const char                      *       name,
-                                                       const char                      *       regtype,
-                                                       const char                      *       domain,
-                                                       void                            *       context
-                                                       )
-{
-       ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
-       check( self != NULL );
-       check( self->m_outer != NULL );
-       
-       if (self->m_disposed == false)
-       {
-               self->m_outer->RegisterDispatch((ServiceFlags) flags, (ErrorCode) errorCode, ConvertToString(name), ConvertToString(regtype), ConvertToString(domain));
-       }
-}
-
-
-//
-// ServiceRefImpl::BrowseCallback()
-//
-// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::BrowseCallback
-                                                       (
-                                                       DNSServiceRef                   sdRef,
-                                                       DNSServiceFlags                 flags,
-                                                       uint32_t                                interfaceIndex,
-                                                       DNSServiceErrorType             errorCode,
-                                                       const char                      *       serviceName,
-                                                       const char                      *       regtype,
-                                                       const char                      *       replyDomain,
-                                                       void                            *       context
-                                                       )
-{
-       ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
-       check( self != NULL );
-       check( self->m_outer != NULL );
-       
-       if (self->m_disposed == false)
-       {
-               self->m_outer->BrowseDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(serviceName), ConvertToString(regtype), ConvertToString(replyDomain));
-       }
-}
-
-
-//
-// ServiceRefImpl::ResolveCallback()
-//
-// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::ResolveCallback
-                                                       (
-                                                       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
-                                                       )
-{
-       ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
-       check( self != NULL );
-       check( self->m_outer != NULL );
-       
-       if (self->m_disposed == false)
-       {
-               Byte txtRecordBytes[];
-
-               txtRecordBytes = NULL;
-
-               if (txtLen > 0)
-               {
-                       //
-                       // copy raw memory into managed byte array
-                       //
-                       txtRecordBytes          =       new Byte[txtLen];
-                       Byte __pin      *       p       =       &txtRecordBytes[0];
-                       memcpy(p, txtRecord, txtLen);
-               }
-
-               self->m_outer->ResolveDispatch((ServiceFlags) flags, interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), ConvertToString(hosttarget), ntohs(notAnIntPort), txtRecordBytes);
-       }       
-}
-
-
-//
-// ServiceRefImpl::RegisterRecordCallback()
-//
-// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::RegisterRecordCallback
-                                                               (
-                                                               DNSServiceRef           sdRef,
-                                                               DNSRecordRef            rrRef,
-                                                               DNSServiceFlags         flags,
-                                                               DNSServiceErrorType     errorCode,
-                                                               void                    *       context
-                                                               )
-{
-       ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
-       check( self != NULL );
-       check( self->m_outer != NULL );
-       
-       if (self->m_disposed == false)
-       {
-               RecordRef * record = NULL;
-
-               if (errorCode == 0)
-               {
-                       record = new RecordRef;
-
-                       record->m_impl->m_ref = rrRef;
-               }
-
-               self->m_outer->RegisterRecordDispatch((ServiceFlags) flags, (ErrorCode) errorCode, record);
-       }
-}
-
-
-//
-// ServiceRefImpl::QueryRecordCallback()
-//
-// This is the callback from dnssd.dll.  We pass this up to our outer, managed type
-//
-void DNSSD_API
-ServiceRef::ServiceRefImpl::QueryRecordCallback
-                                                               (
-                                                               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
-                                                               )
-{
-       ServiceRef::ServiceRefImpl * self = static_cast<ServiceRef::ServiceRefImpl*>(context);
-
-       check( self != NULL );
-       check( self->m_outer != NULL );
-       
-       if (self->m_disposed == false)
-       {
-               Byte rdataBytes[];
-
-               if (rdlen)
-               {
-                       rdataBytes                      =       new Byte[rdlen];
-                       Byte __pin * p          =       &rdataBytes[0];
-                       memcpy(p, rdata, rdlen);
-               }
-
-               self->m_outer->QueryRecordDispatch((ServiceFlags) flags, (int) interfaceIndex, (ErrorCode) errorCode, ConvertToString(fullname), rrtype, rrclass, rdataBytes, ttl);
-       }
-}
-
-
-/*
- * EnumerateDomains()
- *
- * This maps to DNSServiceEnumerateDomains().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::EnumerateDomains
-               (
-               int                                                     flags,
-               int                                                     interfaceIndex,
-               EnumerateDomainsReply   *       callback
-               )
-{
-       ServiceRef * sdRef = new ServiceRef(callback);
-       int                      err;
-
-       err = DNSServiceEnumerateDomains(&sdRef->m_impl->m_ref, flags, interfaceIndex, ServiceRef::ServiceRefImpl::EnumerateDomainsCallback, sdRef->m_impl);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       sdRef->StartThread();
-
-       return sdRef;
-}
-
-
-/*
- * Register()
- *
- * This maps to DNSServiceRegister().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::Register
-                               (
-                               int                                     flags,
-                               int                                     interfaceIndex,
-                               String                  *       name,
-                               String                  *       regtype,
-                               String                  *       domain,
-                               String                  *       host,
-                               int                                     port,
-                               Byte                            txtRecord[],
-                               RegisterReply   *       callback
-                               )
-{
-       ServiceRef      *       sdRef   =       new ServiceRef(callback);
-       PString         *       pName   =       new PString(name);
-       PString         *       pType   =       new PString(regtype);
-       PString         *       pDomain =       new PString(domain);
-       PString         *       pHost   =       new PString(host);
-       int                             len             =       0;
-       Byte __pin      *       p               =       NULL;
-       void            *       v               =       NULL;
-
-       if ((txtRecord != NULL) && (txtRecord->Length > 0))
-       {
-               len             = txtRecord->Length;
-               p               = &txtRecord[0];
-               v               = (void*) p;
-       }
-
-       int err = DNSServiceRegister(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(), pHost->c_str(), htons(port), len, v, ServiceRef::ServiceRefImpl::RegisterCallback, sdRef->m_impl );
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       sdRef->StartThread();
-
-       return sdRef;
-}
-
-
-/*
- * AddRecord()
- *
- * This maps to DNSServiceAddRecord().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-RecordRef*
-DNSService::AddRecord
-                               (
-                               ServiceRef      *       sdRef,
-                               int                             flags,
-                               int                             rrtype,
-                               Byte                    rdata[],
-                               int                             ttl
-                               )
-{
-       int                             len             =       0;
-       Byte __pin      *       p               =       NULL;
-       void            *       v               =       NULL;
-
-       if ((rdata != NULL) && (rdata->Length > 0))
-       {
-               len = rdata->Length;
-               p       = &rdata[0];
-               v       = (void*) p;
-       }
-
-       RecordRef * record = new RecordRef;
-
-       int err = DNSServiceAddRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, rrtype, len, v, ttl);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       return record;
-}
-
-
-/*
- * UpdateRecord()
- *
- * This maps to DNSServiceUpdateRecord().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-void
-DNSService::UpdateRecord
-                               (
-                               ServiceRef      *       sdRef,
-                               RecordRef       *       record,
-                               int                             flags,
-                               Byte                    rdata[],
-                               int                             ttl
-                               )
-{
-       int                             len             =       0;
-       Byte __pin      *       p               =       NULL;
-       void            *       v               =       NULL;
-
-       if ((rdata != NULL) && (rdata->Length > 0))
-       {
-               len     = rdata->Length;
-               p       = &rdata[0];
-               v       = (void*) p;
-       }
-
-       int err = DNSServiceUpdateRecord(sdRef->m_impl->m_ref, record ? record->m_impl->m_ref : NULL, flags, len, v, ttl);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-}
-
-
-/*
- * RemoveRecord()
- *
- * This maps to DNSServiceRemoveRecord().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-void
-DNSService::RemoveRecord
-               (
-               ServiceRef      *       sdRef,
-               RecordRef       *       record,
-               int                             flags
-               )
-{
-       int err = DNSServiceRemoveRecord(sdRef->m_impl->m_ref, record->m_impl->m_ref, flags);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-}      
-
-
-/*
- * Browse()
- *
- * This maps to DNSServiceBrowse().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::Browse
-       (
-       int                             flags,
-       int                             interfaceIndex,
-       String          *       regtype,
-       String          *       domain,
-       BrowseReply     *       callback
-       )
-{
-       ServiceRef      *       sdRef   = new ServiceRef(callback);
-       PString         *       pType   = new PString(regtype);
-       PString         *       pDomain = new PString(domain);
-
-       int err = DNSServiceBrowse(&sdRef->m_impl->m_ref, flags, interfaceIndex, pType->c_str(), pDomain->c_str(),(DNSServiceBrowseReply) ServiceRef::ServiceRefImpl::BrowseCallback, sdRef->m_impl);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       sdRef->StartThread();
-
-       return sdRef;
-}
-
-
-/*
- * Resolve()
- *
- * This maps to DNSServiceResolve().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::Resolve
-       (
-       int                                     flags,
-       int                                     interfaceIndex,
-       String                  *       name,
-       String                  *       regtype,
-       String                  *       domain,
-       ResolveReply    *       callback        
-       )
-{
-       ServiceRef      *       sdRef   = new ServiceRef(callback);
-       PString         *       pName   = new PString(name);
-       PString         *       pType   = new PString(regtype);
-       PString         *       pDomain = new PString(domain);
-
-       int err = DNSServiceResolve(&sdRef->m_impl->m_ref, flags, interfaceIndex, pName->c_str(), pType->c_str(), pDomain->c_str(),(DNSServiceResolveReply) ServiceRef::ServiceRefImpl::ResolveCallback, sdRef->m_impl);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       sdRef->StartThread();
-
-       return sdRef;
-}
-
-
-/*
- * CreateConnection()
- *
- * This maps to DNSServiceCreateConnection().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::CreateConnection
-                       (
-                       RegisterRecordReply * callback
-                       )
-{
-       ServiceRef * sdRef = new ServiceRef(callback);
-
-       int err = DNSServiceCreateConnection(&sdRef->m_impl->m_ref);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       sdRef->StartThread();
-
-       return sdRef;
-}
-
-
-/*
- * RegisterRecord()
- *
- * This maps to DNSServiceRegisterRecord().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-
-RecordRef*
-DNSService::RegisterRecord
-                       (
-                       ServiceRef                      *       sdRef,
-                       ServiceFlags                    flags,
-                       int                                             interfaceIndex,
-                       String                          *       fullname,
-                       int                                             rrtype,
-                       int                                             rrclass,
-                       Byte                                    rdata[],
-                       int                                             ttl
-                       )
-{
-       RecordRef       *       record  = new RecordRef;
-       int                             len             = 0;
-       Byte __pin      *       p               = NULL;
-       void            *       v               = NULL;
-
-       PString * pFullname = new PString(fullname);
-
-       if ((rdata != NULL) && (rdata->Length > 0))
-       {
-               len             = rdata->Length;
-               p               = &rdata[0];
-               v               = (void*) p;
-       }
-
-       int err = DNSServiceRegisterRecord(sdRef->m_impl->m_ref, &record->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v, ttl, (DNSServiceRegisterRecordReply) ServiceRef::ServiceRefImpl::RegisterRecordCallback, sdRef->m_impl);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       return record;
-}
-
-/*
- * QueryRecord()
- *
- * This maps to DNSServiceQueryRecord().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-ServiceRef*
-DNSService::QueryRecord
-               (
-               ServiceFlags                    flags,
-               int                                             interfaceIndex,
-               String                          *       fullname,
-               int                                             rrtype,
-               int                                             rrclass,
-               QueryRecordReply        *       callback
-               )
-{
-       ServiceRef      *       sdRef           = new ServiceRef(callback);
-       PString         *       pFullname       = new PString(fullname);
-
-       int err = DNSServiceQueryRecord(&sdRef->m_impl->m_ref, flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, (DNSServiceQueryRecordReply) ServiceRef::ServiceRefImpl::QueryRecordCallback, sdRef->m_impl);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       sdRef->StartThread();
-
-       return sdRef;
-}
-
-
-/*
- * ReconfirmRecord()
- *
- * This maps to DNSServiceReconfirmRecord().  Returns an
- * initialized ServiceRef on success, throws an exception
- * on failure.
- */
-void
-DNSService::ReconfirmRecord
-               (
-               ServiceFlags    flags,
-               int                             interfaceIndex,
-               String          *       fullname,
-               int                             rrtype,
-               int                             rrclass,
-               Byte                    rdata[]
-               )
-{
-       int                             len     = 0;
-       Byte __pin      *       p       = NULL;
-       void            *       v       = NULL;
-
-       PString * pFullname = new PString(fullname);
-
-       if ((rdata != NULL) && (rdata->Length > 0))
-       {
-               len     = rdata->Length;
-               p       = &rdata[0];
-               v       = (void*) p;
-       }
-
-       DNSServiceReconfirmRecord(flags, interfaceIndex, pFullname->c_str(), rrtype, rrclass, len, v);
-}
-
-
-void
-TextRecord::SetValue
-               (
-               String  *       key,
-               Byte            value[]            /* may be NULL */
-               )
-{
-       PString                 *       pKey = new PString(key);
-       int                                     len             =       0;
-       Byte __pin              *       p               =       NULL;
-       void                    *       v               =       NULL;
-       DNSServiceErrorType     err;
-
-       if (value && (value->Length > 0))
-       {
-               len     =       value->Length;
-               p       =       &value[0];
-               v       =       (void*) p;
-       }
-
-       err = TXTRecordSetValue(&m_impl->m_ref, pKey->c_str(), len, v);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-}
-
-
-void
-TextRecord::RemoveValue
-               (
-               String  *       key
-               )
-{
-       PString                 *       pKey = new PString(key);
-       DNSServiceErrorType     err;
-
-       err = TXTRecordRemoveValue(&m_impl->m_ref, pKey->c_str());
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-}
-
-
-int
-TextRecord::GetLength
-               (
-               )
-{
-       return TXTRecordGetLength(&m_impl->m_ref);
-}
-
-
-Byte
-TextRecord::GetBytes
-               (
-               ) __gc[]
-{
-       const void      *       noGCBytes = NULL;
-       Byte                    gcBytes[] = NULL;               
-
-       noGCBytes               =       TXTRecordGetBytesPtr(&m_impl->m_ref);
-       int                     len     =       GetLength();
-
-       if (noGCBytes && len)
-       {
-               gcBytes                         =       new Byte[len];
-               Byte __pin      *       p       =       &gcBytes[0];
-               memcpy(p, noGCBytes, len);
-       }
-
-       return gcBytes;
-}
-
-
-bool
-TextRecord::ContainsKey
-               (
-               Byte            txtRecord[],
-               String  *       key
-               )
-{
-       PString         *       pKey    = new PString(key);
-       Byte __pin      *       p               = &txtRecord[0];
-       
-       return (TXTRecordContainsKey(txtRecord->Length, p, pKey->c_str()) > 0) ? true : false;
-}
-
-
-Byte
-TextRecord::GetValueBytes
-               (
-               Byte            txtRecord[],
-               String  *       key
-               ) __gc[]
-{
-       uint8_t                 valueLen;
-       Byte                    ret[]   = NULL;
-       PString         *       pKey    = new PString(key);
-       Byte __pin      *       p1              = &txtRecord[0];
-       const void      *       v;
-
-       v = TXTRecordGetValuePtr(txtRecord->Length, p1, pKey->c_str(), &valueLen);
-
-       if (v != NULL)
-       {
-               ret                                     = new Byte[valueLen];
-               Byte __pin      *       p2      = &ret[0];
-
-               memcpy(p2, v, valueLen);
-       }
-
-       return ret;
-}
-
-
-int
-TextRecord::GetCount
-               (
-               Byte txtRecord[]
-               )
-{
-       Byte __pin      *       p       = &txtRecord[0];
-
-       return TXTRecordGetCount(txtRecord->Length, p);
-}
-
-
-Byte
-TextRecord::GetItemAtIndex
-               (
-               Byte                            txtRecord[],
-               int                                     index,
-               [Out] String    **      key
-               ) __gc[]
-{
-       char                            keyBuf[255];
-       uint8_t                         keyBufLen = 255;
-       uint8_t                         valueLen;
-       void                    *       value;
-       Byte                            ret[]   = NULL;
-       DNSServiceErrorType     err;
-       Byte __pin              *       p1              = &txtRecord[0];
-       
-
-       err = TXTRecordGetItemAtIndex(txtRecord->Length, p1, index, keyBufLen, keyBuf, &valueLen, (const void**) &value);
-
-       if (err != 0)
-       {
-               throw new DNSServiceException(err);
-       }
-
-       *key = ConvertToString(keyBuf);
-
-       if (valueLen)
-       {
-               ret                                     = new Byte[valueLen];
-               Byte __pin      *       p2      = &ret[0];
-
-               memcpy(p2, value, valueLen);
-       }
-
-       return ret;
-}
-
-
-//
-// DNSServiceException::DNSServiceException()
-//
-// Constructs an exception with an error code
-//
-DNSServiceException::DNSServiceException
-                               (
-                               int _err
-                               )
-:
-       err(_err)
-{
-}
-
-
-//
-// This version of the constructor is useful for instances in which
-// an inner exception is thrown, caught, and then a new exception
-// is thrown in it's place
-//
-DNSServiceException::DNSServiceException
-                               (       
-                               String                          *       message,
-                               System::Exception       *       innerException
-                               )
-{
-}
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.h b/mDNSWindows/DLL.NET/dnssd_NET.h
deleted file mode 100755 (executable)
index 3e0196d..0000000
+++ /dev/null
@@ -1,1392 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
-
- * 
- * NOTE:
- * 
- * These .Net APIs are a work in progress, currently being discussed and refined.
- * If you plan to build an application based on these APIs, you may wish to
- * statically link this code into your application, or otherwise distribute
- * the DLL so that it installs into the same folder as your application
- * (not into any common system area where it might interfere with other
- * applications using a future completed version of these APIs).
- * If you plan to do this, please be sure to inform us by sending email
- * to bonjour@apple.com to let us know.
- * You may want to discuss what you're doing on the Bonjour mailing
- * list to see if others in similar positions have any suggestions for you:
- * 
- * <http://lists.apple.com/bonjour-dev/>
- * 
- */
-    
-#pragma once
-
-#include <dns_sd.h>
-#include <vcclr.h>
-#include <memory>
-#include <winsock2.h>
-
-using namespace System;
-using namespace System::Net;
-using namespace System::Runtime::InteropServices;
-using namespace System::Threading;
-using namespace System::Collections;
-
-
-namespace Apple
-{
-       namespace DNSSD
-       {
-               public __gc class ServiceRef;
-
-               public __value enum ServiceFlags : int
-               {
-                       MoreComing                      =       1,
-                       /* 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 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
-                               * in the future they will be delivered as usual.
-                               */
-
-                       Add                                     =       2,
-                       Default                         =       4,
-                       /* 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"
-                               * flag NOT set indicates a "Remove", i.e. the domain is no longer
-                               * valid.
-                               */
-
-                       NoAutoRename            =       8,
-                       /* 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
-                               * is only valid if a name is explicitly specified when registering a service
-                               * (i.e. the default name is not used.)
-                               */
-
-                       Shared                          =       16,
-                       Unique                          =       32,
-                       /* 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
-                               * record's name is to be unique on the network (e.g. SRV records).
-                               */
-
-                       BrowseDomains           =       64,
-                       RegistrationDomains     =       128,
-                       /* Flags for specifying domain enumeration type in DNSServiceEnumerateDomain
-       s.
-                               * BrowseDomains enumerates domains recommended for browsing, RegistrationDo
-       mains
-                               * enumerates domains recommended for registration.
-                               */
-               };
-
-
-               public __value enum ErrorCode : int
-               {
-                       NoError                         =       0,
-                       Unknown                         =       -65537,
-                       NoSuchName                      =       -65538,
-                       NoMemory                        =       -65539,
-                       BadParam                        =       -65540,
-                       BadReference            =       -65541,
-                       BadState                        =       -65542,
-                       BadFlags                        =       -65543,
-                       Unsupported                     =       -65544,
-                       AlreadyRegistered       =       -65547,
-                       NameConflict            =       -65548,
-                       Invalid                         =       -65549,
-                       Incompatible            =       -65551,
-                       BadinterfaceIndex       =       -65552
-
-                       /*
-                               * mDNS Error codes are in the range
-                               * FFFE FF00 (-65792) to FFFE FFFF (-65537)
-                               */
-               };
-
-               public __gc class DNSServiceException
-               :
-                       public Exception
-               {
-               public:
-
-                       DNSServiceException
-                               (
-                               int err
-                               );
-
-                       DNSServiceException
-                               (       
-                               String                          *       message,
-                               System::Exception       *       innerException
-                               );
-
-                       int err;
-               };
-
-
-               /*
-               * class RecordRef
-               *
-               * This is a thin MC++ class facade on top of a DNSRecordRef
-               */
-               public __gc class RecordRef
-               {
-               public:
-
-                       RecordRef()
-                       {
-                               m_impl = new RecordRefImpl;
-                               m_impl->m_ref = NULL;
-                       }
-
-                       ~RecordRef()
-                       {
-                               delete m_impl;
-                       }
-
-                       __nogc class RecordRefImpl
-                       {
-                       public:
-
-                               DNSRecordRef m_ref;
-                       };
-
-                       RecordRefImpl * m_impl;
-               };                      
-
-
-               /*
-               * class ServiceRef
-               *
-               * This is a thin MC++ class facade on top of a DNSServiceRef
-               */
-               public __gc class ServiceRef : public IDisposable
-               {
-               public:
-
-                       ServiceRef(Object * callback);
-
-                       ~ServiceRef();
-
-                       /*
-                       * This does an underlying DNSServiceRefDeallocate().  After
-                       * calling Dispose, the ServiceRef is no longer usable.
-                       */
-                       void
-                       Dispose();
-
-                       /*
-                       * Internal - Dispatch an EnumerateDomains callback
-                       */
-                       void
-                       EnumerateDomainsDispatch
-                               (
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,
-                               String          *       replyDomain
-                               );
-
-                       /*
-                       * Internal - Dispatch a Register callback
-                       */
-                       void
-                       RegisterDispatch
-                               (
-                               ServiceFlags    flags,
-                               ErrorCode               errorCode,
-                               String          *       name,
-                               String          *       regtype,
-                               String          *       domain
-                               );
-
-                       /*
-                       * Internal - Dispatch a Browse callback
-                       */
-                       void
-                       BrowseDispatch
-                               (
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,
-                               String          *       serviceName,
-                               String          *       regtype,
-                               String          *       replyDomain
-                               );
-
-                       /*
-                       * Internal - Dispatch a Resolve callback
-                       */
-                       void
-                       ResolveDispatch
-                               (
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,
-                               String          *       fullname,
-                               String          *       hosttarget,
-                               int                             port,
-                               Byte                    txtRecord[]
-                               );
-                       
-                       /*
-                       * Internal - Dispatch a RegisterRecord callback
-                       */
-                       void
-                       RegisterRecordDispatch
-                               (
-                               ServiceFlags    flags,
-                               ErrorCode               errorCode,
-                               RecordRef       *       record
-                               );
-
-                       /*
-                       * Internal - Dispatch a QueryRecord callback
-                       */
-                       void
-                       QueryRecordDispatch
-                               (
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,
-                               String          *       fullname,
-                               int                             rrtype,
-                               int                             rrclass,
-                               Byte                    rdata[],
-                               int                             ttl
-                               );
-
-                       /*
-                       * Internal - A non managed class to wrap a DNSServiceRef
-                       */
-                       __nogc class ServiceRefImpl
-                       {
-                       public:
-
-                               ServiceRefImpl
-                                       (
-                                       ServiceRef * outer
-                                       );
-
-                               ~ServiceRefImpl();
-
-                               /*
-                               * Sets up events for threaded operation
-                               */
-                               void
-                               SetupEvents();
-
-                               /*
-                               * Main processing thread
-                               */
-                               void
-                               ProcessingThread();
-
-                               /*
-                               * Calls DNSServiceRefDeallocate()
-                               */
-                               void
-                               Dispose();
-
-                               /*
-                               * Called from dnssd.dll
-                               */
-                               static void DNSSD_API
-                               EnumerateDomainsCallback
-                                       (
-                                       DNSServiceRef                   sdRef,
-                                       DNSServiceFlags                 flags,
-                                       uint32_t                                interfaceIndex,
-                                       DNSServiceErrorType             errorCode,
-                                       const char                      *       replyDomain,
-                                       void                            *       context
-                                       );
-
-                               static void DNSSD_API
-                               RegisterCallback
-                                       (
-                                       DNSServiceRef                   ref,
-                                       DNSServiceFlags                 flags,
-                                       DNSServiceErrorType             errorCode,
-                                       const char                      *       name,
-                                       const char                      *       regtype,
-                                       const char                      *       domain,
-                                       void                            *       context
-                                       );
-
-                               static void DNSSD_API
-                               BrowseCallback
-                                       (
-                                       DNSServiceRef                   sdRef,
-                                       DNSServiceFlags                 flags,
-                                       uint32_t                                interfaceIndex,
-                                       DNSServiceErrorType             errorCode,
-                                       const char                      *       serviceName,
-                                       const char                      *       regtype,
-                                       const char                      *       replyDomain,
-                                       void                            *       context
-                                       );
-
-                               static void DNSSD_API
-                               ResolveCallback
-                                       (
-                                       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
-                                       );
-
-                               static void DNSSD_API
-                               RegisterRecordCallback
-                                       ( 
-                                       DNSServiceRef           sdRef,
-                                       DNSRecordRef            RecordRef,
-                                       DNSServiceFlags         flags,
-                                       DNSServiceErrorType     errorCode,
-                                       void                    *       context
-                                       );
-
-                               static void DNSSD_API
-                               QueryRecordCallback
-                                       (
-                                       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
-                                       );
-
-                               SOCKET                          m_socket;
-                               HANDLE                          m_socketEvent;
-                               HANDLE                          m_stopEvent;
-                               DWORD                           m_threadId;
-                               bool                            m_disposed;
-                               DNSServiceRef           m_ref;
-                               gcroot<ServiceRef*> m_outer;
-                       };
-
-                       void
-                       StartThread();
-
-                       void
-                       ProcessingThread();
-
-                       bool                            m_bDisposed;
-                       Object                  *       m_callback;
-                       Thread                  *       m_thread;
-                       ServiceRefImpl  *       m_impl;
-               };
-                       
-               /*********************************************************************************************
-               *
-               *   TXT Record Construction Functions
-               *
-               *********************************************************************************************/
-
-               /*
-               * A typical calling sequence for TXT record construction is something like:
-               *
-               * DNSService.TextRecord tr = new DNSService.TextRecord(1024);
-               * tr.SetValue();
-               * tr.SetValue();
-               * tr.SetValue();
-               * ...
-               * DNSServiceRegister( ... tr.GetLength(), tr.GetBytes() ... );
-               */
-
-
-               /* TextRecord
-               *
-               * Opaque internal data type.
-               * Note: Represents a DNS-SD TXT record.
-               */
-
-
-               /* TextRecord::TextRecord()
-               *
-               * Creates a new empty TextRecord .
-               *
-               */
-
-               public __gc class TextRecord
-               {
-               public:
-
-                       TextRecord()
-                       {
-                               m_impl = new TextRecordImpl();
-                               TXTRecordCreate(&m_impl->m_ref, 0, NULL);
-                       }
-
-                       ~TextRecord()
-                       {
-                               TXTRecordDeallocate(&m_impl->m_ref);
-                               delete m_impl;
-                       }
-
-                       __nogc class TextRecordImpl
-                       {
-                       public:
-
-                               TXTRecordRef m_ref;
-                       };
-
-                       TextRecordImpl * m_impl;
-
-
-                       /* SetValue()
-                       *
-                       * Adds a key (optionally with value) to a TextRecord. If the "key" already
-                       * exists in the TextRecord, then the current value will be replaced with
-                       * the new value.
-                       * Keys may exist in four states with respect to a given TXT record:
-                       *  - Absent (key does not appear at all)
-                       *  - Present with no value ("key" appears alone)
-                       *  - Present with empty value ("key=" appears in TXT record)
-                       *  - Present with non-empty value ("key=value" appears in TXT record)
-                       * For more details refer to "Data Syntax for DNS-SD TXT Records" in
-                       * <http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt>
-                       *
-                       * key:             A null-terminated string which only contains printable ASCII
-                       *                  values (0x20-0x7E), excluding '=' (0x3D). Keys should be
-                       *                  14 characters or less (not counting the terminating null).
-                       *
-                       * value:           Any binary value. For values that represent
-                       *                  textual data, UTF-8 is STRONGLY recommended.
-                       *                  For values that represent textual data, valueSize
-                       *                  should NOT include the terminating null (if any)
-                       *                  at the end of the string.
-                       *                  If NULL, then "key" will be added with no value.
-                       *                  If non-NULL but valueSize is zero, then "key=" will be
-                       *                  added with empty value.
-                       *
-                       * exceptions:      Throws kDNSServiceErr_Invalid if the "key" string contains
-                       *                  illegal characters.
-                       *                  Throws kDNSServiceErr_NoMemory if adding this key would
-                       *                  exceed the available storage.
-                       */
-
-                       void
-                       SetValue
-                               (
-                               String  *       key,
-                               Byte            value[]  /* may be NULL */
-                               );
-
-
-                       /* RemoveValue()
-                       *
-                       * Removes a key from a TextRecord.  The "key" must be an
-                       * ASCII string which exists in the TextRecord.
-                       *
-                       * key:             A key name which exists in the TextRecord.
-                       *
-                       * exceptions:      Throws kDNSServiceErr_NoSuchKey if the "key" does not
-                       *                  exist in the TextRecord.
-                       *
-                       */
-
-                       void
-                       RemoveValue
-                               (
-                               String  *       key
-                               );
-
-
-                       /* GetLength()
-                       *
-                       * Allows you to determine the length of the raw bytes within a TextRecord.
-                       *
-                       * return value :     Returns the size of the raw bytes inside a TextRecord
-                       *                  which you can pass directly to DNSServiceRegister() or
-                       *                  to DNSServiceUpdateRecord().
-                       *                  Returns 0 if the TextRecord is empty.
-                       *
-                       */
-
-                       int
-                       GetLength
-                               (
-                               );
-
-
-                       /* GetBytes()
-                       *
-                       * Allows you to retrieve a pointer to the raw bytes within a TextRecord.
-                       *
-                       * return value:    Returns a pointer to the bytes inside the TextRecord
-                       *                  which you can pass directly to DNSServiceRegister() or
-                       *                  to DNSServiceUpdateRecord().
-                       *
-                       */
-
-                       Byte
-                       GetBytes
-                               (
-                               ) __gc[];
-
-
-                       /*********************************************************************************************
-                       *
-                       *   TXT Record Parsing Functions
-                       *
-                       *********************************************************************************************/
-
-                       /*
-                       * A typical calling sequence for TXT record parsing is something like:
-                       *
-                       * Receive TXT record data in DNSServiceResolve() callback
-                       * if (TXTRecordContainsKey(txtLen, txtRecord, "key")) then do something
-                       * val1ptr = DNSService.TextService.GetValue(txtRecord, "key1", &len1);
-                       * val2ptr = DNSService.TextService.GetValue(txtRecord, "key2", &len2);
-                       * ...
-                       * return;
-                       *
-                       */
-
-                       /* ContainsKey()
-                       *
-                       * Allows you to determine if a given TXT Record contains a specified key.
-                       *
-                       * txtRecord:       Pointer to the received TXT Record bytes.
-                       *
-                       * key:             A null-terminated ASCII string containing the key name.
-                       *
-                       * return value:    Returns 1 if the TXT Record contains the specified key.
-                       *                  Otherwise, it returns 0.
-                       *
-                       */
-
-                       static public bool
-                       ContainsKey
-                               (
-                               Byte            txtRecord[],
-                               String  *       key
-                               );
-
-
-                       /* GetValueBytes()
-                       *
-                       * Allows you to retrieve the value for a given key from a TXT Record.
-                       *
-                       * txtRecord:       Pointer to the received TXT Record bytes.
-                       *
-                       * key:             A null-terminated ASCII string containing the key name.
-                       *
-                       * return value:    Returns NULL if the key does not exist in this TXT record,
-                       *                  or exists with no value (to differentiate between
-                       *                  these two cases use ContainsKey()).
-                       *                  Returns byte array 
-                       *                  if the key exists with empty or non-empty value.
-                       *                  For empty value, length of byte array will be zero.
-                       *                  For non-empty value, it will be the length of value data.
-                       */
-
-                       static public Byte
-                       GetValueBytes
-                               (
-                               Byte            txtRecord[],
-                               String  *       key
-                               ) __gc[];
-
-
-                       /* GetCount()
-                       *
-                       * Returns the number of keys stored in the TXT Record.  The count
-                       * can be used with TXTRecordGetItemAtIndex() to iterate through the keys.
-                       *
-                       * txtRecord:       Pointer to the received TXT Record bytes.
-                       *
-                       * return value:    Returns the total number of keys in the TXT Record.
-                       *
-                       */
-
-                       static public int
-                       GetCount
-                               (
-                               Byte    txtRecord[]
-                               );
-
-
-                       /* GetItemAtIndex()
-                       *
-                       * 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.
-                       * 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.
-                       *
-                       * On return:
-                       * For keys with no value, *value is set to NULL and *valueLen is zero.
-                       * For keys with empty value, *value is non-NULL and *valueLen is zero.
-                       * For keys with non-empty value, *value is non-NULL and *valueLen is non-zero.
-                       *
-                       * txtRecord:       Pointer to the received TXT Record bytes.
-                       *
-                       * index:           An index into the TXT Record.
-                       *
-                       * key:             A string buffer used to store the key name.
-                       *                  On return, the buffer contains a string
-                       *                  giving the key name. DNS-SD TXT keys are usually
-                       *                  14 characters or less. 
-                       *
-                       * return value:    Record bytes that holds the value data.
-                       *
-                       * exceptions:      Throws kDNSServiceErr_Invalid if index is greater than
-                       *                  GetCount()-1.
-                       */
-
-                       static public Byte
-                       GetItemAtIndex
-                               (
-                               Byte                            txtRecord[],
-                               int                                     index,
-                               [Out] String    **      key
-                               ) __gc[];
-               };
-
-
-               public __abstract __gc class DNSService
-               {
-               public:
-
-                       /*********************************************************************************************
-                       *
-                       * Domain Enumeration
-                       *
-                       *********************************************************************************************/
-
-                       /* DNSServiceEnumerateDomains()
-                       *
-                       * Asynchronously enumerate domains available for browsing and registration.
-                       * Currently, the only domain returned is "local.", but other domains will be returned in future.
-                       *
-                       * The enumeration MUST be cancelled via DNSServiceRefDeallocate() when no more domains
-                       * are to be found.
-                       *
-                       *
-                       * EnumerateDomainsReply Delegate
-                       *
-                       * This Delegate is invoked upon a reply from an EnumerateDomains call.
-                       *
-                       * sdRef:           The DNSServiceRef initialized by DNSServiceEnumerateDomains().
-                       *
-                       * flags:           Possible values are:
-                       *                  MoreComing
-                       *                  Add
-                       *                  Default
-                       *
-                       * 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 NoError (0) on success, otherwise indicates
-                       *                  the failure that occurred (other parameters are undefined if errorCode is nonzero).
-                       *
-                       * replyDomain:     The name of the domain.
-                       *
-                       */
-
-                       __delegate void
-                       EnumerateDomainsReply
-                               (
-                               ServiceRef      *       sdRef,
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,
-                               String          *       replyDomain
-                               );
-
-                       /* DNSServiceEnumerateDomains() Parameters:
-                       *
-                       *
-                       * flags:           Possible values are:
-                       *                  BrowseDomains to enumerate domains recommended for browsing.
-                       *                  RegistrationDomains to enumerate domains recommended
-                       *                  for registration.
-                       *
-                       * 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
-                       *                  all interfaces.
-                       *
-                       * callback:        The delegate to be called when a domain is found or the call asynchronously
-                       *                  fails.
-                       *
-                       *
-                       * return value:    Returns initialize ServiceRef on succeses (any subsequent, asynchronous
-                       *                  errors are delivered to the delegate), otherwise throws an exception indicating
-                       *                  the error that occurred (the callback is not invoked and the ServiceRef
-                       *                  is not initialized.)
-                       */
-
-                       static public ServiceRef*
-                       EnumerateDomains
-                               (
-                               int                                                     flags,
-                               int                                                     interfaceIndex,
-                               EnumerateDomainsReply   *       callback
-                               );
-
-                       /*********************************************************************************************
-                       *
-                       *  Service Registration
-                       *
-                       *********************************************************************************************/
-
-                       /* Register a service that is discovered via Browse() and Resolve() calls.
-                       * 
-                       * RegisterReply() Callback Parameters:
-                       *
-                       * sdRef:           The ServiceRef initialized by Register().
-                       *
-                       * flags:           Currently unused, reserved for future use.
-                       *
-                       * errorCode:       Will be NoError on success, otherwise will
-                       *                  indicate the failure that occurred (including name conflicts, if the
-                       *                  NoAutoRename flag was passed to the
-                       *                  callout.)  Other parameters are undefined if errorCode is nonzero.
-                       *
-                       * name:            The service name registered (if the application did not specify a name in
-                       *                  DNSServiceRegister(), this indicates what name was automatically chosen).
-                       *
-                       * regtype:         The type of service registered, as it was passed to the callout.
-                       *
-                       * domain:          The domain on which the service was registered (if the application did not
-                       *                  specify a domain in Register(), this indicates the default domain
-                       *                  on which the service was registered).
-                       *
-                       */
-
-                       __delegate void
-                       RegisterReply
-                               (
-                               ServiceRef      *       sdRef,
-                               ServiceFlags    flags,
-                               ErrorCode               errorCode,
-                               String          *       name,
-                               String          *       regtype,
-                               String          *       domain
-                               );
-
-                       /* Register()  Parameters:
-                       *
-                       * flags:           Indicates the renaming behavior on name conflict (most applications
-                       *                  will pass 0).  See flag definitions above for details.
-                       *
-                       * 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
-                       *                  available interfaces.  Pass -1 to register a service only on the local
-                       *                  machine (service will not be visible to remote hosts.)
-                       *
-                       * name:            If non-NULL, specifies the service name to be registered.
-                       *                  Most applications will not specify a name, in which case the
-                       *                  computer name is used (this name is communicated to the client via
-                       *                  the callback).
-                       *
-                       * regtype:         The service type followed by the protocol, separated by a dot
-                       *                  (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
-                       *                  New service types should be registered at htp://www.dns-sd.org/ServiceTypes.html.
-                       *
-                       * 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
-                       *                  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
-                       *                  for ensuring that the appropriate address record exists, or creating it
-                       *                  via DNSServiceRegisterRecord().
-                       *
-                       * port:            The port, in host 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.
-                       *
-                       * txtRecord:       The txt record rdata.  May be NULL.  Note that a non-NULL txtRecord
-                       *                  MUST be a properly formatted DNS TXT record, i.e. <length byte> <data>
-                       *                  <length byte> <data> ...
-                       *
-                       * callback:        The delegate to be called when the registration completes or asynchronously
-                       *                  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.
-                       *                  The client may still deregister the service at any time via DNSServiceRefDeallocate().
-                       *
-                       * return value:    Returns initialize ServiceRef (any subsequent, asynchronous
-                       *                  errors are delivered to the callback), otherwise throws an exception indicating
-                       *                  the error that occurred (the callback is never invoked and the DNSServiceRef
-                       *                  is not initialized.)
-                       *
-                       */
-                       static public ServiceRef*
-                       Register
-                               (
-                               int                                     flags,
-                               int                                     interfaceIndex,
-                               String                  *       name,
-                               String                  *       regtype,
-                               String                  *       domain,
-                               String                  *       host,
-                               int                                     port,
-                               Byte                            txtRecord[],
-                               RegisterReply   *       callback
-                               );
-
-                       /* AddRecord()
-                       *
-                       * 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 UpdateRecord() or RemoveRecord().
-                       *
-                       *
-                       * Parameters;
-                       *
-                       * sdRef:           A ServiceRef initialized by Register().
-                       *
-                       * RecordRef:       A pointer to an uninitialized RecordRef.  Upon succesfull completion of this
-                       *                  call, this ref may be passed to UpdateRecord() or RemoveRecord().
-                       *                  If the above ServiceRef is disposed, RecordRef is also
-                       *                  invalidated and may not be used further.
-                       *
-                       * flags:           Currently ignored, reserved for future use.
-                       *
-                       * rrtype:          The type of the record (e.g. TXT, SRV, etc), as defined in nameser.h.
-                       *
-                       * rdata:           The raw rdata to be contained in the added resource record.
-                       *
-                       * ttl:             The time to live of the resource record, in seconds.
-                       *
-                       * return value:    Returns initialized RecordRef, otherwise throws
-                       *                  an exception indicating the error that occurred (the RecordRef is not initialized).
-                       */
-
-                       static public RecordRef*
-                       AddRecord
-                               (
-                               ServiceRef      *       sref,
-                               int                             flags,
-                               int                             rrtype,
-                               Byte                    rdata[],
-                               int                             ttl
-                               );
-
-                       /* UpdateRecord
-                       *
-                       * Update a registered resource record.  The record must either be:
-                       *   - The primary txt record of a service registered via Register()
-                       *   - A record added to a registered service via AddRecord()
-                       *   - An individual record registered by RegisterRecord()
-                       *
-                       *
-                       * Parameters:
-                       *
-                       * sdRef:           A ServiceRef that was initialized by Register()
-                       *                  or CreateConnection().
-                       *
-                       * RecordRef:       A RecordRef initialized by AddRecord, or NULL to update the
-                       *                  service's primary txt record.
-                       *
-                       * flags:           Currently ignored, reserved for future use.
-                       *
-                       * rdata:           The new rdata to be contained in the updated resource record.
-                       *
-                       * ttl:             The time to live of the updated resource record, in seconds.
-                       *
-                       * return value:    No return value on success, otherwise throws an exception
-                       *                  indicating the error that occurred.
-                       */
-                       static public void
-                       UpdateRecord
-                               (
-                               ServiceRef      *       sref,
-                               RecordRef       *       record,
-                               int                             flags,
-                               Byte                    rdata[],
-                               int                             ttl
-                               );
-
-                       /* RemoveRecord
-                       *
-                       * Remove a record previously added to a service record set via AddRecord(), or deregister
-                       * an record registered individually via RegisterRecord().
-                       *
-                       * Parameters:
-                       *
-                       * sdRef:           A ServiceRef initialized by Register() (if the
-                       *                  record being removed was registered via AddRecord()) or by
-                       *                  CreateConnection() (if the record being removed was registered via
-                       *                  RegisterRecord()).
-                       *
-                       * recordRef:       A RecordRef initialized by a successful call to AddRecord()
-                       *                  or RegisterRecord().
-                       *
-                       * flags:           Currently ignored, reserved for future use.
-                       *
-                       * return value:    Nothing on success, otherwise throws an
-                       *                  exception indicating the error that occurred.
-                       */
-
-                       static public void
-                       RemoveRecord
-                                                       (
-                                                       ServiceRef      *       sref,
-                                                       RecordRef       *       record, 
-                                                       int                             flags
-                                                       );
-
-                       /*********************************************************************************************
-                       *
-                       *  Service Discovery
-                       *
-                       *********************************************************************************************/
-
-                       /* Browse for instances of a service.
-                       *
-                       *
-                       * BrowseReply() Parameters:
-                       *
-                       * sdRef:           The DNSServiceRef initialized by Browse().
-                       *
-                       * flags:           Possible values are MoreComing and Add.
-                       *                  See flag definitions for details.
-                       *
-                       * interfaceIndex:  The interface on which the service is advertised.  This index should
-                       *                  be passed to Resolve() when resolving the service.
-                       *
-                       * errorCode:       Will be NoError (0) on success, otherwise will
-                       *                  indicate the failure that occurred.  Other parameters are undefined if
-                       *                  the errorCode is nonzero.
-                       *
-                       * serviceName:     The service name discovered.
-                       *
-                       * regtype:         The service type, as passed in to Browse().
-                       * 
-                       * domain:          The domain on which the service was discovered (if the application did not
-                       *                  specify a domain in Browse(), this indicates the domain on which the
-                       *                  service was discovered.)
-                       *
-                       */
-
-                       __delegate void
-                       BrowseReply
-                               (
-                               ServiceRef      *       sdRef,
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,
-                               String          *       name,
-                               String          *       type,
-                               String          *       domain
-                               );
-
-                       /* DNSServiceBrowse() Parameters:
-                       *
-                       * sdRef:           A pointer to an uninitialized ServiceRef.  Call ServiceRef.Dispose()
-                       *                  to terminate the browse.
-                       *
-                       * flags:           Currently ignored, reserved for future use.
-                       *
-                       * 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
-                       *                  interfaces.  Pass -1 to only browse for services provided on the local host.
-                       *
-                       * 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".
-                       *
-                       * domain:          If non-NULL, specifies the domain on which to browse for services.
-                       *                  Most applications will not specify a domain, instead browsing on the
-                       *                  default domain(s).
-                       *
-                       * callback:        The delegate to be called when an instance of the service being browsed for
-                       *                  is found, or if the call asynchronously fails.
-                       *
-                       * return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
-                       *                  errors are delivered to the callback), otherwise throws an exception indicating
-                       *                  the error that occurred (the callback is not invoked and the ServiceRef
-                       *                  is not initialized.)
-                       */
-
-                       static public ServiceRef*
-                       Browse
-                               (
-                               int                             flags,
-                               int                             interfaceIndex,
-                               String          *       regtype,
-                               String          *       domain,
-                               BrowseReply     *       callback
-                               );
-
-                       /* ResolveReply() Parameters:
-                       *
-                       * Resolve a service name discovered via Browse() to a target host name, port number, and
-                       * txt record.
-                       *
-                       * Note: Applications should NOT use Resolve() solely for txt record monitoring - use
-                       * QueryRecord() instead, as it is more efficient for this task.
-                       *
-                       * Note: When the desired results have been returned, the client MUST terminate the resolve by calling
-                       * ServiceRef.Dispose().
-                       *
-                       * 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 multiple
-                       * SRV or TXT records, QueryRecord() should be used.
-                       *
-                       * ResolveReply Callback Parameters:
-                       *
-                       * sdRef:           The DNSServiceRef initialized by Resolve().
-                       *
-                       * flags:           Currently unused, reserved for future use.
-                       *
-                       * interfaceIndex:  The interface on which the service was resolved.
-                       *
-                       * errorCode:       Will be NoError (0) on success, otherwise will
-                       *                  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>.
-                       *                  (Any literal dots (".") are escaped with a backslash ("\."), and literal
-                       *                  backslashes are escaped with a second backslash ("\\"), e.g. a web server
-                       *                  named "Dr. Pepper" would have the fullname  "Dr\.\032Pepper._http._tcp.local.").
-                       *                  This is the appropriate format to pass to standard system DNS APIs such as
-                       *                  res_query(), or to the special-purpose functions included in this API that
-                       *                  take fullname parameters.
-                       *
-                       * 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 host byte order, on which connections are accepted for this service.
-                       *
-                       * txtRecord:       The service's primary txt record, in standard txt record format.
-                       *
-                       */
-
-                       __delegate void
-                       ResolveReply
-                               (       
-                               ServiceRef      *       sdRef,  
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,
-                               String          *       fullName,
-                               String          *       hostName,
-                               int                             port,
-                               Byte                    txtRecord[]
-                               );
-
-                       /* Resolve() Parameters
-                       *
-                       * flags:           Currently ignored, reserved for future use.
-                       *
-                       * interfaceIndex:  The interface on which to resolve the service.  The client should
-                       *                  pass the interface on which the servicename was discovered, i.e.
-                       *                  the interfaceIndex passed to the DNSServiceBrowseReply callback,
-                       *                  or 0 to resolve the named service on all available interfaces.
-                       *
-                       * name:            The servicename to be resolved.
-                       *
-                       * regtype:         The service type being resolved followed by the protocol, separated by a
-                       *                  dot (e.g. "_ftp._tcp").  The transport protocol must be "_tcp" or "_udp".
-                       *
-                       * domain:          The domain on which the service is registered, i.e. the domain passed
-                       *                  to the DNSServiceBrowseReply callback.
-                       *
-                       * callback:        The delegate to be called when a result is found, or if the call
-                       *                  asynchronously fails.
-                       *
-                       *
-                       * return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
-                       *                  errors are delivered to the callback), otherwise throws an exception indicating
-                       *                  the error that occurred (the callback is never invoked and the DNSServiceRef
-                       *                  is not initialized.)
-                       */
-
-                       static public ServiceRef*
-                       Resolve
-                               (
-                               int                                     flags,
-                               int                                     interfaceIndex,
-                               String                  *       name,
-                               String                  *       regtype,
-                               String                  *       domain,
-                               ResolveReply    *       callback
-                               );
-
-                       /*********************************************************************************************
-                       *
-                       *  Special Purpose Calls (most applications will not use these)
-                       *
-                       *********************************************************************************************/
-
-                       /* CreateConnection/RegisterRecord
-                       *
-                       * Register an individual resource record on a connected ServiceRef.
-                       *
-                       * Note that name conflicts occurring for records registered via this call must be handled
-                       * by the client in the callback.
-                       *
-                       *
-                       * RecordReply() parameters:
-                       *
-                       * sdRef:           The connected ServiceRef initialized by
-                       *                  CreateConnection().
-                       *
-                       * RecordRef:       The RecordRef initialized by RegisterRecord().  If the above
-                       *                  ServiceRef.Dispose is called, this RecordRef is
-                       *                  invalidated, and may not be used further.
-                       *
-                       * flags:           Currently unused, reserved for future use.
-                       *
-                       * errorCode:       Will be NoError on success, otherwise will
-                       *                  indicate the failure that occurred (including name conflicts.)
-                       *                  Other parameters are undefined if errorCode is nonzero.
-                       *
-                       */
-
-                       __delegate void
-                       RegisterRecordReply
-                               (
-                               ServiceRef      *       sdRef,
-                               ServiceFlags    flags,
-                               ErrorCode               errorCode,
-                               RecordRef       *       record
-                               );
-
-                       /* CreateConnection()
-                       *
-                       * Create a connection to the daemon allowing efficient registration of
-                       * multiple individual records.
-                       *
-                       *
-                       * Parameters:
-                       *
-                       * callback:        The delegate to be called when a result is found, or if the call
-                       *                  asynchronously fails (e.g. because of a name conflict.)
-                       *
-                       * return value:    Returns initialize ServiceRef on success, otherwise throws
-                       *                  an exception indicating the specific failure that occurred (in which
-                       *                  case the ServiceRef is not initialized).
-                       */
-
-                       static public ServiceRef*
-                       CreateConnection
-                               (
-                               RegisterRecordReply * callback
-                               );
-
-
-                       /* RegisterRecord() Parameters:
-                       *
-                       * sdRef:           A ServiceRef initialized by CreateConnection().
-                       *
-                       * RecordRef:       A pointer to an uninitialized RecordRef.  Upon succesfull completion of this
-                       *                  call, this ref may be passed to UpdateRecord() or RemoveRecord().
-                       *                  (To deregister ALL records registered on a single connected ServiceRef
-                       *                  and deallocate each of their corresponding RecordRefs, call
-                       *                  ServiceRef.Dispose()).
-                       *
-                       * flags:           Possible values are Shared or Unique
-                       *                  (see flag type definitions for details).
-                       *
-                       * 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.
-                       *                  Passing -1 causes the record to only be visible on the local host.
-                       *
-                       * fullname:        The full domain name of the resource record.
-                       *
-                       * rrtype:          The numerical type of the resource record (e.g. PTR, SRV, etc), as defined
-                       *                  in nameser.h.
-                       *
-                       * rrclass:         The class of the resource record, as defined in nameser.h (usually 1 for the
-                       *                  Internet class).
-                       *
-                       * 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.
-                       *
-                       *
-                       * return value:    Returns initialize RecordRef on succeses (any subsequent, asynchronous
-                       *                  errors are delivered to the callback), otherwise throws an exception indicating
-                       *                  the error that occurred (the callback is never invoked and the RecordRef is
-                       *                  not initialized.)
-                       */
-                       static public RecordRef*
-                       RegisterRecord
-                               (
-                               ServiceRef                      *       sdRef,
-                               ServiceFlags                    flags,
-                               int                                             interfaceIndex,
-                               String                          *       fullname,
-                               int                                             rrtype,
-                               int                                             rrclass,
-                               Byte                                    rdata[],
-                               int                                             ttl
-                               );
-
-
-                       /* DNSServiceQueryRecord
-                       *
-                       * Query for an arbitrary DNS record.
-                       *
-                       *
-                       * QueryRecordReply() Delegate Parameters:
-                       *
-                       * sdRef:           The ServiceRef initialized by QueryRecord().
-                       *
-                       * flags:           Possible values are MoreComing and
-                       *                  Add.  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).
-                       *
-                       * 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. PTR, SRV, etc) as defined in nameser.h.
-                       *
-                       * rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
-                       *
-                       * rdata:           The raw rdata of the resource record.
-                       *
-                       * ttl:             The resource record's time to live, in seconds.
-                       *
-                       */
-
-                       __delegate void
-                       QueryRecordReply
-                               (
-                               ServiceRef      *       sdRef,
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               ErrorCode               errorCode,      
-                               String          *       fullName,
-                               int                             rrtype,
-                               int                             rrclass,
-                               Byte                    rdata[],
-                               int                             ttl
-                               );
-
-                       /* QueryRecord() Parameters:
-                       *
-                       * flags:           Pass LongLivedQuery 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.  Passing -1 causes the name to be queried for only on the
-                       *                  local host.
-                       *
-                       * 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. PTR, SRV, etc)
-                       *                  as defined in nameser.h.
-                       *
-                       * rrclass:         The class of the resource record, as defined in nameser.h
-                       *                  (usually 1 for the Internet class).
-                       *
-                       * callback:        The delegate to be called when a result is found, or if the call
-                       *                  asynchronously fails.
-                       *
-                       *
-                       * return value:    Returns initialized ServiceRef on succeses (any subsequent, asynchronous
-                       *                  errors are delivered to the callback), otherwise throws an exception indicating
-                       *                  the error that occurred (the callback is never invoked and the ServiceRef
-                       *                  is not initialized.)
-                       */
-
-                       static public ServiceRef*
-                       QueryRecord
-                               (
-                               ServiceFlags                    flags,
-                               int                                             interfaceIndex,
-                               String                          *       fullname,
-                               int                                             rrtype,
-                               int                                             rrclass,
-                               QueryRecordReply        *       callback
-                               );
-
-                       /* ReconfirmRecord
-                       *
-                       * 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.
-                       *
-                       * Parameters:
-                       *
-                       * flags:           Currently unused, reserved for future use.
-                       *
-                       * fullname:        The resource record's full domain name.
-                       *
-                       * rrtype:          The resource record's type (e.g. PTR, SRV, etc) as defined in nameser.h.
-                       *
-                       * rrclass:         The class of the resource record, as defined in nameser.h (usually 1).
-                       *
-                       * rdata:           The raw rdata of the resource record.
-                       *
-                       */
-                       static public void
-                       ReconfirmRecord
-                               (
-                               ServiceFlags    flags,
-                               int                             interfaceIndex,
-                               String          *       fullname,
-                               int                             rrtype,
-                               int                             rrclass,
-                               Byte                    rdata[]
-                               );
-               };
-       }
-}
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.ico b/mDNSWindows/DLL.NET/dnssd_NET.ico
deleted file mode 100755 (executable)
index 3a5525f..0000000
Binary files a/mDNSWindows/DLL.NET/dnssd_NET.ico and /dev/null differ
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.rc b/mDNSWindows/DLL.NET/dnssd_NET.rc
deleted file mode 100755 (executable)
index 95df1cf..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "WinVersRes.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-1                       ICON                    "dnssd_NET.ico"
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-    "\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", MASTER_COMPANY_NAME
-            VALUE "FileDescription", "Bonjour.NET Client Library"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "dnssd.NET.dll"
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
-            VALUE "OriginalFilename", "dnssd.NET.dll"
-            VALUE "ProductName", MASTER_PROD_NAME
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/mDNSWindows/DLL.NET/dnssd_NET.vcproj b/mDNSWindows/DLL.NET/dnssd_NET.vcproj
deleted file mode 100755 (executable)
index 98cc63b..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="DLL.NET"\r
-       ProjectGUID="{2A2FFA97-AF60-494F-9384-BBAA283AA3F2}"\r
-       RootNamespace="DLL2NET"\r
-       Keyword="ManagedCProj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       CharacterSet="1"\r
-                       ManagedExtensions="4"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                               Description="Generating keypair..."\r
-                               CommandLine="sn -k dnssd_NET.snk"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="../;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"\r
-                               RuntimeLibrary="3"\r
-                               UsePrecompiledHeader="2"\r
-                               WarningLevel="3"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)\dnssd.NET.dll"\r
-                               LinkIncremental="2"\r
-                               GenerateDebugInformation="true"\r
-                               AssemblyDebug="1"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               EmbedManifest="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       CharacterSet="1"\r
-                       ManagedExtensions="4"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                               Description="Generating keypair..."\r
-                               CommandLine="sn -k dnssd_NET.snk"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="../;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;WIN32_LEAN_AND_MEAN"\r
-                               RuntimeLibrary="3"\r
-                               UsePrecompiledHeader="2"\r
-                               WarningLevel="3"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)\dnssd.NET.dll"\r
-                               LinkIncremental="2"\r
-                               GenerateDebugInformation="true"\r
-                               AssemblyDebug="1"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               EmbedManifest="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       CharacterSet="1"\r
-                       ManagedExtensions="4"\r
-                       WholeProgramOptimization="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                               Description="Generating keypair..."\r
-                               CommandLine="sn -k dnssd_NET.snk"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="../;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"\r
-                               RuntimeLibrary="2"\r
-                               UsePrecompiledHeader="0"\r
-                               WarningLevel="3"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)\dnssd.NET.dll"\r
-                               LinkIncremental="1"\r
-                               GenerateDebugInformation="true"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               EmbedManifest="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       CharacterSet="1"\r
-                       ManagedExtensions="4"\r
-                       WholeProgramOptimization="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                               Description="Generating keypair..."\r
-                               CommandLine="sn -k dnssd_NET.snk"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="../;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;WIN32_LEAN_AND_MEAN"\r
-                               RuntimeLibrary="2"\r
-                               UsePrecompiledHeader="0"\r
-                               WarningLevel="3"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="../DLL/$(OutDir)/dnssd.lib ws2_32.lib"\r
-                               OutputFile="$(OutDir)\dnssd.NET.dll"\r
-                               LinkIncremental="1"\r
-                               GenerateDebugInformation="true"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               EmbedManifest="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-               <AssemblyReference\r
-                       RelativePath="System.dll"\r
-                       AssemblyName="System, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"\r
-               />\r
-               <AssemblyReference\r
-                       RelativePath="System.Data.dll"\r
-                       AssemblyName="System.Data, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"\r
-               />\r
-               <AssemblyReference\r
-                       RelativePath="System.XML.dll"\r
-                       AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"\r
-               />\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\AssemblyInfo.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\dnssd_NET.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\Stdafx.cpp"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="1"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="1"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="1"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="1"\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\dnssd_NET.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\resource.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\Stdafx.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\dnssd_NET.ico"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\dnssd_NET.rc"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <File\r
-                       RelativePath=".\ReadMe.txt"\r
-                       >\r
-               </File>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/DLL.NET/resource.h b/mDNSWindows/DLL.NET/resource.h
deleted file mode 100755 (executable)
index 9a14836..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by dnssd_NET.rc
diff --git a/mDNSWindows/DLL/dll.aps b/mDNSWindows/DLL/dll.aps
deleted file mode 100644 (file)
index 31b4787..0000000
Binary files a/mDNSWindows/DLL/dll.aps and /dev/null differ
diff --git a/mDNSWindows/DLL/dll.rc b/mDNSWindows/DLL/dll.rc
deleted file mode 100644 (file)
index e76fb30..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "WinVersRes.h"
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "#include ""WinVersRes.h""\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", MASTER_COMPANY_NAME
-            VALUE "FileDescription", "Bonjour Client Library"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "dnssd.dll"
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
-            VALUE "OriginalFilename", "dnssd.dll"
-            VALUE "ProductName", MASTER_PROD_NAME
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/mDNSWindows/DLL/dllmain.c b/mDNSWindows/DLL/dllmain.c
deleted file mode 100644 (file)
index 295e2ed..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/* -*- Mode: C; 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.
- */
-
-#include <windows.h>
-#include <DebugServices.h>
-#include <stdlib.h>
-
-BOOL APIENTRY  DllMain( HANDLE inModule, DWORD inReason, LPVOID inReserved )
-{
-       (void) inModule;
-       (void) inReserved;
-       
-       switch( inReason )
-       {
-               case DLL_PROCESS_ATTACH:
-               case DLL_THREAD_ATTACH:
-               case DLL_THREAD_DETACH:
-               case DLL_PROCESS_DETACH:
-                       break;
-       }
-    return( TRUE );
-}
-
-
-BOOL
-IsSystemServiceDisabled()
-{
-       ENUM_SERVICE_STATUS     *       lpService = NULL;
-       SC_HANDLE                                       sc;
-       BOOL                                                    ret = FALSE;
-       BOOL                                                    ok;
-       DWORD                                                   bytesNeeded = 0;
-       DWORD                                                   srvCount;
-       DWORD                                                   resumeHandle = 0;
-       DWORD                                                   srvType;
-       DWORD                                                   srvState;
-       DWORD                                                   dwBytes = 0;
-       DWORD                                                   i;
-       OSStatus                                                err;
-
-       sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
-       err = translate_errno( sc, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       srvType         =       SERVICE_WIN32;
-       srvState                =       SERVICE_STATE_ALL;
-
-       for ( ;; )
-       {
-               // Call EnumServicesStatus using the handle returned by OpenSCManager
-
-               ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
-
-               if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
-               {
-                       break;
-               }
-
-               if ( lpService )
-               {
-                       free( lpService );
-               }
-
-               dwBytes = bytesNeeded;
-
-               lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
-               require_action( lpService, exit, ret = FALSE );
-       }
-
-       err = translate_errno( ok, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       for ( i = 0; i < srvCount; i++ )
-       {
-               if ( strcmp( lpService[i].lpServiceName, "Bonjour Service" ) == 0 )
-               {
-                       if ( ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_PAUSED ) || ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED ) )
-                       {
-                               ret = TRUE;
-                       }
-
-                       break;
-               }
-       }
-
-exit:
-
-       if ( lpService )
-       {
-               free( lpService );
-       }
-
-       if ( sc )
-       {
-               CloseServiceHandle ( sc );
-       }
-
-       return ret;
-}
diff --git a/mDNSWindows/DLL/dnssd.def b/mDNSWindows/DLL/dnssd.def
deleted file mode 100644 (file)
index 160510b..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-; -*- tab-width: 4 -*-
-;
-; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-; 
-;     http://www.apache.org/licenses/LICENSE-2.0
-; 
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-; See the License for the specific language governing permissions and
-; limitations under the License.
-;
-
-LIBRARY                dnssd
-
-EXPORTS
-       DNSServiceRefSockFD
-       DNSServiceProcessResult
-       DNSServiceRefDeallocate
-       DNSServiceEnumerateDomains
-       DNSServiceRegister
-       DNSServiceAddRecord
-       DNSServiceUpdateRecord
-       DNSServiceRemoveRecord
-       DNSServiceBrowse
-       DNSServiceResolve
-       DNSServiceConstructFullName
-       DNSServiceCreateConnection
-       DNSServiceRegisterRecord
-       DNSServiceQueryRecord
-       DNSServiceReconfirmRecord
-       DNSServiceNATPortMappingCreate
-       DNSServiceGetAddrInfo
-       DNSServiceGetProperty
-       TXTRecordCreate
-       TXTRecordDeallocate
-       TXTRecordSetValue
-       TXTRecordRemoveValue
-       TXTRecordContainsKey
-       TXTRecordGetCount
-       TXTRecordGetLength
-       TXTRecordGetBytesPtr
-       TXTRecordGetValuePtr
-       TXTRecordGetItemAtIndex
diff --git a/mDNSWindows/DLL/dnssd.vcproj b/mDNSWindows/DLL/dnssd.vcproj
deleted file mode 100644 (file)
index 814a322..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="DLL"\r
-       ProjectGUID="{AB581101-18F0-46F6-B56A-83A6B1EA657E}"\r
-       RootNamespace="DLL"\r
-       Keyword="Win32Proj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;NOT_HAVE_SA_LEN;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                               DisableSpecificWarnings="4127;4204"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/dnssd.dll"\r
-                               LinkIncremental="2"\r
-                               ModuleDefinitionFile="dnssd.def"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
-                               SubSystem="2"\r
-                               BaseAddress="0x16000000"\r
-                               ImportLibrary="$(OutDir)\dnssd.lib"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                               DisableSpecificWarnings="4127;4204"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/dnssd.dll"\r
-                               LinkIncremental="2"\r
-                               ModuleDefinitionFile="dnssd.def"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
-                               SubSystem="2"\r
-                               BaseAddress="0x16000000"\r
-                               ImportLibrary="$(OutDir)\dnssd.lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                               DisableSpecificWarnings="4127;4204"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/dnssd.dll"\r
-                               LinkIncremental="1"\r
-                               ModuleDefinitionFile="dnssd.def"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               BaseAddress="0x16000000"\r
-                               ImportLibrary="$(OutDir)\dnssd.lib"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;                     mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib&quot;                                     mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;     mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;                            mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal&quot;                                                                   mkdir &quot;$(DSTROOT)\AppleInternal&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin&quot;                                                           mkdir &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin\$(PlatformName)&quot;                           mkdir &quot;$(DSTROOT)\AppleInternal\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                           &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(OutDir)\dnssd.dll.pdb&quot;                                                                          &quot;$(DSTROOT)\AppleInternal\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(ProjectDir)..\..\mDNSShared\dns_sd.h&quot;                                             &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="../../mDNSCore;../../mDNSShared;../"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.dll.pdb"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               CompileAs="0"\r
-                               DisableSpecificWarnings="4127;4204"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/dnssd.dll"\r
-                               LinkIncremental="1"\r
-                               ModuleDefinitionFile="dnssd.def"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)\dnssd.dll.pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               BaseAddress="0x16000000"\r
-                               ImportLibrary="$(OutDir)\dnssd.lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;                     mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib&quot;                                     mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;     mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;                            mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\include&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal&quot;                                                                   mkdir &quot;$(DSTROOT)\AppleInternal&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin&quot;                                                           mkdir &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin\$(PlatformName)&quot;                           mkdir &quot;$(DSTROOT)\AppleInternal\bin\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                                           &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(OutDir)\dnssd.dll.pdb&quot;                                                                         &quot;$(DSTROOT)\AppleInternal\bin\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\dllmain.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\dnssd.def"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dnssd_clientlib.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dnssd_clientstub.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\GenLinkedList.c"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\CommonServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dns_sd.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\GenLinkedList.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\resource.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\dll.rc"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/DLL/dnssd.vcxproj b/mDNSWindows/DLL/dnssd.vcxproj
deleted file mode 100755 (executable)
index 7438a3a..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectName>DLL</ProjectName>\r
-    <ProjectGuid>{AB581101-18F0-46F6-B56A-83A6B1EA657E}</ProjectGuid>\r
-    <RootNamespace>DLL</RootNamespace>\r
-    <Keyword>Win32Proj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">dnssd</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">dnssd</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dnssd</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dnssd</TargetName>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;NOT_HAVE_SA_LEN;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-      <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
-      <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <BaseAddress>0x16000000</BaseAddress>\r
-      <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;DEBUG=1;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-      <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
-      <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <BaseAddress>0x16000000</BaseAddress>\r
-      <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-      <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
-      <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <BaseAddress>0x16000000</BaseAddress>\r
-      <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)"                     mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib"                                     mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"     mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\include"                            mkdir "$(DSTROOT)\Program Files\Bonjour SDK\include"\r
-if not exist "$(DSTROOT)\AppleInternal"                                                                   mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin"                                                           mkdir "$(DSTROOT)\AppleInternal\bin"\r
-if not exist "$(DSTROOT)\AppleInternal\bin\$(Platform)"                           mkdir "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                                           "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(OutDir)dnssd.dll.pdb"                                                                          "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-xcopy /I/Y "$(ProjectDir)..\..\mDNSShared\dns_sd.h"                                             "$(DSTROOT)\Program Files\Bonjour SDK\include"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>../../mDNSCore;../../mDNSShared;../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;MDNS_DEBUGMSGS=0;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;NOT_HAVE_SA_LEN;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.dll.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <CompileAs>Default</CompileAs>\r
-      <DisableSpecificWarnings>4127;4204;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssd.dll</OutputFile>\r
-      <ModuleDefinitionFile>dnssd.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)dnssd.dll.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <BaseAddress>0x16000000</BaseAddress>\r
-      <ImportLibrary>$(OutDir)dnssd.lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)"                     mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib"                                     mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"     mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\include"                            mkdir "$(DSTROOT)\Program Files\Bonjour SDK\include"\r
-if not exist "$(DSTROOT)\AppleInternal"                                                                   mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin"                                                           mkdir "$(DSTROOT)\AppleInternal\bin"\r
-if not exist "$(DSTROOT)\AppleInternal\bin\$(Platform)"                           mkdir "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                                           "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(OutDir)dnssd.dll.pdb"                                                                         "$(DSTROOT)\AppleInternal\bin\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
-    <ClCompile Include="dllmain.c" />\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_clientlib.c" />\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_clientstub.c" />\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c" />\r
-    <ClCompile Include="..\..\mDNSShared\GenLinkedList.c" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="dnssd.def" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\dns_sd.h" />\r
-    <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h" />\r
-    <ClInclude Include="..\..\mDNSShared\GenLinkedList.h" />\r
-    <ClInclude Include="resource.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="dll.rc" />\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/DLL/dnssd.vcxproj.filters b/mDNSWindows/DLL/dnssd.vcxproj.filters
deleted file mode 100755 (executable)
index 3920fd6..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="dllmain.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_clientlib.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_clientstub.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\GenLinkedList.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="dnssd.def">\r
-      <Filter>Source Files</Filter>\r
-    </None>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\dns_sd.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\GenLinkedList.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="resource.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="dll.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/DLL/resource.h b/mDNSWindows/DLL/resource.h
deleted file mode 100644 (file)
index bdea251..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by dll.rc
-//
-#define IDS_PROJNAME                    100
-#define IDR_WMDMLOGGER                  101
-#define IDS_LOG_SEV_INFO                201
-#define IDS_LOG_SEV_WARN                202
-#define IDS_LOG_SEV_ERROR               203
-#define IDS_LOG_DATETIME                204
-#define IDS_LOG_SRCNAME                 205
-#define IDS_DEF_LOGFILE                 301
-#define IDS_DEF_MAXSIZE                 302
-#define IDS_DEF_SHRINKTOSIZE            303
-#define IDS_DEF_LOGENABLED              304
-#define IDS_MUTEX_TIMEOUT               401
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        201
-#define _APS_NEXT_COMMAND_VALUE         32768
-#define _APS_NEXT_CONTROL_VALUE         201
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/mDNSWindows/DLLStub/DLLStub.cpp b/mDNSWindows/DLLStub/DLLStub.cpp
deleted file mode 100755 (executable)
index 38fd5e0..0000000
+++ /dev/null
@@ -1,693 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009, Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1.  Redistributions of source code must retain the above copyright notice,
- *     this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright notice,
- *     this list of conditions and the following disclaimer in the documentation
- *     and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- *     contributors may be used to endorse or promote products derived from this
- *     software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "DLLStub.h"
-
-static int             g_defaultErrorCode = kDNSServiceErr_ServiceNotRunning;
-static DLLStub g_glueLayer;
-
-
-// ------------------------------------------
-// DLLStub implementation
-// ------------------------------------------
-DLLStub * DLLStub::m_instance;
-
-DLLStub::DLLStub()
-:
-       m_library( LoadLibrary( TEXT( "dnssd.dll" ) ) )
-{
-       m_instance = this;
-}
-
-
-DLLStub::~DLLStub()
-{
-       if ( m_library != NULL )
-       {
-               FreeLibrary( m_library );
-               m_library = NULL;
-       }
-
-       m_instance = NULL;
-}
-
-
-bool
-DLLStub::GetProcAddress( FARPROC * func, LPCSTR lpProcName )
-{ 
-       if ( m_instance && m_instance->m_library )
-       {
-               // Only call ::GetProcAddress if *func is NULL. This allows
-               // the calling code to cache the funcptr value, and we get
-               // some performance benefit.
-
-               if ( *func == NULL )
-               {
-                       *func = ::GetProcAddress( m_instance->m_library, lpProcName );
-               }
-       }
-       else
-       {
-               *func = NULL;
-       }
-
-       return ( *func != NULL );
-}
-
-
-dnssd_sock_t DNSSD_API
-DNSServiceRefSockFD(DNSServiceRef sdRef)
-{
-       typedef int (DNSSD_API * Func)(DNSServiceRef sdRef);
-       static Func func = NULL;
-       int ret = INVALID_SOCKET;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceProcessResult(DNSServiceRef sdRef)
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef sdRef);
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef );
-       }
-       
-       return ret;
-}
-
-
-void DNSSD_API
-DNSServiceRefDeallocate(DNSServiceRef sdRef)
-{
-       typedef void (DNSSD_API * Func)(DNSServiceRef sdRef);
-       static Func func = NULL;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               func( sdRef );
-       }
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceEnumerateDomains
-               (
-               DNSServiceRef                       *sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               DNSServiceDomainEnumReply           callBack,
-               void                                *context
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceDomainEnumReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, flags, interfaceIndex, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceRegister
-               (
-               DNSServiceRef                       *sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               const char                          *name,
-               const char                          *regtype,
-               const char                          *domain,
-               const char                          *host,
-               uint16_t                            port,
-               uint16_t                            txtLen,
-               const void                          *txtRecord,
-               DNSServiceRegisterReply             callBack,
-               void                                *context
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, const char*, const char*, uint16_t, uint16_t, const void*, DNSServiceRegisterReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, flags, interfaceIndex, name, regtype, domain, host, port, txtLen, txtRecord, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceAddRecord
-               (
-               DNSServiceRef                       sdRef,
-               DNSRecordRef                        *RecordRef,
-               DNSServiceFlags                     flags,
-               uint16_t                            rrtype,
-               uint16_t                            rdlen,
-               const void                          *rdata,
-               uint32_t                            ttl
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef*, DNSServiceFlags, uint16_t, uint16_t, const void*, uint32_t );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, RecordRef, flags, rrtype, rdlen, rdata, ttl );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceUpdateRecord
-               (
-               DNSServiceRef                       sdRef,
-               DNSRecordRef                        RecordRef,     /* may be NULL */
-               DNSServiceFlags                     flags,
-               uint16_t                            rdlen,
-               const void                          *rdata,
-               uint32_t                            ttl
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef, DNSServiceFlags, uint16_t, const void*, uint32_t );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, RecordRef, flags, rdlen, rdata, ttl );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceRemoveRecord
-               (
-               DNSServiceRef                 sdRef,
-               DNSRecordRef                  RecordRef,
-               DNSServiceFlags               flags
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef, DNSServiceFlags );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, RecordRef, flags );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceBrowse
-               (
-               DNSServiceRef                       *sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               const char                          *regtype,
-               const char                          *domain,    /* may be NULL */
-               DNSServiceBrowseReply               callBack,
-               void                                *context    /* may be NULL */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, DNSServiceBrowseReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, flags, interfaceIndex, regtype, domain, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceResolve
-               (
-               DNSServiceRef                       *sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               const char                          *name,
-               const char                          *regtype,
-               const char                          *domain,
-               DNSServiceResolveReply              callBack,
-               void                                *context  /* may be NULL */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, const char*, const char*, DNSServiceResolveReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, flags, interfaceIndex, name, regtype, domain, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceConstructFullName
-               (
-               char                            *fullName,
-               const char                      *service,      /* may be NULL */
-               const char                      *regtype,
-               const char                      *domain
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)( char*, const char*, const char*, const char* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( fullName, service, regtype, domain );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceCreateConnection(DNSServiceRef *sdRef)
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)( DNSServiceRef* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceRegisterRecord
-               (
-               DNSServiceRef                       sdRef,
-               DNSRecordRef                        *RecordRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               const char                          *fullname,
-               uint16_t                            rrtype,
-               uint16_t                            rrclass,
-               uint16_t                            rdlen,
-               const void                          *rdata,
-               uint32_t                            ttl,
-               DNSServiceRegisterRecordReply       callBack,
-               void                                *context    /* may be NULL */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef, DNSRecordRef*, DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, uint16_t, const void*, uint16_t, DNSServiceRegisterRecordReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, RecordRef, flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata, ttl, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceQueryRecord
-               (
-               DNSServiceRef                       *sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               const char                          *fullname,
-               uint16_t                            rrtype,
-               uint16_t                            rrclass,
-               DNSServiceQueryRecordReply          callBack,
-               void                                *context  /* may be NULL */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, DNSServiceQueryRecordReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, flags, interfaceIndex, fullname, rrtype, rrclass, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceReconfirmRecord
-               (
-               DNSServiceFlags                    flags,
-               uint32_t                           interfaceIndex,
-               const char                         *fullname,
-               uint16_t                           rrtype,
-               uint16_t                           rrclass,
-               uint16_t                           rdlen,
-               const void                         *rdata
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)( DNSServiceFlags, uint32_t, const char*, uint16_t, uint16_t, uint16_t, const void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( flags, interfaceIndex, fullname, rrtype, rrclass, rdlen, rdata );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceNATPortMappingCreate
-               (
-               DNSServiceRef                    *sdRef,
-               DNSServiceFlags                  flags,
-               uint32_t                         interfaceIndex,
-               DNSServiceProtocol               protocol,          /* TCP and/or UDP          */
-               uint16_t                         internalPort,      /* network byte order      */
-               uint16_t                         externalPort,      /* network byte order      */
-               uint32_t                         ttl,               /* time to live in seconds */
-               DNSServiceNATPortMappingReply    callBack,
-               void                             *context           /* may be NULL             */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceProtocol, uint16_t, uint16_t, uint16_t, DNSServiceNATPortMappingReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, flags, interfaceIndex, protocol, internalPort, externalPort, ttl, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceGetAddrInfo
-               (
-               DNSServiceRef                    *sdRef,
-               DNSServiceFlags                  flags,
-               uint32_t                         interfaceIndex,
-               DNSServiceProtocol               protocol,
-               const char                       *hostname,
-               DNSServiceGetAddrInfoReply       callBack,
-               void                             *context          /* may be NULL */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)(DNSServiceRef*, DNSServiceFlags, uint32_t, DNSServiceProtocol, const char*, DNSServiceGetAddrInfoReply, void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( sdRef, flags, interfaceIndex, protocol, hostname, callBack, context );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-DNSServiceGetProperty
-               (
-               const char *property,  /* Requested property (i.e. kDNSServiceProperty_DaemonVersion) */
-               void       *result,    /* Pointer to place to store result */
-               uint32_t   *size       /* size of result location */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)( const char*, void*, uint32_t* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( property, result, size );
-       }
-       
-       return ret;
-}
-
-
-void DNSSD_API
-TXTRecordCreate
-               (
-               TXTRecordRef     *txtRecord,
-               uint16_t         bufferLen,
-               void             *buffer
-               )
-{
-       typedef void (DNSSD_API * Func)( TXTRecordRef*, uint16_t, void* );
-       static Func func = NULL;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               func( txtRecord, bufferLen, buffer );
-       }
-}
-
-
-void DNSSD_API
-TXTRecordDeallocate
-               (
-               TXTRecordRef     *txtRecord
-               )
-{
-       typedef void (DNSSD_API * Func)( TXTRecordRef* );
-       static Func func = NULL;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               func( txtRecord );
-       }
-}
-
-
-DNSServiceErrorType DNSSD_API
-TXTRecordSetValue
-               (
-               TXTRecordRef     *txtRecord,
-               const char       *key,
-               uint8_t          valueSize,        /* may be zero */
-               const void       *value            /* may be NULL */
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)( TXTRecordRef*, const char*, uint8_t, const void* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtRecord, key, valueSize, value );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-TXTRecordRemoveValue
-               (
-               TXTRecordRef     *txtRecord,
-               const char       *key
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)( TXTRecordRef*, const char* );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtRecord, key );
-       }
-       
-       return ret;
-}
-
-
-int DNSSD_API
-TXTRecordContainsKey
-               (
-               uint16_t         txtLen,
-               const void       *txtRecord,
-               const char       *key
-               )
-{
-       typedef int (DNSSD_API * Func)( uint16_t, const void*, const char* );
-       static Func func = NULL;
-       int ret = 0;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtLen, txtRecord, key );
-       }
-       
-       return ret;
-}
-
-
-uint16_t DNSSD_API
-TXTRecordGetCount
-               (
-               uint16_t         txtLen,
-               const void       *txtRecord
-               )
-{
-       typedef uint16_t (DNSSD_API * Func)( uint16_t, const void* );
-       static Func func = NULL;
-       uint16_t ret = 0;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtLen, txtRecord );
-       }
-       
-       return ret;
-}
-
-
-uint16_t DNSSD_API
-TXTRecordGetLength
-               (
-               const TXTRecordRef *txtRecord
-               )
-{
-       typedef uint16_t (DNSSD_API * Func)( const TXTRecordRef* );
-       static Func func = NULL;
-       uint16_t ret = 0;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtRecord );
-       }
-       
-       return ret;
-}
-
-
-const void * DNSSD_API
-TXTRecordGetBytesPtr
-               (
-               const TXTRecordRef *txtRecord
-               )
-{
-       typedef const void* (DNSSD_API * Func)( const TXTRecordRef* );
-       static Func func = NULL;
-       const void* ret = NULL;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtRecord );
-       }
-       
-       return ret;
-}
-
-
-const void * DNSSD_API
-TXTRecordGetValuePtr
-               (
-               uint16_t         txtLen,
-               const void       *txtRecord,
-               const char       *key,
-               uint8_t          *valueLen
-               )
-{
-       typedef const void* (DNSSD_API * Func)( uint16_t, const void*, const char*, uint8_t* );
-       static Func func = NULL;
-       const void* ret = NULL;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtLen, txtRecord, key, valueLen );
-       }
-       
-       return ret;
-}
-
-
-DNSServiceErrorType DNSSD_API
-TXTRecordGetItemAtIndex
-               (
-               uint16_t         txtLen,
-               const void       *txtRecord,
-               uint16_t         itemIndex,
-               uint16_t         keyBufLen,
-               char             *key,
-               uint8_t          *valueLen,
-               const void       **value
-               )
-{
-       typedef DNSServiceErrorType (DNSSD_API * Func)( uint16_t, const void*, uint16_t, uint16_t, char*, uint8_t*, const void** );
-       static Func func = NULL;
-       DNSServiceErrorType ret = g_defaultErrorCode;
-
-       if ( DLLStub::GetProcAddress( ( FARPROC* ) &func, __FUNCTION__ ) )
-       {
-               ret = func( txtLen, txtRecord, itemIndex, keyBufLen, key, valueLen, value );
-       }
-       
-       return ret;
-}
diff --git a/mDNSWindows/DLLStub/DLLStub.h b/mDNSWindows/DLLStub/DLLStub.h
deleted file mode 100755 (executable)
index 44f57d1..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009, Apple Computer, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1.  Redistributions of source code must retain the above copyright notice,
- *     this list of conditions and the following disclaimer.
- * 2.  Redistributions in binary form must reproduce the above copyright notice,
- *     this list of conditions and the following disclaimer in the documentation
- *     and/or other materials provided with the distribution.
- * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of its
- *     contributors may be used to endorse or promote products derived from this
- *     software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _DLLStub_h
-#define _DLLStub_h
-
-#include <windows.h>
-#include <dns_sd.h>
-
-class DLLStub
-{
-public:
-
-       DLLStub();
-       ~DLLStub();
-
-       static bool
-       GetProcAddress( FARPROC * func, LPCSTR lpProcName );
-
-private:
-
-       static DLLStub  *       m_instance;
-       HMODULE                         m_library;
-};
-
-
-#endif
\ No newline at end of file
diff --git a/mDNSWindows/DLLStub/DLLStub.vcproj b/mDNSWindows/DLLStub/DLLStub.vcproj
deleted file mode 100755 (executable)
index dc68289..0000000
+++ /dev/null
@@ -1,324 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="DLLStub"\r
-       ProjectGUID="{3A2B6325-3053-4236-84BD-AA9BE2E323E5}"\r
-       RootNamespace="DLLStub"\r
-       Keyword="Win32Proj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="4"\r
-                       UseOfATL="0"\r
-                       CharacterSet="1"\r
-                       WholeProgramOptimization="0"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               MinimalRebuild="false"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.pdb"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLibrarianTool"\r
-                               OutputFile="$(OutDir)\dnssdStatic.lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="4"\r
-                       UseOfATL="0"\r
-                       CharacterSet="1"\r
-                       WholeProgramOptimization="0"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               MinimalRebuild="false"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.pdb"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLibrarianTool"\r
-                               OutputFile="$(OutDir)\dnssdStatic.lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="4"\r
-                       UseOfATL="0"\r
-                       CharacterSet="1"\r
-                       WholeProgramOptimization="0"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.lib.pdb"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLibrarianTool"\r
-                               OutputFile="$(OutDir)\dnssdStatic.lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;echo F | xcopy /Y &quot;$(OutDir)\dnssdStatic.lib&quot;                                                        &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)\dnssd.lib&quot;&#x0D;&#x0A;xcopy /Y &quot;$(OutDir)\dnssd.lib.pdb&quot;                                                                         &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="4"\r
-                       UseOfATL="0"\r
-                       CharacterSet="1"\r
-                       WholeProgramOptimization="0"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               ProgramDataBaseFileName="$(IntDir)\dnssd.lib.pdb"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLibrarianTool"\r
-                               OutputFile="$(OutDir)\dnssdStatic.lib"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot; mkdir &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;echo F | xcopy /I/Y &quot;$(OutDir)\dnssdStatic.lib&quot;                                                     &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)\dnssd.lib&quot;&#x0D;&#x0A;xcopy /Y &quot;$(OutDir)\dnssd.lib.pdb&quot;                                                                         &quot;$(DSTROOT)\Program Files\Bonjour SDK\lib\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\DLLStub.cpp"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\DLLStub.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
-                       >\r
-               </Filter>\r
-               <File\r
-                       RelativePath=".\ReadMe.txt"\r
-                       >\r
-               </File>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/DLLStub/DLLStub.vcxproj b/mDNSWindows/DLLStub/DLLStub.vcxproj
deleted file mode 100755 (executable)
index 292d931..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{3A2B6325-3053-4236-84BD-AA9BE2E323E5}</ProjectGuid>\r
-    <RootNamespace>DLLStub</RootNamespace>\r
-    <Keyword>Win32Proj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>StaticLibrary</ConfigurationType>\r
-    <UseOfAtl>false</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-    <WholeProgramOptimization>false</WholeProgramOptimization>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>StaticLibrary</ConfigurationType>\r
-    <UseOfAtl>false</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-    <WholeProgramOptimization>false</WholeProgramOptimization>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>StaticLibrary</ConfigurationType>\r
-    <UseOfAtl>false</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-    <WholeProgramOptimization>false</WholeProgramOptimization>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>StaticLibrary</ConfigurationType>\r
-    <UseOfAtl>false</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-    <WholeProgramOptimization>false</WholeProgramOptimization>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">dnssdStatic</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">dnssdStatic</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dnssdStatic</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dnssdStatic</TargetName>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MinimalRebuild>false</MinimalRebuild>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <Lib>\r
-      <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
-    </Lib>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MinimalRebuild>false</MinimalRebuild>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <Lib>\r
-      <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
-    </Lib>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.lib.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <Lib>\r
-      <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
-    </Lib>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-echo F | xcopy /Y "$(OutDir)dnssdStatic.lib"                                                        "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)\dnssd.lib"\r
-xcopy /Y "$(OutDir)dnssd.lib.pdb"                                                                         "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <ProgramDataBaseFileName>$(IntDir)dnssd.lib.pdb</ProgramDataBaseFileName>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <Lib>\r
-      <OutputFile>$(OutDir)dnssdStatic.lib</OutputFile>\r
-    </Lib>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)" mkdir "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-echo F | xcopy /I/Y "$(OutDir)dnssdStatic.lib"                                                     "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)\dnssd.lib"\r
-xcopy /Y "$(OutDir)dnssd.lib.pdb"                                                                         "$(DSTROOT)\Program Files\Bonjour SDK\lib\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="DLLStub.cpp" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="DLLStub.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="ReadMe.txt" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
-      <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
-      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/DLLStub/DLLStub.vcxproj.filters b/mDNSWindows/DLLStub/DLLStub.vcxproj.filters
deleted file mode 100755 (executable)
index 8b6d833..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="DLLStub.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="DLLStub.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="ReadMe.txt" />\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/DLLX/DLLX.cpp b/mDNSWindows/DLLX/DLLX.cpp
deleted file mode 100755 (executable)
index 77883cc..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-
-
-#include "stdafx.h"
-
-#include "resource.h"
-
-#include "DLLX.h"
-
-#include "dlldatax.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-class CDLLComponentModule : public CAtlDllModuleT< CDLLComponentModule >
-
-{
-
-public :
-
-       DECLARE_LIBID(LIBID_Bonjour)
-
-       DECLARE_REGISTRY_APPID_RESOURCEID(IDR_DLLX, "{56608F9C-223B-4CB6-813D-85EDCCADFB4B}")
-
-};
-
-
-
-CDLLComponentModule _AtlModule;
-
-
-
-
-
-#ifdef _MANAGED
-
-#pragma managed(push, off)
-
-#endif
-
-
-
-// DLL Entry Point
-
-extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
-
-{
-
-       debug_initialize( kDebugOutputTypeWindowsDebugger );
-       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
-
-
-
-#ifdef _MERGE_PROXYSTUB
-
-    if (!PrxDllMain(hInstance, dwReason, lpReserved))
-
-        return FALSE;
-
-#endif
-
-       hInstance;
-
-    return _AtlModule.DllMain(dwReason, lpReserved); 
-
-}
-
-
-
-#ifdef _MANAGED
-
-#pragma managed(pop)
-
-#endif
-
-
-
-
-
-
-
-
-
-// Used to determine whether the DLL can be unloaded by OLE
-
-STDAPI DllCanUnloadNow(void)
-
-{
-
-#ifdef _MERGE_PROXYSTUB
-
-    HRESULT hr = PrxDllCanUnloadNow();
-
-    if (hr != S_OK)
-
-        return hr;
-
-#endif
-
-    return _AtlModule.DllCanUnloadNow();
-
-}
-
-
-
-
-
-// Returns a class factory to create an object of the requested type
-
-STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
-
-{
-
-#ifdef _MERGE_PROXYSTUB
-
-    if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)
-
-        return S_OK;
-
-#endif
-
-    return _AtlModule.DllGetClassObject(rclsid, riid, ppv);
-
-}
-
-
-
-
-
-// DllRegisterServer - Adds entries to the system registry
-
-STDAPI DllRegisterServer(void)
-
-{
-
-    // registers object, typelib and all interfaces in typelib
-
-    HRESULT hr = _AtlModule.DllRegisterServer();
-
-#ifdef _MERGE_PROXYSTUB
-
-    if (FAILED(hr))
-
-        return hr;
-
-    hr = PrxDllRegisterServer();
-
-#endif
-
-       return hr;
-
-}
-
-
-
-
-
-// DllUnregisterServer - Removes entries from the system registry
-
-STDAPI DllUnregisterServer(void)
-
-{
-
-       HRESULT hr = _AtlModule.DllUnregisterServer();
-
-#ifdef _MERGE_PROXYSTUB
-
-    if (FAILED(hr))
-
-        return hr;
-
-    hr = PrxDllRegisterServer();
-
-    if (FAILED(hr))
-
-        return hr;
-
-    hr = PrxDllUnregisterServer();
-
-#endif
-
-       return hr;
-
-}
-
-
-
diff --git a/mDNSWindows/DLLX/DLLX.def b/mDNSWindows/DLLX/DLLX.def
deleted file mode 100755 (executable)
index 698b172..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-; -*- Mode: C; tab-width: 4 -*-
-;
-; Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-; 
-;     http://www.apache.org/licenses/LICENSE-2.0
-; 
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-; See the License for the specific language governing permissions and
-; limitations under the License.
-;
-
-
-
-
-
-LIBRARY      "dnssdX.DLL"
-
-
-
-EXPORTS
-
-       DllCanUnloadNow         PRIVATE
-
-       DllGetClassObject       PRIVATE
-
-       DllRegisterServer       PRIVATE
-
-       DllUnregisterServer     PRIVATE
-
diff --git a/mDNSWindows/DLLX/DLLX.idl b/mDNSWindows/DLLX/DLLX.idl
deleted file mode 100755 (executable)
index e44865b..0000000
+++ /dev/null
@@ -1,491 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009-2013 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 will be processed by the MIDL tool to
-
-// produce the type library (DLLComponent.tlb) and marshalling code.
-
-
-
-typedef [ uuid(4085DD59-D0E1-4efe-B6EE-DDBF7631B9C0) ]
-
-enum DNSSDFlags
-
-{
-
-       kDNSSDFlagsMoreComing                   = 0x0001,
-
-       kDNSSDFlagsDefault                              = 0x0004,
-
-       kDNSSDFlagsNoAutoRename                 = 0x0008,
-
-       kDNSSDFlagsShared                               = 0x0010,
-
-       kDNSSDFlagsUnique                               = 0x0020,
-
-       kDNSSDFlagsBrowseDomains                = 0x0040,
-
-       kDNSSDFlagsRegistrationDomains  = 0x0080,
-
-       kDNSSDFlagsLongLivedQuery               = 0x0100,
-
-       kDNSSDFlagsAllowRemoteQuery             = 0x0200,
-
-       kDNSSDFlagsForceMulticast               = 0x0400,
-
-       kDNSSDFlagsForce                                = 0x0800,
-
-       kDNSSDFlagsReturnIntermediates  = 0x1000,
-
-       kDNSSDFlagsNonBrowsable                 = 0x2000
-
-} DNSSDFlags;
-
-
-
-
-
-typedef [ uuid(30CDF335-CA52-4b17-AFF2-E83C64C450D4) ]
-
-enum DNSSDAddressFamily
-
-{
-
-       kDNSSDAddressFamily_IPv4 = 0x1,
-
-       kDNSSDAddressFamily_IPv6 = 0x2
-
-} DNSSDAddressFamily;
-
-
-
-
-
-typedef [ uuid(98FB4702-7374-4b16-A8DB-AD35BFB8364D) ]
-
-enum DNSSDProtocol
-
-{
-
-       kDNSSDProtocol_UDP      = 0x10,
-
-       kDNSSDProtocol_TCP      = 0x20
-
-} DNSSDProtocol;
-
-
-
-
-
-typedef [ uuid(72BF3EC3-19BC-47e5-8D95-3B73FF37D893) ]
-
-enum DNSSDRRClass
-
-{
-
-       kDNSSDClass_IN = 1
-
-} DNSSDRRClass;
-
-
-
-
-
-typedef [ uuid(08E362DF-5468-4c9a-AC66-FD4747B917BD) ]
-
-enum DNSSDRRType
-
-{
-
-       kDNSSDType_A         = 1,
-    kDNSSDType_NS        = 2,
-    kDNSSDType_MD        = 3,
-    kDNSSDType_MF        = 4,
-    kDNSSDType_CNAME     = 5,
-    kDNSSDType_SOA       = 6,
-    kDNSSDType_MB        = 7,
-    kDNSSDType_MG        = 8,
-    kDNSSDType_MR        = 9,
-    kDNSSDType_NULL      = 10,
-    kDNSSDType_WKS       = 11,
-    kDNSSDType_PTR       = 12,
-    kDNSSDType_HINFO     = 13,
-    kDNSSDType_MINFO     = 14,
-    kDNSSDType_MX        = 15,
-    kDNSSDType_TXT       = 16,
-    kDNSSDType_RP        = 17,
-    kDNSSDType_AFSDB     = 18,
-    kDNSSDType_X25       = 19,
-    kDNSSDType_ISDN      = 20,
-    kDNSSDType_RT        = 21,
-    kDNSSDType_NSAP      = 22,
-    kDNSSDType_NSAP_PTR  = 23,
-    kDNSSDType_SIG       = 24,
-    kDNSSDType_KEY       = 25,
-    kDNSSDType_PX        = 26,
-    kDNSSDType_GPOS      = 27,
-    kDNSSDType_AAAA      = 28,
-    kDNSSDType_LOC       = 29,
-    kDNSSDType_NXT       = 30,
-    kDNSSDType_EID       = 31,
-    kDNSSDType_NIMLOC    = 32,
-    kDNSSDType_SRV       = 33,
-    kDNSSDType_ATMA      = 34,
-    kDNSSDType_NAPTR     = 35,
-    kDNSSDType_KX        = 36,
-    kDNSSDType_CERT      = 37,
-    kDNSSDType_A6        = 38,
-    kDNSSDType_DNAME     = 39,
-    kDNSSDType_SINK      = 40,
-    kDNSSDType_OPT       = 41,
-    kDNSSDType_APL       = 42,
-    kDNSSDType_DS        = 43,
-    kDNSSDType_SSHFP     = 44,
-    kDNSSDType_IPSECKEY  = 45,
-    kDNSSDType_RRSIG     = 46,
-    kDNSSDType_NSEC      = 47,
-    kDNSSDType_DNSKEY    = 48,
-    kDNSSDType_DHCID     = 49,
-    kDNSSDType_NSEC3     = 50,
-    kDNSSDType_NSEC3PARAM= 51,
-    kDNSSDType_HIP       = 55,
-    kDNSSDType_SPF       = 99,
-    kDNSSDType_UINFO     = 100,
-    kDNSSDType_UID       = 101,
-    kDNSSDType_GID       = 102,
-    kDNSSDType_UNSPEC    = 103,
-    kDNSSDType_TKEY      = 249,
-    kDNSSDType_TSIG      = 250,
-    kDNSSDType_IXFR      = 251,
-    kDNSSDType_AXFR      = 252,
-    kDNSSDType_MAILB     = 253,
-    kDNSSDType_MAILA     = 254,
-    kDNSSDType_ANY       = 255
-
-} DNSSDRRType;
-
-
-
-
-
-typedef [ uuid(3B0059E7-5297-4301-9AAB-1522F31EC8A7) ]
-
-enum DNSSDError
-{
-       kDNSSDError_NoError                   = 0,
-       kDNSSDError_Unknown                   = -65537,
-       kDNSSDError_NoSuchName                = -65538,
-    kDNSSDError_NoMemory                  = -65539,
-    kDNSSDError_BadParam                  = -65540,
-    kDNSSDError_BadReference              = -65541,
-    kDNSSDError_BadState                  = -65542,
-    kDNSSDError_BadFlags                  = -65543,
-    kDNSSDError_Unsupported               = -65544,
-    kDNSSDError_NotInitialized            = -65545,
-    kDNSSDError_AlreadyRegistered         = -65547,
-    kDNSSDError_NameConflict              = -65548,
-    kDNSSDError_Invalid                   = -65549,
-    kDNSSDError_Firewall                  = -65550,
-    kDNSSDError_Incompatible              = -65551,
-    kDNSSDError_BadInterfaceIndex         = -65552,
-    kDNSSDError_Refused                   = -65553,
-    kDNSSDError_NoSuchRecord              = -65554,
-    kDNSSDError_NoAuth                    = -65555,
-    kDNSSDError_NoSuchKey                 = -65556,
-    kDNSSDError_NATTraversal              = -65557,
-    kDNSSDError_DoubleNAT                 = -65558,
-    kDNSSDError_BadTime                   = -65559,
-    kDNSSDError_BadSig                    = -65560,
-    kDNSSDError_BadKey                    = -65561,
-    kDNSSDError_Transient                 = -65562,
-    kDNSSDError_ServiceNotRunning         = -65563,  /* Background daemon not running */
-    kDNSSDError_NATPortMappingUnsupported = -65564,  /* NAT doesn't support PCP, NAT-PMP or UPnP */
-    kDNSSDError_NATPortMappingDisabled    = -65565,  /* NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator */
-    kDNSSDError_NoRouter                  = -65566,  /* No router currently configured (probably no network connectivity) */
-    kDNSSDError_PollingMode               = -65567
-} DNSSDError;
-
-
-
-import "oaidl.idl";
-
-import "ocidl.idl";
-
-
-
-
-
-[
-
-       object,
-
-       uuid(8FA0889C-5973-4FC9-970B-EC15C925D0CE),
-
-       dual,
-
-       nonextensible,
-
-       helpstring("ITXTRecord Interface"),
-
-       pointer_default(unique)
-
-]
-
-interface ITXTRecord : IDispatch{
-
-       [id(1), helpstring("method SetValue")] HRESULT SetValue([in] BSTR key, [in] VARIANT value);
-
-       [id(2), helpstring("method RemoveValue")] HRESULT RemoveValue([in] BSTR key);
-
-       [id(3), helpstring("method ContainsKey")] HRESULT ContainsKey([in] BSTR key, [out,retval] VARIANT_BOOL* retval);
-
-       [id(4), helpstring("method GetValueForKey")] HRESULT GetValueForKey([in] BSTR key, [out,retval] VARIANT* value);
-
-       [id(5), helpstring("method GetCount")] HRESULT GetCount([out,retval] ULONG* count);
-
-       [id(6), helpstring("method GetKeyAtIndex")] HRESULT GetKeyAtIndex([in] ULONG index, [out,retval] BSTR* retval);
-
-       [id(7), helpstring("method GetValueAtIndex")] HRESULT GetValueAtIndex([in] ULONG index, [out,retval] VARIANT* retval);
-
-};
-
-[
-
-       object,
-
-       uuid(9CE603A0-3365-4DA0-86D1-3F780ECBA110),
-
-       dual,
-
-       nonextensible,
-
-       helpstring("IDNSSDRecord Interface"),
-
-       pointer_default(unique)
-
-]
-
-interface IDNSSDRecord : IDispatch{
-
-       [id(1), helpstring("method Update")] HRESULT Update([in] DNSSDFlags flags, [in] VARIANT rdata, [in] ULONG ttl);
-
-       [id(2), helpstring("method Remove")] HRESULT Remove([in] DNSSDFlags flags);
-
-};
-
-[
-
-       object,
-
-       uuid(7FD72324-63E1-45AD-B337-4D525BD98DAD),
-
-       dual,
-
-       nonextensible,
-
-       helpstring("IDNSSDEventManager Interface"),
-
-       pointer_default(unique)
-
-]
-
-interface IDNSSDEventManager : IDispatch{
-
-};
-
-[
-
-       object,
-
-       uuid(29DE265F-8402-474F-833A-D4653B23458F),
-
-       dual,
-
-       nonextensible,
-
-       helpstring("IDNSSDService Interface"),
-
-       pointer_default(unique)
-
-]
-
-interface IDNSSDService : IDispatch{
-
-       [id(1), helpstring("method EnumerateDomains")] HRESULT EnumerateDomains([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
-
-       [id(2), helpstring("method Browse"), local] HRESULT Browse([in] DNSSDFlags flags, [in] ULONG interfaceIndex, [in] BSTR regtype, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** sdref);
-
-       [id(3), helpstring("method Resolve")] HRESULT Resolve([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
-
-       [id(4), helpstring("method Register")] HRESULT Register([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR name, [in] BSTR regType, [in] BSTR domain, [in] BSTR host, [in] USHORT port, [in] ITXTRecord* record, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
-
-       [id(5), helpstring("method QueryRecord")] HRESULT QueryRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
-
-       [id(6), helpstring("method RegisterRecord")] HRESULT RegisterRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDRecord** record);
-
-       [id(7), helpstring("method AddRecord")] HRESULT AddRecord([in] DNSSDFlags flags, [in] DNSSDRRType rrtype, [in] VARIANT rdata, [in] ULONG ttl, [out,retval] IDNSSDRecord** record);
-
-       [id(8), helpstring("method ReconfirmRecord")] HRESULT ReconfirmRecord([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullname, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata);
-
-       [id(9), helpstring("method GetProperty")] HRESULT GetProperty([in] BSTR prop, [in,out] VARIANT * value );       
-
-       [id(10), helpstring("method GetAddrInfo")] HRESULT GetAddrInfo([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] BSTR hostname, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
-
-       [id(11), helpstring("method NATPortMappingCreate")] HRESULT NATPortMappingCreate([in] DNSSDFlags flags, [in] ULONG ifIndex, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl, [in] IDNSSDEventManager* eventManager, [out,retval] IDNSSDService** service);
-
-       [id(12), helpstring("method Stop"), local] HRESULT Stop(void);
-
-};
-
-[
-
-       uuid(18FBED6D-F2B7-4EC8-A4A4-46282E635308),
-
-       version(1.0),
-
-       helpstring("Apple Bonjour Library 1.0")
-
-]
-
-library Bonjour
-
-{
-
-       importlib("stdole2.tlb");
-
-       [
-
-               uuid(21AE8D7F-D5FE-45cf-B632-CFA2C2C6B498),
-
-               helpstring("_IDNSSDEvents Interface")
-
-       ]
-
-       dispinterface _IDNSSDEvents
-
-       {
-
-               properties:
-
-               methods:
-
-               [id(1), helpstring("method DomainFound")] void DomainFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain);
-
-               [id(2), helpstring("method DomainLost")] void DomainLost([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR domain);
-
-               [id(3), helpstring("method ServiceFound")] void ServiceFound([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain);
-
-               [id(4), helpstring("method ServiceLost")] void ServiceLost([in] IDNSSDService* browser, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR serviceName, [in] BSTR regType, [in] BSTR domain);
-
-               [id(5), helpstring("method ServiceResolved")] void ServiceResolved([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] BSTR hostName, [in] USHORT port, [in] ITXTRecord* record);
-
-               [id(6), helpstring("method ServiceRegistered")] void ServiceRegistered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] BSTR name, [in] BSTR regType, [in] BSTR domain);
-
-               [id(7), helpstring("method QueryRecordAnswered")] void QueryRecordAnswered([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR fullName, [in] DNSSDRRType rrtype, [in] DNSSDRRClass rrclass, [in] VARIANT rdata, [in] ULONG ttl);
-
-               [id(8), helpstring("method RecordRegistered")] void RecordRegistered([in] IDNSSDRecord* record, [in] DNSSDFlags flags);
-
-               [id(9), helpstring("method AddressFound")] void AddressFound([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] BSTR hostname, [in] DNSSDAddressFamily addressFamily, [in] BSTR address, [in] ULONG ttl);
-
-               [id(10), helpstring("method MappingCreated")] void MappingCreated([in] IDNSSDService* service, [in] DNSSDFlags flags, [in] ULONG ifIndex, [in] ULONG externalAddress, [in] DNSSDAddressFamily addressFamily, [in] DNSSDProtocol protocol, [in] USHORT internalPort, [in] USHORT externalPort, [in] ULONG ttl);
-
-               [id(11), helpstring("method OperationFailed")] void OperationFailed([in] IDNSSDService* service, [in] DNSSDError error);
-
-       };
-
-       [
-
-               uuid(24CD4DE9-FF84-4701-9DC1-9B69E0D1090A),
-
-               helpstring("DNSSDService Class")
-
-       ]
-
-       coclass DNSSDService
-
-       {
-
-               [default] interface IDNSSDService;
-
-       };
-
-       [
-
-               uuid(AFEE063C-05BA-4248-A26E-168477F49734),
-
-               helpstring("TXTRecord Class")
-
-       ]
-
-       coclass TXTRecord
-
-       {
-
-               [default] interface ITXTRecord;
-
-       };
-
-       [
-
-               uuid(5E93C5A9-7516-4259-A67B-41A656F6E01C),
-
-               helpstring("DNSSDRecord Class")
-
-       ]
-
-       coclass DNSSDRecord
-
-       {
-
-               [default] interface IDNSSDRecord;
-
-       };
-
-       [
-
-               uuid(BEEB932A-8D4A-4619-AEFE-A836F988B221),
-
-               helpstring("DNSSDEventManager Class")
-
-       ]
-
-       coclass DNSSDEventManager
-
-       {
-
-               [default] interface IDNSSDEventManager;
-
-               [default, source] dispinterface _IDNSSDEvents;
-
-       };
-
-       enum DNSSDFlags;
-
-       enum DNSSDAddressFamily;
-
-       enum DNSSDProtocol;
-
-       enum DNSSDRRClass;
-
-       enum DNSSDRRType;
-
-       enum DNSSDError;
-
-};
-
diff --git a/mDNSWindows/DLLX/DLLX.rc b/mDNSWindows/DLLX/DLLX.rc
deleted file mode 100755 (executable)
index 4299b5a..0000000
+++ /dev/null
@@ -1,126 +0,0 @@
-// 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 "winres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
-    "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
-    "#include ""winres.h""\r\n"\r
-    "#include ""WinVersRes.h""\r\n"\r
-    "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
-    "1 TYPELIB ""BonjourLib.tlb""\r\n"\r
-    "\0"\r
-END\r
-\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x3fL\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x2L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
-    BLOCK "StringFileInfo"\r
-    BEGIN\r
-        BLOCK "040904e4"\r
-        BEGIN\r
-            VALUE "CompanyName", MASTER_COMPANY_NAME\r
-            VALUE "FileDescription", "Bonjour COM Component Library"\r
-            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
-            VALUE "InternalName", "dnssdX.dll"\r
-            VALUE "OriginalFilename", "dnssdX.dll"\r
-            VALUE "ProductName", MASTER_PROD_NAME\r
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
-        END\r
-    END\r
-    BLOCK "VarFileInfo"\r
-    BEGIN\r
-        VALUE "Translation", 0x409, 1252\r
-    END\r
-END\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// REGISTRY\r
-//\r
-\r
-IDR_DLLX                       REGISTRY                "DLLX.rgs"\r
-IDR_DNSSDSERVICE        REGISTRY                "DNSSDService.rgs"\r
-IDR_TXTRECORD           REGISTRY                "TXTRecord.rgs"\r
-IDR_DNSSDRECORD         REGISTRY                "DNSSDRecord.rgs"\r
-IDR_DNSSDEVENTMANAGER   REGISTRY                "DNSSDEventManager.rgs"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// String Table\r
-//\r
-\r
-STRINGTABLE \r
-BEGIN\r
-    IDS_PROJNAME            "BonjourLib"\r
-END\r
-\r
-#endif    // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-1 TYPELIB "dnssdX.tlb"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif    // not APSTUDIO_INVOKED\r
-\r
diff --git a/mDNSWindows/DLLX/DLLX.rgs b/mDNSWindows/DLLX/DLLX.rgs
deleted file mode 100755 (executable)
index c55ee8d..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-HKCR\r
-{\r
-       NoRemove AppID\r
-       {\r
-               '%APPID%' = s 'Bonjour'\r
-               'Bonjour.DLL'\r
-               {\r
-                       val AppID = s '%APPID%'\r
-               }\r
-       }\r
-}\r
diff --git a/mDNSWindows/DLLX/DLLX.vcproj b/mDNSWindows/DLLX/DLLX.vcproj
deleted file mode 100755 (executable)
index 7c58b0a..0000000
+++ /dev/null
@@ -1,625 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="DLLX"\r
-       ProjectGUID="{78FBFCC5-2873-4AE2-9114-A08082F71124}"\r
-       RootNamespace="DLLX"\r
-       Keyword="AtlProj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       UseOfMFC="0"\r
-                       UseOfATL="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="1"\r
-                               GenerateStublessProxies="true"\r
-                               TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
-                               HeaderFileName="DLLX.h"\r
-                               DLLDataFileName=""\r
-                               InterfaceIdentifierFileName="DLLX_i.c"\r
-                               ProxyFileName="DLLX_p.c"\r
-                               ValidateParameters="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               MinimalRebuild="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               RegisterOutput="true"\r
-                               IgnoreImportLibrary="true"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
-                               OutputFile="$(OutDir)\dnssdX.dll"\r
-                               LinkIncremental="2"\r
-                               ModuleDefinitionFile=".\DLLX.def"\r
-                               GenerateDebugInformation="true"\r
-                               SubSystem="2"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       UseOfMFC="0"\r
-                       UseOfATL="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="3"\r
-                               GenerateStublessProxies="true"\r
-                               TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
-                               HeaderFileName="DLLX.h"\r
-                               DLLDataFileName=""\r
-                               InterfaceIdentifierFileName="DLLX_i.c"\r
-                               ProxyFileName="DLLX_p.c"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               MinimalRebuild="true"\r
-                               BasicRuntimeChecks="3"\r
-                               RuntimeLibrary="1"\r
-                               UsePrecompiledHeader="0"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="_DEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               RegisterOutput="true"\r
-                               IgnoreImportLibrary="true"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
-                               OutputFile="$(OutDir)\dnssdX.dll"\r
-                               LinkIncremental="2"\r
-                               ModuleDefinitionFile=".\DLLX.def"\r
-                               GenerateDebugInformation="true"\r
-                               SubSystem="2"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       UseOfATL="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="1"\r
-                               GenerateStublessProxies="true"\r
-                               TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
-                               HeaderFileName="DLLX.h"\r
-                               DLLDataFileName=""\r
-                               InterfaceIdentifierFileName="DLLX_i.c"\r
-                               ProxyFileName="DLLX_p.c"\r
-                               ValidateParameters="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               RegisterOutput="false"\r
-                               IgnoreImportLibrary="true"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
-                               OutputFile="$(OutDir)\dnssdX.dll"\r
-                               LinkIncremental="1"\r
-                               ModuleDefinitionFile=".\DLLX.def"\r
-                               GenerateDebugInformation="true"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;             mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                            &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       UseOfATL="1"\r
-                       ATLMinimizesCRunTimeLibraryUsage="false"\r
-                       CharacterSet="1"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               MkTypLibCompatible="false"\r
-                               TargetEnvironment="3"\r
-                               GenerateStublessProxies="true"\r
-                               TypeLibraryName="$(IntDir)/dnssdX.tlb"\r
-                               HeaderFileName="DLLX.h"\r
-                               DLLDataFileName=""\r
-                               InterfaceIdentifierFileName="DLLX_i.c"\r
-                               ProxyFileName="DLLX_p.c"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="2"\r
-                               AdditionalIncludeDirectories="..\..\mDNSShared;..\..\mDNSWindows"\r
-                               PreprocessorDefinitions="WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               WarningLevel="3"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               PreprocessorDefinitions="NDEBUG"\r
-                               Culture="1033"\r
-                               AdditionalIncludeDirectories="..;&quot;$(IntDir)&quot;"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               RegisterOutput="false"\r
-                               IgnoreImportLibrary="true"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="ws2_32.lib ../../mDNSWindows/DLLStub/$(PlatformName)/$(ConfigurationName)/dnssdStatic.lib"\r
-                               OutputFile="$(OutDir)\dnssdX.dll"\r
-                               LinkIncremental="1"\r
-                               ModuleDefinitionFile=".\DLLX.def"\r
-                               GenerateDebugInformation="true"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;             mkdir &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                            &quot;$(DSTROOT)\WINDOWS\system32\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\dlldatax.c"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DLLX.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DLLX.def"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DLLX.idl"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDEventManager.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDRecord.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDService.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\TXTRecord.cpp"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\_IDNSSDEvents_CP.H"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\dlldatax.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDEventManager.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDRecord.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDService.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\Resource.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\stdafx.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\TXTRecord.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"\r
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\DLLX.rc"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DLLX.rgs"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDEventManager.rgs"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDRecord.rgs"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DNSSDService.rgs"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\TXTRecord.rgs"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Generated Files"\r
-                       SourceControlFiles="false"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\DLLX.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\DLLX_i.c"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCLCompilerTool"\r
-                                               UsePrecompiledHeader="0"\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Support Files"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\CommonServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\StringServices.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\StringServices.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/DLLX/DLLX.vcxproj b/mDNSWindows/DLLX/DLLX.vcxproj
deleted file mode 100755 (executable)
index a57e4ed..0000000
+++ /dev/null
@@ -1,328 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{78FBFCC5-2873-4AE2-9114-A08082F71124}</ProjectGuid>\r
-    <RootNamespace>DLLX</RootNamespace>\r
-    <Keyword>AtlProj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfAtl>Static</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>false</UseOfMfc>\r
-    <UseOfAtl>Static</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfAtl>Static</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <UseOfMfc>false</UseOfMfc>\r
-    <UseOfAtl>Static</UseOfAtl>\r
-    <CharacterSet>Unicode</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</IgnoreImportLibrary>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</IgnoreImportLibrary>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</IgnoreImportLibrary>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">dnssdX</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">dnssdX</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">dnssdX</TargetName>\r
-    <TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dnssdX</TargetName>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <GenerateStublessProxies>true</GenerateStublessProxies>\r
-      <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
-      <HeaderFileName>DLLX.h</HeaderFileName>\r
-      <DllDataFileName>\r
-      </DllDataFileName>\r
-      <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
-      <ProxyFileName>DLLX_p.c</ProxyFileName>\r
-      <ValidateAllParameters>false</ValidateAllParameters>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <RegisterOutput>true</RegisterOutput>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
-      <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <SubSystem>Windows</SubSystem>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-      <GenerateStublessProxies>true</GenerateStublessProxies>\r
-      <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
-      <HeaderFileName>DLLX.h</HeaderFileName>\r
-      <DllDataFileName>\r
-      </DllDataFileName>\r
-      <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
-      <ProxyFileName>DLLX_p.c</ProxyFileName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;_USRDLL;_MERGE_PROXYSTUB;DEBUG=1;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <RegisterOutput>false</RegisterOutput>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
-      <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <SubSystem>Windows</SubSystem>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-      <TargetEnvironment>Win32</TargetEnvironment>\r
-      <GenerateStublessProxies>true</GenerateStublessProxies>\r
-      <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
-      <HeaderFileName>DLLX.h</HeaderFileName>\r
-      <DllDataFileName>\r
-      </DllDataFileName>\r
-      <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
-      <ProxyFileName>DLLX_p.c</ProxyFileName>\r
-      <ValidateAllParameters>false</ValidateAllParameters>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <RegisterOutput>false</RegisterOutput>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
-      <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)"             mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                            "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <MkTypLibCompatible>false</MkTypLibCompatible>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-      <GenerateStublessProxies>true</GenerateStublessProxies>\r
-      <TypeLibraryName>$(IntDir)dnssdX.tlb</TypeLibraryName>\r
-      <HeaderFileName>DLLX.h</HeaderFileName>\r
-      <DllDataFileName>\r
-      </DllDataFileName>\r
-      <InterfaceIdentifierFileName>DLLX_i.c</InterfaceIdentifierFileName>\r
-      <ProxyFileName>DLLX_p.c</ProxyFileName>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>MaxSpeed</Optimization>\r
-      <AdditionalIncludeDirectories>..\..\mDNSShared;..\..\mDNSWindows;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;_USRDLL;_MERGE_PROXYSTUB;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <WarningLevel>Level3</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <Culture>0x0409</Culture>\r
-      <AdditionalIncludeDirectories>..;$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <RegisterOutput>false</RegisterOutput>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;../../mDNSWindows/DLLStub/$(Platform)/$(Configuration)/dnssdStatic.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)dnssdX.dll</OutputFile>\r
-      <ModuleDefinitionFile>.\DLLX.def</ModuleDefinitionFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\WINDOWS\system32\$(Platform)"             mkdir "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                            "$(DSTROOT)\WINDOWS\system32\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="dlldatax.c">\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-      </PrecompiledHeader>\r
-    </ClCompile>\r
-    <ClCompile Include="DLLX.cpp" />\r
-    <ClCompile Include="DNSSDEventManager.cpp" />\r
-    <ClCompile Include="DNSSDRecord.cpp" />\r
-    <ClCompile Include="DNSSDService.cpp" />\r
-    <ClCompile Include="TXTRecord.cpp" />\r
-    <ClCompile Include="DLLX_i.c">\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-      </PrecompiledHeader>\r
-      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-      </PrecompiledHeader>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
-    <ClCompile Include="StringServices.cpp" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="DLLX.def" />\r
-    <None Include="DLLX.rgs" />\r
-    <None Include="DNSSDEventManager.rgs" />\r
-    <None Include="DNSSDRecord.rgs" />\r
-    <None Include="DNSSDService.rgs" />\r
-    <None Include="TXTRecord.rgs" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <Midl Include="DLLX.idl" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="_IDNSSDEvents_CP.H" />\r
-    <ClInclude Include="dlldatax.h" />\r
-    <ClInclude Include="DNSSDEventManager.h" />\r
-    <ClInclude Include="DNSSDRecord.h" />\r
-    <ClInclude Include="DNSSDService.h" />\r
-    <ClInclude Include="Resource.h" />\r
-    <ClInclude Include="stdafx.h" />\r
-    <ClInclude Include="TXTRecord.h" />\r
-    <ClInclude Include="DLLX.h" />\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
-    <ClInclude Include="StringServices.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="DLLX.rc" />\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/DLLX/DLLX.vcxproj.filters b/mDNSWindows/DLLX/DLLX.vcxproj.filters
deleted file mode 100755 (executable)
index 54f4be6..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>\r
-    </Filter>\r
-    <Filter Include="Generated Files">\r
-      <UniqueIdentifier>{f6bd0810-64ce-4840-9a29-d80d06414fcf}</UniqueIdentifier>\r
-      <SourceControlFiles>False</SourceControlFiles>\r
-    </Filter>\r
-    <Filter Include="Support Files">\r
-      <UniqueIdentifier>{0756c4a0-cd93-4f7e-a376-dc55c520a2d0}</UniqueIdentifier>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="dlldatax.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="DLLX.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="DNSSDEventManager.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="DNSSDRecord.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="DNSSDService.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="TXTRecord.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="DLLX_i.c">\r
-      <Filter>Generated Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
-      <Filter>Support Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="StringServices.cpp">\r
-      <Filter>Support Files</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="DLLX.def">\r
-      <Filter>Source Files</Filter>\r
-    </None>\r
-    <None Include="DLLX.rgs">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="DNSSDEventManager.rgs">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="DNSSDRecord.rgs">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="DNSSDService.rgs">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-    <None Include="TXTRecord.rgs">\r
-      <Filter>Resource Files</Filter>\r
-    </None>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <Midl Include="DLLX.idl">\r
-      <Filter>Source Files</Filter>\r
-    </Midl>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="_IDNSSDEvents_CP.H">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="dlldatax.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="DNSSDEventManager.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="DNSSDRecord.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="DNSSDService.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="Resource.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="stdafx.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="TXTRecord.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="DLLX.h">\r
-      <Filter>Generated Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
-      <Filter>Support Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
-      <Filter>Support Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="StringServices.h">\r
-      <Filter>Support Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="DLLX.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/DLLX/DNSSD.cpp b/mDNSWindows/DLLX/DNSSD.cpp
deleted file mode 100755 (executable)
index f011dd1..0000000
+++ /dev/null
@@ -1,892 +0,0 @@
-// DNSSD.cpp : Implementation of CDNSSD
-
-#include "stdafx.h"
-#include "DNSSD.h"
-#include "DNSSDService.h"
-#include "TXTRecord.h"
-#include <dns_sd.h>
-#include <CommonServices.h>
-#include <DebugServices.h>
-#include "StringServices.h"
-
-
-// CDNSSD
-
-STDMETHODIMP CDNSSD::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IBrowseListener* listener, IDNSSDService** browser )
-{
-       CComObject<CDNSSDService>       *       object          = NULL;
-       std::string                                             regtypeUTF8;
-       std::string                                             domainUTF8;
-       DNSServiceRef                                   sref            = NULL;
-       DNSServiceErrorType                             err                     = 0;
-       HRESULT                                                 hr                      = 0;
-       BOOL                                                    ok;
-
-       // Initialize
-       *browser = NULL;
-
-       // Convert BSTR params to utf8
-       ok = BSTRToUTF8( regtype, regtypeUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-       ok = BSTRToUTF8( domain, domainUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       err = DNSServiceBrowse( &sref, flags, ifIndex, regtypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceBrowseReply ) &BrowseReply, object );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-       object->SetListener( listener );
-
-       err = object->Run();
-       require_noerr( err, exit );
-
-       *browser = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IResolveListener* listener, IDNSSDService** service)
-{
-       CComObject<CDNSSDService>       *       object                  = NULL;
-       std::string                                             serviceNameUTF8;
-       std::string                                             regTypeUTF8;
-       std::string                                             domainUTF8;
-       DNSServiceRef                                   sref                    = NULL;
-       DNSServiceErrorType                             err                             = 0;
-       HRESULT                                                 hr                              = 0;
-       BOOL                                                    ok;
-
-       // Initialize
-       *service = NULL;
-
-       // Convert BSTR params to utf8
-       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-       ok = BSTRToUTF8( regType, regTypeUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-       ok = BSTRToUTF8( domain, domainUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       err = DNSServiceResolve( &sref, flags, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-       object->SetListener( listener );
-
-       err = object->Run();
-       require_noerr( err, exit );
-
-       *service = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDomainListener *listener, IDNSSDService **service)
-{
-       CComObject<CDNSSDService>       *       object                  = NULL;
-       DNSServiceRef                                   sref                    = NULL;
-       DNSServiceErrorType                             err                             = 0;
-       HRESULT                                                 hr                              = 0;
-
-       // Initialize
-       *service = NULL;
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       err = DNSServiceEnumerateDomains( &sref, flags, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-       object->SetListener( listener );
-
-       err = object->Run();
-       require_noerr( err, exit );
-
-       *service = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IRegisterListener *listener, IDNSSDService **service)
-{
-       CComObject<CDNSSDService>       *       object                  = NULL;
-       std::string                                             serviceNameUTF8;
-       std::string                                             regTypeUTF8;
-       std::string                                             domainUTF8;
-       std::string                                             hostUTF8;
-       const void                                      *       txtRecord               = NULL;
-       uint16_t                                                txtLen                  = 0;
-       DNSServiceRef                                   sref                    = NULL;
-       DNSServiceErrorType                             err                             = 0;
-       HRESULT                                                 hr                              = 0;
-       BOOL                                                    ok;
-
-       // Initialize
-       *service = NULL;
-
-       // Convert BSTR params to utf8
-       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-       ok = BSTRToUTF8( regType, regTypeUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-       ok = BSTRToUTF8( domain, domainUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-       ok = BSTRToUTF8( host, hostUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       if ( record )
-       {
-               CComObject< CTXTRecord > * realTXTRecord;
-
-               realTXTRecord = ( CComObject< CTXTRecord >* ) record;
-
-               txtRecord       = realTXTRecord->GetBytes();
-               txtLen          = realTXTRecord->GetLen();
-       }
-
-       err = DNSServiceRegister( &sref, flags, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), hostUTF8.c_str(), port, txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-       object->SetListener( listener );
-
-       err = object->Run();
-       require_noerr( err, exit );
-
-       *service = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IQueryRecordListener *listener, IDNSSDService **service)
-{
-       CComObject<CDNSSDService>       *       object                  = NULL;
-       DNSServiceRef                                   sref                    = NULL;
-       std::string                                             fullNameUTF8;
-       DNSServiceErrorType                             err                             = 0;
-       HRESULT                                                 hr                              = 0;
-       BOOL                                                    ok;
-
-       // Initialize
-       *service = NULL;
-
-       // Convert BSTR params to utf8
-       ok = BSTRToUTF8( fullname, fullNameUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       err = DNSServiceQueryRecord( &sref, flags, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-       object->SetListener( listener );
-
-       err = object->Run();
-       require_noerr( err, exit );
-
-       *service = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IGetAddrInfoListener *listener, IDNSSDService **service)
-{
-       CComObject<CDNSSDService>       *       object                  = NULL;
-       DNSServiceRef                                   sref                    = NULL;
-       std::string                                             hostNameUTF8;
-       DNSServiceErrorType                             err                             = 0;
-       HRESULT                                                 hr                              = 0;
-       BOOL                                                    ok;
-
-       // Initialize
-       *service = NULL;
-
-       // Convert BSTR params to utf8
-       ok = BSTRToUTF8( hostName, hostNameUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       err = DNSServiceGetAddrInfo( &sref, flags, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-       object->SetListener( listener );
-
-       err = object->Run();
-       require_noerr( err, exit );
-
-       *service = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::CreateConnection(IDNSSDService **service)
-{
-       CComObject<CDNSSDService>       *       object  = NULL;
-       DNSServiceRef                                   sref    = NULL;
-       DNSServiceErrorType                             err             = 0;
-       HRESULT                                                 hr              = 0;
-
-       // Initialize
-       *service = NULL;
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       err = DNSServiceCreateConnection( &sref );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-
-       *service = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, INATPortMappingListener *listener, IDNSSDService **service)
-{
-       CComObject<CDNSSDService>       *       object                  = NULL;
-       DNSServiceRef                                   sref                    = NULL;
-       DNSServiceProtocol                              prot                    = 0;
-       DNSServiceErrorType                             err                             = 0;
-       HRESULT                                                 hr                              = 0;
-
-       // Initialize
-       *service = NULL;
-
-       try
-       {
-               object = new CComObject<CDNSSDService>();
-       }
-       catch ( ... )
-       {
-               object = NULL;
-       }
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-       hr = object->FinalConstruct();
-       require_action( hr == S_OK, exit, err = kDNSServiceErr_Unknown );
-       object->AddRef();
-
-       prot = ( addressFamily | protocol );
-
-       err = DNSServiceNATPortMappingCreate( &sref, flags, ifIndex, prot, internalPort, externalPort, ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object );
-       require_noerr( err, exit );
-
-       object->SetServiceRef( sref );
-       object->SetListener( listener );
-
-       err = object->Run();
-       require_noerr( err, exit );
-
-       *service = object;
-
-exit:
-
-       if ( err && object )
-       {
-               object->Release();
-       }
-
-       return err;
-}
-
-
-STDMETHODIMP CDNSSD::GetProperty(BSTR prop, VARIANT * value )
-{
-       std::string                     propUTF8;
-       std::vector< BYTE >     byteArray;
-       SAFEARRAY               *       psa                     = NULL;
-       BYTE                    *       pData           = NULL;
-       uint32_t                        elems           = 0;
-       DNSServiceErrorType     err                     = 0;
-       BOOL                            ok = TRUE;
-
-       // Convert BSTR params to utf8
-       ok = BSTRToUTF8( prop, propUTF8 );
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       // Setup the byte array
-       require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown );
-       psa = V_ARRAY( value );
-       require_action( psa, exit, err = kDNSServiceErr_Unknown );
-       require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown );
-       byteArray.reserve( psa->rgsabound[0].cElements );
-       byteArray.assign( byteArray.capacity(), 0 );
-       elems = ( uint32_t ) byteArray.capacity();
-
-       // Call the function and package the return value in the Variant
-       err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems );
-       require_noerr( err, exit );
-       ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value );
-       require_action( ok, exit, err = kDNSSDError_Unknown );
-
-exit:
-
-       if ( psa )
-       {
-               SafeArrayUnaccessData( psa );
-               psa = NULL;
-       }
-
-       return err;
-}
-
-
-void DNSSD_API
-CDNSSD::DomainEnumReply
-    (
-    DNSServiceRef                       sdRef,
-    DNSServiceFlags                     flags,
-    uint32_t                            ifIndex,
-    DNSServiceErrorType                 errorCode,
-    const char                          *replyDomainUTF8,
-    void                                *context
-    )
-{
-       CComObject<CDNSSDService> * service;
-       int err;
-       
-       service = ( CComObject< CDNSSDService>* ) context;
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-       if ( !service->Stopped() )
-       {
-               IDomainListener * listener;
-
-               listener = ( IDomainListener* ) service->GetListener();
-               require_action( listener, exit, err = kDNSServiceErr_Unknown );
-
-               if ( !errorCode )
-               {
-                       CComBSTR replyDomain;
-               
-                       UTF8ToBSTR( replyDomainUTF8, replyDomain );
-
-                       if ( flags & kDNSServiceFlagsAdd )
-                       {
-                               listener->DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
-                       }
-                       else
-                       {
-                               listener->DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
-                       }
-               }
-               else
-               {
-                       listener->EnumDomainsFailed( service, ( DNSSDError ) errorCode );
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-void DNSSD_API
-CDNSSD::BrowseReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            ifIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *serviceNameUTF8,
-               const char                          *regTypeUTF8,
-               const char                          *replyDomainUTF8,
-               void                                *context
-               )
-{
-       CComObject<CDNSSDService> * service;
-       int err;
-       
-       service = ( CComObject< CDNSSDService>* ) context;
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-       if ( !service->Stopped() )
-       {
-               IBrowseListener * listener;
-
-               listener = ( IBrowseListener* ) service->GetListener();
-               require_action( listener, exit, err = kDNSServiceErr_Unknown );
-
-               if ( !errorCode )
-               {
-                       CComBSTR        serviceName;
-                       CComBSTR        regType;
-                       CComBSTR        replyDomain;
-               
-                       UTF8ToBSTR( serviceNameUTF8, serviceName );
-                       UTF8ToBSTR( regTypeUTF8, regType );
-                       UTF8ToBSTR( replyDomainUTF8, replyDomain );
-
-                       if ( flags & kDNSServiceFlagsAdd )
-                       {
-                               listener->ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
-                       }
-                       else
-                       {
-                               listener->ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
-                       }
-               }
-               else
-               {
-                       listener->BrowseFailed( service, ( DNSSDError ) errorCode );
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-void DNSSD_API
-CDNSSD::ResolveReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            ifIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *fullNameUTF8,
-               const char                          *hostNameUTF8,
-               uint16_t                            port,
-               uint16_t                            txtLen,
-               const unsigned char                 *txtRecord,
-               void                                *context
-               )
-{
-       CComObject<CDNSSDService> * service;
-       int err;
-       
-       service = ( CComObject< CDNSSDService>* ) context;
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-       if ( !service->Stopped() )
-       {
-               IResolveListener * listener;
-
-               listener = ( IResolveListener* ) service->GetListener();
-               require_action( listener, exit, err = kDNSServiceErr_Unknown );
-
-               if ( !errorCode )
-               {
-                       CComBSTR                                        fullName;
-                       CComBSTR                                        hostName;
-                       CComBSTR                                        regType;
-                       CComBSTR                                        replyDomain;
-                       CComObject< CTXTRecord >*       record;
-                       BOOL                                            ok;
-
-                       ok = UTF8ToBSTR( fullNameUTF8, fullName );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-                       ok = UTF8ToBSTR( hostNameUTF8, hostName );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-                       try
-                       {
-                               record = new CComObject<CTXTRecord>();
-                       }
-                       catch ( ... )
-                       {
-                               record = NULL;
-                       }
-
-                       require_action( record, exit, err = kDNSServiceErr_NoMemory );
-                       record->AddRef();
-
-                       char buf[ 64 ];
-                       snprintf( buf, sizeof( buf ), "txtLen = %d", txtLen );
-                       OutputDebugStringA( buf );
-
-                       if ( txtLen > 0 )
-                       {
-                               record->SetBytes( txtRecord, txtLen );
-                       }
-
-                       listener->ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, port, record );
-               }
-               else
-               {
-                       listener->ResolveFailed( service, ( DNSSDError ) errorCode );
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-void DNSSD_API
-CDNSSD::RegisterReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               DNSServiceErrorType                 errorCode,
-               const char                          *serviceNameUTF8,
-               const char                          *regTypeUTF8,
-               const char                          *domainUTF8,
-               void                                *context
-               )
-{
-       CComObject<CDNSSDService> * service;
-       int err;
-       
-       service = ( CComObject< CDNSSDService>* ) context;
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-       if ( !service->Stopped() )
-       {
-               IRegisterListener * listener;
-
-               listener = ( IRegisterListener* ) service->GetListener();
-               require_action( listener, exit, err = kDNSServiceErr_Unknown );
-
-               if ( !errorCode )
-               {
-                       CComBSTR                                        serviceName;
-                       CComBSTR                                        regType;
-                       CComBSTR                                        domain;
-                       BOOL                                            ok;
-
-                       ok = UTF8ToBSTR( serviceNameUTF8, serviceName );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-                       ok = UTF8ToBSTR( regTypeUTF8, regType );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-                       ok = UTF8ToBSTR( domainUTF8, domain );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-                       listener->ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain );
-               }
-               else
-               {
-                       listener->ServiceRegisterFailed( service, ( DNSSDError ) errorCode );
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-void DNSSD_API
-CDNSSD::QueryRecordReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            ifIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *fullNameUTF8,
-               uint16_t                            rrtype,
-               uint16_t                            rrclass,
-               uint16_t                            rdlen,
-               const void                          *rdata,
-               uint32_t                            ttl,
-               void                                *context
-               )
-{
-       CComObject<CDNSSDService> * service;
-       int err;
-       
-       service = ( CComObject< CDNSSDService>* ) context;
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-       if ( !service->Stopped() )
-       {
-               IQueryRecordListener * listener;
-
-               listener = ( IQueryRecordListener* ) service->GetListener();
-               require_action( listener, exit, err = kDNSServiceErr_Unknown );
-
-               if ( !errorCode )
-               {
-                       CComBSTR        fullName;
-                       VARIANT         var;
-                       BOOL            ok;
-
-                       ok = UTF8ToBSTR( fullNameUTF8, fullName );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-                       ok = ByteArrayToVariant( rdata, rdlen, &var );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-                       listener->QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl );
-               }
-               else
-               {
-                       listener->QueryRecordFailed( service, ( DNSSDError ) errorCode );
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-void DNSSD_API
-CDNSSD::GetAddrInfoReply
-               (
-               DNSServiceRef                    sdRef,
-               DNSServiceFlags                  flags,
-               uint32_t                         ifIndex,
-               DNSServiceErrorType              errorCode,
-               const char                       *hostNameUTF8,
-               const struct sockaddr            *rawAddress,
-               uint32_t                         ttl,
-               void                             *context
-               )
-{
-       CComObject<CDNSSDService> * service;
-       int err;
-       
-       service = ( CComObject< CDNSSDService>* ) context;
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-       if ( !service->Stopped() )
-       {
-               IGetAddrInfoListener * listener;
-
-               listener = ( IGetAddrInfoListener* ) service->GetListener();
-               require_action( listener, exit, err = kDNSServiceErr_Unknown );
-
-               if ( !errorCode )
-               {
-                       CComBSTR                        hostName;
-                       DWORD                           sockaddrLen;
-                       DNSSDAddressFamily      addressFamily;
-                       char                            addressUTF8[INET6_ADDRSTRLEN];
-                       DWORD                           addressLen = sizeof( addressUTF8 );
-                       CComBSTR                        address;
-                       BOOL                            ok;
-
-                       ok = UTF8ToBSTR( hostNameUTF8, hostName );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-                       switch ( rawAddress->sa_family )
-                       {
-                               case AF_INET:
-                               {
-                                       addressFamily   = kDNSSDAddressFamily_IPv4;
-                                       sockaddrLen             = sizeof( sockaddr_in );
-                               }
-                               break;
-
-                               case AF_INET6:
-                               {
-                                       addressFamily   = kDNSSDAddressFamily_IPv6;
-                                       sockaddrLen             = sizeof( sockaddr_in6 );
-                               }
-                               break;
-                       }
-
-                       err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen );
-                       require_noerr( err, exit );
-                       ok = UTF8ToBSTR( addressUTF8, address );
-                       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-                       listener->GetAddrInfoReply( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl );
-               }
-               else
-               {
-                       listener->GetAddrInfoFailed( service, ( DNSSDError ) errorCode );
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-void DNSSD_API
-CDNSSD::NATPortMappingReply
-    (
-    DNSServiceRef                    sdRef,
-    DNSServiceFlags                  flags,
-    uint32_t                         ifIndex,
-    DNSServiceErrorType              errorCode,
-    uint32_t                         externalAddress,   /* four byte IPv4 address in network byte order */
-    DNSServiceProtocol               protocol,
-    uint16_t                         internalPort,
-    uint16_t                         externalPort,      /* may be different than the requested port     */
-    uint32_t                         ttl,               /* may be different than the requested ttl      */
-    void                             *context
-    )
-{
-       CComObject<CDNSSDService> * service;
-       int err;
-       
-       service = ( CComObject< CDNSSDService>* ) context;
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-       if ( !service->Stopped() )
-       {
-               INATPortMappingListener * listener;
-
-               listener = ( INATPortMappingListener* ) service->GetListener();
-               require_action( listener, exit, err = kDNSServiceErr_Unknown );
-
-               if ( !errorCode )
-               {
-                       listener->MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), internalPort, externalPort, ttl  );
-               }
-               else
-               {
-                       listener->MappingFailed( service, ( DNSSDError ) errorCode );
-               }
-       }
-
-exit:
-
-       return;
-}
-
diff --git a/mDNSWindows/DLLX/DNSSDEventManager.cpp b/mDNSWindows/DLLX/DNSSDEventManager.cpp
deleted file mode 100755 (executable)
index 310ced0..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#include "stdafx.h"
-
-#include "DNSSDEventManager.h"
-
-
-
-
-
-// CDNSSDEventManager
-
-
-
diff --git a/mDNSWindows/DLLX/DNSSDEventManager.h b/mDNSWindows/DLLX/DNSSDEventManager.h
deleted file mode 100755 (executable)
index 70aedfc..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#pragma once
-
-#include "resource.h"       // main symbols
-
-
-
-#include "DLLX.h"
-
-#include "_IDNSSDEvents_CP.H"
-
-
-
-
-
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
-
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
-
-#endif
-
-
-
-
-
-
-
-// CDNSSDEventManager
-
-
-
-class ATL_NO_VTABLE CDNSSDEventManager :
-
-       public CComObjectRootEx<CComSingleThreadModel>,
-
-       public CComCoClass<CDNSSDEventManager, &CLSID_DNSSDEventManager>,
-
-       public IConnectionPointContainerImpl<CDNSSDEventManager>,
-
-       public CProxy_IDNSSDEvents<CDNSSDEventManager>,
-
-       public IDispatchImpl<IDNSSDEventManager, &IID_IDNSSDEventManager, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-public:
-
-       CDNSSDEventManager()
-
-       {
-
-       }
-
-
-
-DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDEVENTMANAGER)
-
-
-
-
-
-BEGIN_COM_MAP(CDNSSDEventManager)
-
-       COM_INTERFACE_ENTRY(IDNSSDEventManager)
-
-       COM_INTERFACE_ENTRY(IDispatch)
-
-       COM_INTERFACE_ENTRY(IConnectionPointContainer)
-
-END_COM_MAP()
-
-
-
-BEGIN_CONNECTION_POINT_MAP(CDNSSDEventManager)
-
-       CONNECTION_POINT_ENTRY(__uuidof(_IDNSSDEvents))
-
-END_CONNECTION_POINT_MAP()
-
-
-
-
-
-       DECLARE_PROTECT_FINAL_CONSTRUCT()
-
-
-
-       HRESULT FinalConstruct()
-
-       {
-
-               return S_OK;
-
-       }
-
-
-
-       void FinalRelease()
-
-       {
-
-       }
-
-
-
-public:
-
-
-
-};
-
-
-
-OBJECT_ENTRY_AUTO(__uuidof(DNSSDEventManager), CDNSSDEventManager)
-
diff --git a/mDNSWindows/DLLX/DNSSDEventManager.rgs b/mDNSWindows/DLLX/DNSSDEventManager.rgs
deleted file mode 100755 (executable)
index 9103512..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-HKCR\r
-{\r
-       Bonjour.DNSSDEventManager.1 = s 'DNSSDEventManager Class'\r
-       {\r
-               CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}'\r
-       }\r
-       Bonjour.DNSSDEventManager = s 'DNSSDEventManager Class'\r
-       {\r
-               CLSID = s '{BEEB932A-8D4A-4619-AEFE-A836F988B221}'\r
-               CurVer = s 'Bonjour.DNSSDEventManager.1'\r
-       }\r
-       NoRemove CLSID\r
-       {\r
-               ForceRemove {BEEB932A-8D4A-4619-AEFE-A836F988B221} = s 'DNSSDEventManager Class'\r
-               {\r
-                       ProgID = s 'Bonjour.DNSSDEventManager.1'\r
-                       VersionIndependentProgID = s 'Bonjour.DNSSDEventManager'\r
-                       ForceRemove 'Programmable'\r
-                       InprocServer32 = s '%MODULE%'\r
-                       {\r
-                               val ThreadingModel = s 'Apartment'\r
-                       }\r
-                       val AppID = s '%APPID%'\r
-                       'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
-               }\r
-       }\r
-}\r
diff --git a/mDNSWindows/DLLX/DNSSDRecord.cpp b/mDNSWindows/DLLX/DNSSDRecord.cpp
deleted file mode 100755 (executable)
index a272720..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#include "stdafx.h"
-
-#include "DNSSDRecord.h"
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-// CDNSSDRecord
-
-
-
-STDMETHODIMP CDNSSDRecord::Update(DNSSDFlags flags, VARIANT rdata, ULONG ttl)
-
-{
-
-       std::vector< BYTE >     byteArray;
-
-       const void              *       byteArrayPtr    = NULL;
-
-       DNSServiceErrorType     err                             = 0;
-
-       HRESULT                         hr                              = 0;
-
-       BOOL                            ok;
-
-
-
-       // Convert the VARIANT
-
-       ok = VariantToByteArray( &rdata, byteArray );
-
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       err = DNSServiceUpdateRecord( m_serviceObject->GetSubordRef(), m_rref, flags, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );
-
-       require_noerr( err, exit );
-
-
-
-exit:
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDRecord::Remove(DNSSDFlags flags)
-
-{
-
-       DNSServiceErrorType     err = 0;
-
-
-
-       err = DNSServiceRemoveRecord( m_serviceObject->GetSubordRef(), m_rref, flags );
-
-       require_noerr( err, exit );
-
-
-
-exit:
-
-
-
-       return err;
-
-}
-
-
-
diff --git a/mDNSWindows/DLLX/DNSSDRecord.h b/mDNSWindows/DLLX/DNSSDRecord.h
deleted file mode 100755 (executable)
index bdedda5..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#pragma once
-
-#include "resource.h"       // main symbols
-
-
-
-#include "DLLX.h"
-
-#include "DNSSDService.h"
-
-#include <dns_sd.h>
-
-
-
-
-
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
-
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
-
-#endif
-
-
-
-
-
-
-
-// CDNSSDRecord
-
-
-
-class ATL_NO_VTABLE CDNSSDRecord :
-
-       public CComObjectRootEx<CComSingleThreadModel>,
-
-       public CComCoClass<CDNSSDRecord, &CLSID_DNSSDRecord>,
-
-       public IDispatchImpl<IDNSSDRecord, &IID_IDNSSDRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-public:
-
-       CDNSSDRecord()
-
-       {
-
-       }
-
-
-
-DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDRECORD)
-
-
-
-
-
-BEGIN_COM_MAP(CDNSSDRecord)
-
-       COM_INTERFACE_ENTRY(IDNSSDRecord)
-
-       COM_INTERFACE_ENTRY(IDispatch)
-
-END_COM_MAP()
-
-
-
-
-
-
-
-       DECLARE_PROTECT_FINAL_CONSTRUCT()
-
-
-
-       HRESULT FinalConstruct()
-
-       {
-
-               return S_OK;
-
-       }
-
-
-
-       void FinalRelease()
-
-       {
-
-       }
-
-
-
-       inline CDNSSDService*
-
-       GetServiceObject()
-
-       {
-
-               return m_serviceObject;
-
-       }
-
-
-
-       inline void
-
-       SetServiceObject( CDNSSDService * serviceObject )
-
-       {
-
-               m_serviceObject = serviceObject;
-
-       }
-
-
-
-       inline DNSRecordRef
-
-       GetRecordRef()
-
-       {
-
-               return m_rref;
-
-       }
-
-
-
-       inline void
-
-       SetRecordRef( DNSRecordRef rref )
-
-       {
-
-               m_rref = rref;
-
-       }
-
-
-
-public:
-
-
-
-       STDMETHOD(Update)(DNSSDFlags flags, VARIANT rdata, ULONG ttl);
-
-       STDMETHOD(Remove)(DNSSDFlags flags);
-
-
-
-private:
-
-
-
-       CDNSSDService * m_serviceObject;
-
-       DNSRecordRef    m_rref;
-
-};
-
-
-
-OBJECT_ENTRY_AUTO(__uuidof(DNSSDRecord), CDNSSDRecord)
-
diff --git a/mDNSWindows/DLLX/DNSSDRecord.rgs b/mDNSWindows/DLLX/DNSSDRecord.rgs
deleted file mode 100755 (executable)
index ee0a5a2..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-HKCR\r
-{\r
-       Bonjour.DNSSDRecord.1 = s 'DNSSDRecord Class'\r
-       {\r
-               CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}'\r
-       }\r
-       Bonjour.DNSSDRecord = s 'DNSSDRecord Class'\r
-       {\r
-               CLSID = s '{5E93C5A9-7516-4259-A67B-41A656F6E01C}'\r
-               CurVer = s 'Bonjour.DNSSDRecord.1'\r
-       }\r
-       NoRemove CLSID\r
-       {\r
-               ForceRemove {5E93C5A9-7516-4259-A67B-41A656F6E01C} = s 'DNSSDRecord Class'\r
-               {\r
-                       ProgID = s 'Bonjour.DNSSDRecord.1'\r
-                       VersionIndependentProgID = s 'Bonjour.DNSSDRecord'\r
-                       ForceRemove 'Programmable'\r
-                       InprocServer32 = s '%MODULE%'\r
-                       {\r
-                               val ThreadingModel = s 'Apartment'\r
-                       }\r
-                       val AppID = s '%APPID%'\r
-                       'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
-               }\r
-       }\r
-}\r
diff --git a/mDNSWindows/DLLX/DNSSDService.cpp b/mDNSWindows/DLLX/DNSSDService.cpp
deleted file mode 100755 (executable)
index b8ce49b..0000000
+++ /dev/null
@@ -1,2095 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#pragma warning(disable:4995)
-
-
-
-#include "stdafx.h"
-
-#include <strsafe.h>
-
-#include "DNSSDService.h"
-
-#include "DNSSDEventManager.h"
-
-#include "DNSSDRecord.h"
-
-#include "TXTRecord.h"
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-#define WM_SOCKET (WM_APP + 100)
-
-
-
-
-
-// CDNSSDService
-
-
-
-BOOL                                           CDNSSDService::m_registeredWindowClass  = FALSE;
-
-HWND                                           CDNSSDService::m_hiddenWindow                   = NULL;
-
-CDNSSDService::SocketMap       CDNSSDService::m_socketMap;
-
-
-
-
-
-HRESULT CDNSSDService::FinalConstruct()
-
-{
-
-       DNSServiceErrorType     err     = 0;
-
-       HRESULT                         hr      = S_OK;
-
-
-
-       m_isPrimary = TRUE;
-
-       err = DNSServiceCreateConnection( &m_primary );
-
-       require_action( !err, exit, hr = E_FAIL );
-
-
-
-       if ( !m_hiddenWindow )
-
-       {
-
-               TCHAR windowClassName[ 256 ];
-
-
-
-               StringCchPrintf( windowClassName, sizeof( windowClassName ) / sizeof( TCHAR ), TEXT( "Bonjour Hidden Window %d" ), GetProcessId( NULL ) );
-
-
-
-               if ( !m_registeredWindowClass )
-
-               {
-
-                       WNDCLASS        wc;
-
-                       ATOM            atom;
-
-
-
-                       wc.style                        = 0;
-
-                       wc.lpfnWndProc          = WndProc;
-
-                       wc.cbClsExtra           = 0;
-
-                       wc.cbWndExtra           = 0;
-
-                       wc.hInstance            = NULL;
-
-                       wc.hIcon                        = NULL;
-
-                       wc.hCursor                      = NULL;
-
-                       wc.hbrBackground        = NULL;
-
-                       wc.lpszMenuName         = NULL;
-
-                       wc.lpszClassName        = windowClassName;
-
-
-
-                       atom = RegisterClass(&wc);
-
-                       require_action( atom != NULL, exit, hr = E_FAIL );
-
-
-
-                       m_registeredWindowClass = TRUE;
-
-               }
-
-
-
-               m_hiddenWindow = CreateWindow( windowClassName, windowClassName, WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, GetModuleHandle( NULL ), NULL );
-
-               require_action( m_hiddenWindow != NULL, exit, hr = E_FAIL );
-
-       }
-
-
-
-       err = WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, WM_SOCKET, FD_READ );
-
-       require_action( !err, exit, hr = E_FAIL );
-
-
-
-       m_socketMap[ DNSServiceRefSockFD( m_primary ) ] = this;
-
-
-
-exit:
-
-
-
-       return hr;
-
-}
-
-
-
-
-
-void CDNSSDService::FinalRelease()
-
-{
-
-       dlog( kDebugLevelTrace, "FinalRelease()\n" ); 
-
-       Stop();
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::EnumerateDomains(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service)
-
-{
-
-       CComObject<CDNSSDService>       *       object  = NULL;
-
-       DNSServiceRef                                   subord  = NULL;
-
-       DNSServiceErrorType                             err             = 0;
-
-       HRESULT                                                 hr              = 0;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *service = NULL;
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDService>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       subord = m_primary;
-
-       err = DNSServiceEnumerateDomains( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, ( DNSServiceDomainEnumReply ) &DomainEnumReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetPrimaryRef( m_primary );
-
-       object->SetSubordRef( subord );
-
-       object->SetEventManager( eventManager );
-
-
-
-       *service = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::Browse(DNSSDFlags flags, ULONG ifIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service )
-
-{
-
-       CComObject<CDNSSDService>       *       object          = NULL;
-
-       std::string                                             regtypeUTF8;
-
-       std::string                                             domainUTF8;
-
-       DNSServiceRef                                   subord          = NULL;
-
-       DNSServiceErrorType                             err                     = 0;
-
-       HRESULT                                                 hr                      = 0;
-
-       BOOL                                                    ok;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *service = NULL;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( regtype, regtypeUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       ok = BSTRToUTF8( domain, domainUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDService>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       subord = m_primary;
-
-       err = DNSServiceBrowse( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, regtypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, ( DNSServiceBrowseReply ) &BrowseReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetPrimaryRef( m_primary );
-
-       object->SetSubordRef( subord );
-
-       object->SetEventManager( eventManager );
-
-
-
-       *service = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::Resolve(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service)
-
-{
-
-       CComObject<CDNSSDService>       *       object                  = NULL;
-
-       std::string                                             serviceNameUTF8;
-
-       std::string                                             regTypeUTF8;
-
-       std::string                                             domainUTF8;
-
-       DNSServiceRef                                   subord                  = NULL;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-       BOOL                                                    ok;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *service = NULL;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       ok = BSTRToUTF8( regType, regTypeUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       ok = BSTRToUTF8( domain, domainUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDService>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       subord = m_primary;
-
-       err = DNSServiceResolve( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), domainUTF8.c_str(), ( DNSServiceResolveReply ) &ResolveReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetPrimaryRef( m_primary );
-
-       object->SetSubordRef( subord );
-
-       object->SetEventManager( eventManager );
-
-
-
-       *service = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::Register(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service)
-
-{
-
-       CComObject<CDNSSDService>       *       object                  = NULL;
-
-       std::string                                             serviceNameUTF8;
-
-       std::string                                             regTypeUTF8;
-
-       std::string                                             domainUTF8;
-
-       std::string                                             hostUTF8;
-
-       const void                                      *       txtRecord               = NULL;
-
-       uint16_t                                                txtLen                  = 0;
-
-       DNSServiceRef                                   subord                  = NULL;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-       BOOL                                                    ok;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *service = NULL;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( serviceName, serviceNameUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       ok = BSTRToUTF8( regType, regTypeUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       ok = BSTRToUTF8( domain, domainUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-       ok = BSTRToUTF8( host, hostUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDService>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       if ( record )
-
-       {
-
-               CComObject< CTXTRecord > * realTXTRecord;
-
-
-
-               realTXTRecord = ( CComObject< CTXTRecord >* ) record;
-
-
-
-               txtRecord       = realTXTRecord->GetBytes();
-
-               txtLen          = realTXTRecord->GetLen();
-
-       }
-
-
-
-       subord = m_primary;
-
-       err = DNSServiceRegister( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, serviceNameUTF8.c_str(), regTypeUTF8.c_str(), ( domainUTF8.size() > 0 ) ? domainUTF8.c_str() : NULL, hostUTF8.c_str(), htons( port ), txtLen, txtRecord, ( DNSServiceRegisterReply ) &RegisterReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetPrimaryRef( m_primary );
-
-       object->SetSubordRef( subord );
-
-       object->SetEventManager( eventManager );
-
-
-
-       *service = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::QueryRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service)
-
-{
-
-       CComObject<CDNSSDService>       *       object                  = NULL;
-
-       DNSServiceRef                                   subord                  = NULL;
-
-       std::string                                             fullNameUTF8;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-       BOOL                                                    ok;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *service = NULL;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( fullname, fullNameUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDService>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       subord = m_primary;
-
-       err = DNSServiceQueryRecord( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, fullNameUTF8.c_str(), ( uint16_t ) rrtype, ( uint16_t ) rrclass, ( DNSServiceQueryRecordReply ) &QueryRecordReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetPrimaryRef( m_primary );
-
-       object->SetSubordRef( subord );
-
-       object->SetEventManager( eventManager );
-
-
-
-       *service = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::RegisterRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record)
-
-{
-
-       CComObject<CDNSSDRecord>        *       object                  = NULL;
-
-       DNSRecordRef                                    rref                    = NULL;
-
-       std::string                                             fullNameUTF8;
-
-       std::vector< BYTE >                             byteArray;
-
-       const void                                      *       byteArrayPtr    = NULL;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-       BOOL                                                    ok;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *object = NULL;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( fullName, fullNameUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       // Convert the VARIANT
-
-       ok = VariantToByteArray( &rdata, byteArray );
-
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDRecord>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       err = DNSServiceRegisterRecord( m_primary, &rref, flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl, &RegisterRecordReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetServiceObject( this );
-
-       object->SetRecordRef( rref );
-
-       this->SetEventManager( eventManager );
-
-
-
-       *record = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::AddRecord(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record)
-
-{
-
-       CComObject<CDNSSDRecord>        *       object                  = NULL;
-
-       DNSRecordRef                                    rref                    = NULL;
-
-       std::vector< BYTE >                             byteArray;
-
-       const void                                      *       byteArrayPtr    = NULL;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-       BOOL                                                    ok;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *object = NULL;
-
-
-
-       // Convert the VARIANT
-
-       ok = VariantToByteArray( &rdata, byteArray );
-
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDRecord>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       err = DNSServiceAddRecord( m_primary, &rref, flags, rrtype, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL, ttl );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetServiceObject( this );
-
-       object->SetRecordRef( rref );
-
-
-
-       *record = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-STDMETHODIMP CDNSSDService::ReconfirmRecord(DNSSDFlags flags, ULONG ifIndex, BSTR fullName, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata)
-
-{
-
-       std::string                                             fullNameUTF8;
-
-       std::vector< BYTE >                             byteArray;
-
-       const void                                      *       byteArrayPtr    = NULL;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-       BOOL                                                    ok;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( fullName, fullNameUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       // Convert the VARIANT
-
-       ok = VariantToByteArray( &rdata, byteArray );
-
-       require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       err = DNSServiceReconfirmRecord( flags, ifIndex, fullNameUTF8.c_str(), rrtype, rrclass, ( uint16_t ) byteArray.size(), byteArray.size() > 0 ? &byteArray[ 0 ] : NULL );
-
-       require_noerr( err, exit );
-
-
-
-exit:
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::GetProperty(BSTR prop, VARIANT * value )
-
-{
-
-       std::string                     propUTF8;
-
-       std::vector< BYTE >     byteArray;
-
-       SAFEARRAY               *       psa                     = NULL;
-
-       BYTE                    *       pData           = NULL;
-
-       uint32_t                        elems           = 0;
-
-       DNSServiceErrorType     err                     = 0;
-
-       BOOL                            ok = TRUE;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( prop, propUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       // Setup the byte array
-
-       require_action( V_VT( value ) == ( VT_ARRAY|VT_UI1 ), exit, err = kDNSServiceErr_Unknown );
-
-       psa = V_ARRAY( value );
-
-       require_action( psa, exit, err = kDNSServiceErr_Unknown );
-
-       require_action( SafeArrayGetDim( psa ) == 1, exit, err = kDNSServiceErr_Unknown );
-
-       byteArray.reserve( psa->rgsabound[0].cElements );
-
-       byteArray.assign( byteArray.capacity(), 0 );
-
-       elems = ( uint32_t ) byteArray.capacity();
-
-
-
-       // Call the function and package the return value in the Variant
-
-       err = DNSServiceGetProperty( propUTF8.c_str(), &byteArray[ 0 ], &elems );
-
-       require_noerr( err, exit );
-
-       ok = ByteArrayToVariant( &byteArray[ 0 ], elems, value );
-
-       require_action( ok, exit, err = kDNSSDError_Unknown );
-
-
-
-exit:
-
-
-
-       if ( psa )
-
-       {
-
-               SafeArrayUnaccessData( psa );
-
-               psa = NULL;
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-STDMETHODIMP CDNSSDService::GetAddrInfo(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostName, IDNSSDEventManager *eventManager, IDNSSDService **service)
-
-{
-
-       CComObject<CDNSSDService>       *       object                  = NULL;
-
-       DNSServiceRef                                   subord                  = NULL;
-
-       std::string                                             hostNameUTF8;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-       BOOL                                                    ok;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *service = NULL;
-
-
-
-       // Convert BSTR params to utf8
-
-       ok = BSTRToUTF8( hostName, hostNameUTF8 );
-
-       require_action( ok, exit, err = kDNSServiceErr_BadParam );
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDService>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       subord = m_primary;
-
-       err = DNSServiceGetAddrInfo( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, addressFamily, hostNameUTF8.c_str(), ( DNSServiceGetAddrInfoReply ) &GetAddrInfoReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetPrimaryRef( m_primary );
-
-       object->SetSubordRef( subord );
-
-       object->SetEventManager( eventManager );
-
-
-
-       *service = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::NATPortMappingCreate(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service)
-
-{
-
-       CComObject<CDNSSDService>       *       object                  = NULL;
-
-       DNSServiceRef                                   subord                  = NULL;
-
-       DNSServiceProtocol                              prot                    = 0;
-
-       DNSServiceErrorType                             err                             = 0;
-
-       HRESULT                                                 hr                              = 0;
-
-
-
-       check( m_primary );
-
-
-
-       // Initialize
-
-       *service = NULL;
-
-
-
-       try
-
-       {
-
-               object = new CComObject<CDNSSDService>();
-
-       }
-
-       catch ( ... )
-
-       {
-
-               object = NULL;
-
-       }
-
-
-
-       require_action( object != NULL, exit, err = kDNSServiceErr_NoMemory );
-
-       object->AddRef();
-
-
-
-       prot = ( addressFamily | protocol );
-
-
-
-       subord = m_primary;
-
-       err = DNSServiceNATPortMappingCreate( &subord, flags | kDNSServiceFlagsShareConnection, ifIndex, prot, htons( internalPort ), htons( externalPort ), ttl, ( DNSServiceNATPortMappingReply ) &NATPortMappingReply, object );
-
-       require_noerr( err, exit );
-
-
-
-       object->SetPrimaryRef( m_primary );
-
-       object->SetSubordRef( subord );
-
-       object->SetEventManager( eventManager );
-
-
-
-       *service = object;
-
-
-
-exit:
-
-
-
-       if ( err && object )
-
-       {
-
-               object->Release();
-
-       }
-
-
-
-       return err;
-
-}
-
-
-
-
-
-STDMETHODIMP CDNSSDService::Stop(void)
-
-{
-
-       if ( !m_stopped )
-
-       {
-
-               m_stopped = TRUE;
-
-
-
-               dlog( kDebugLevelTrace, "Stop()\n" );
-
-
-
-               if ( m_isPrimary && m_primary )
-
-               {
-
-                       SocketMap::iterator it;
-
-
-
-                       if ( m_hiddenWindow )
-
-                       {
-
-                               WSAAsyncSelect( DNSServiceRefSockFD( m_primary ), m_hiddenWindow, 0, 0 );
-
-                       }
-
-
-
-                       it = m_socketMap.find( DNSServiceRefSockFD( m_primary ) );
-
-
-
-                       if ( it != m_socketMap.end() )
-
-                       {
-
-                               m_socketMap.erase( it );
-
-                       }
-
-
-
-                       DNSServiceRefDeallocate( m_primary );
-
-                       m_primary = NULL;
-
-               }
-
-               else if ( m_subord )
-
-               {
-
-                       DNSServiceRefDeallocate( m_subord );
-
-                       m_subord = NULL;
-
-               }
-
-
-
-               if ( m_eventManager != NULL )
-
-               {
-
-                       m_eventManager->Release();
-
-                       m_eventManager = NULL;
-
-               }
-
-       }
-
-
-
-       return S_OK;
-
-}
-
-
-
-
-
-void DNSSD_API
-CDNSSDService::DomainEnumReply
-    (
-    DNSServiceRef                       sdRef,
-    DNSServiceFlags                     flags,
-    uint32_t                            ifIndex,
-    DNSServiceErrorType                 errorCode,
-    const char                          *replyDomainUTF8,
-    void                                *context
-    )
-
-{
-
-       CComObject<CDNSSDService>       * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       service = ( CComObject< CDNSSDService>* ) context;
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               CComBSTR replyDomain;
-
-               BOOL ok;
-
-               
-
-               ok = UTF8ToBSTR( replyDomainUTF8, replyDomain );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-               if ( flags & kDNSServiceFlagsAdd )
-
-               {
-
-                       eventManager->Fire_DomainFound( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
-
-               }
-
-               else
-
-               {
-
-                       eventManager->Fire_DomainLost( service, ( DNSSDFlags ) flags, ifIndex, replyDomain );
-
-               }
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-void DNSSD_API
-CDNSSDService::BrowseReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            ifIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *serviceNameUTF8,
-               const char                          *regTypeUTF8,
-               const char                          *replyDomainUTF8,
-               void                                *context
-               )
-
-{
-
-       CComObject<CDNSSDService>       * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       service = ( CComObject< CDNSSDService>* ) context;
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               CComBSTR        serviceName;
-
-               CComBSTR        regType;
-
-               CComBSTR        replyDomain;
-
-       
-
-               UTF8ToBSTR( serviceNameUTF8, serviceName );
-
-               UTF8ToBSTR( regTypeUTF8, regType );
-
-               UTF8ToBSTR( replyDomainUTF8, replyDomain );
-
-
-
-               if ( flags & kDNSServiceFlagsAdd )
-
-               {
-
-                       eventManager->Fire_ServiceFound( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
-
-               }
-
-               else
-
-               {
-
-                       eventManager->Fire_ServiceLost( service, ( DNSSDFlags ) flags, ifIndex, serviceName, regType, replyDomain );
-
-               }
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-void DNSSD_API
-
-CDNSSDService::ResolveReply
-
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            ifIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *fullNameUTF8,
-               const char                          *hostNameUTF8,
-               uint16_t                            port,
-               uint16_t                            txtLen,
-               const unsigned char                 *txtRecord,
-               void                                *context
-
-               )
-
-{
-
-       CComObject<CDNSSDService>       * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       service = ( CComObject< CDNSSDService>* ) context;
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               CComBSTR                                        fullName;
-
-               CComBSTR                                        hostName;
-
-               CComBSTR                                        regType;
-
-               CComBSTR                                        replyDomain;
-
-               CComObject< CTXTRecord >*       record;
-
-               BOOL                                            ok;
-
-
-
-               ok = UTF8ToBSTR( fullNameUTF8, fullName );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-               ok = UTF8ToBSTR( hostNameUTF8, hostName );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-               try
-
-               {
-
-                       record = new CComObject<CTXTRecord>();
-
-               }
-
-               catch ( ... )
-
-               {
-
-                       record = NULL;
-
-               }
-
-
-
-               require_action( record, exit, err = kDNSServiceErr_NoMemory );
-
-               record->AddRef();
-
-
-
-               if ( txtLen > 0 )
-
-               {
-
-                       record->SetBytes( txtRecord, txtLen );
-
-               }
-
-
-
-               eventManager->Fire_ServiceResolved( service, ( DNSSDFlags ) flags, ifIndex, fullName, hostName, ntohs( port ), record );
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-void DNSSD_API
-CDNSSDService::RegisterReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               DNSServiceErrorType                 errorCode,
-               const char                          *serviceNameUTF8,
-               const char                          *regTypeUTF8,
-               const char                          *domainUTF8,
-               void                                *context
-               )
-
-{
-
-       CComObject<CDNSSDService>       * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       service = ( CComObject< CDNSSDService>* ) context;
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               CComBSTR                                        serviceName;
-
-               CComBSTR                                        regType;
-
-               CComBSTR                                        domain;
-
-               BOOL                                            ok;
-
-
-
-               ok = UTF8ToBSTR( serviceNameUTF8, serviceName );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-               ok = UTF8ToBSTR( regTypeUTF8, regType );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-               ok = UTF8ToBSTR( domainUTF8, domain );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-               eventManager->Fire_ServiceRegistered( service, ( DNSSDFlags ) flags, serviceName, regType, domain );
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-void DNSSD_API
-CDNSSDService::QueryRecordReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            ifIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *fullNameUTF8,
-               uint16_t                            rrtype,
-               uint16_t                            rrclass,
-               uint16_t                            rdlen,
-               const void                          *rdata,
-               uint32_t                            ttl,
-               void                                *context
-               )
-
-{
-
-       CComObject<CDNSSDService>       * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       service = ( CComObject< CDNSSDService>* ) context;
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               CComBSTR        fullName;
-
-               VARIANT         var;
-
-               BOOL            ok;
-
-
-
-               ok = UTF8ToBSTR( fullNameUTF8, fullName );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-               ok = ByteArrayToVariant( rdata, rdlen, &var );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-               eventManager->Fire_QueryRecordAnswered( service, ( DNSSDFlags ) flags, ifIndex, fullName, ( DNSSDRRType ) rrtype, ( DNSSDRRClass ) rrclass, var, ttl );
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-void DNSSD_API
-CDNSSDService::GetAddrInfoReply
-               (
-               DNSServiceRef                    sdRef,
-               DNSServiceFlags                  flags,
-               uint32_t                         ifIndex,
-               DNSServiceErrorType              errorCode,
-               const char                       *hostNameUTF8,
-               const struct sockaddr            *rawAddress,
-               uint32_t                         ttl,
-               void                             *context
-               )
-
-{
-
-       CComObject<CDNSSDService>       * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       service = ( CComObject< CDNSSDService>* ) context;
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               CComBSTR                        hostName;
-
-               DWORD                           sockaddrLen;
-
-               DNSSDAddressFamily      addressFamily;
-
-               char                            addressUTF8[INET6_ADDRSTRLEN];
-
-               DWORD                           addressLen = sizeof( addressUTF8 );
-
-               CComBSTR                        address;
-
-               BOOL                            ok;
-
-
-
-               ok = UTF8ToBSTR( hostNameUTF8, hostName );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-               switch ( rawAddress->sa_family )
-
-               {
-
-                       case AF_INET:
-
-                       {
-
-                               addressFamily   = kDNSSDAddressFamily_IPv4;
-
-                               sockaddrLen             = sizeof( sockaddr_in );
-
-                       }
-
-                       break;
-
-
-
-                       case AF_INET6:
-
-                       {
-
-                               addressFamily   = kDNSSDAddressFamily_IPv6;
-
-                               sockaddrLen             = sizeof( sockaddr_in6 );
-
-                       }
-
-                       break;
-
-               }
-
-
-
-               err = WSAAddressToStringA( ( LPSOCKADDR ) rawAddress, sockaddrLen, NULL, addressUTF8, &addressLen );
-
-               require_noerr( err, exit );
-
-               ok = UTF8ToBSTR( addressUTF8, address );
-
-               require_action( ok, exit, err = kDNSServiceErr_Unknown );
-
-
-
-               eventManager->Fire_AddressFound( service, ( DNSSDFlags ) flags, ifIndex, hostName, addressFamily, address, ttl );
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-void DNSSD_API
-CDNSSDService::NATPortMappingReply
-    (
-    DNSServiceRef                    sdRef,
-    DNSServiceFlags                  flags,
-    uint32_t                         ifIndex,
-    DNSServiceErrorType              errorCode,
-    uint32_t                         externalAddress,   /* four byte IPv4 address in network byte order */
-    DNSServiceProtocol               protocol,
-    uint16_t                         internalPort,
-    uint16_t                         externalPort,      /* may be different than the requested port     */
-    uint32_t                         ttl,               /* may be different than the requested ttl      */
-    void                             *context
-    )
-
-{
-
-       CComObject<CDNSSDService>       * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       service = ( CComObject< CDNSSDService>* ) context;
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               eventManager->Fire_MappingCreated( service, ( DNSSDFlags ) flags, ifIndex, externalAddress, ( DNSSDAddressFamily ) ( protocol & 0x8 ), ( DNSSDProtocol ) ( protocol & 0x80 ), ntohs( internalPort ), ntohs( externalPort ), ttl  );
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-void DNSSD_API
-CDNSSDService::RegisterRecordReply
-               (
-               DNSServiceRef           sdRef,
-               DNSRecordRef            RecordRef,
-               DNSServiceFlags         flags,
-               DNSServiceErrorType     errorCode,
-               void                            *context
-               )
-
-{
-
-       CComObject<CDNSSDRecord>        * record                = NULL;
-
-       CDNSSDService                           * service               = NULL;
-
-       CDNSSDEventManager                      * eventManager  = NULL;
-
-       int err = 0;
-
-       
-
-       record = ( CComObject< CDNSSDRecord >* ) context;
-
-       require_action( record, exit, err = kDNSServiceErr_Unknown );
-
-       service = record->GetServiceObject();
-
-       require_action( service, exit, err = kDNSServiceErr_Unknown );
-
-
-
-       if ( service->ShouldHandleReply( errorCode, eventManager ) )
-
-       {
-
-               eventManager->Fire_RecordRegistered( record, ( DNSSDFlags ) flags );
-
-       }
-
-
-
-exit:
-
-
-
-       return;
-
-}
-
-
-
-
-
-BOOL
-
-CDNSSDService::ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager )
-
-{
-
-       BOOL ok = FALSE;
-
-
-
-       if ( !this->Stopped() )
-
-       {
-
-               eventManager = this->GetEventManager();
-
-               require_action( eventManager, exit, ok = FALSE );
-
-
-
-               if ( !errorCode )
-
-               {
-
-                       ok = TRUE;
-
-               }
-
-               else
-
-               {
-
-                       eventManager->Fire_OperationFailed( this, ( DNSSDError ) errorCode );
-
-               }
-
-       }
-
-
-
-exit:
-
-
-
-       return ok;
-
-}
-
-
-
-
-
-LRESULT CALLBACK
-
-CDNSSDService::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
-
-{
-
-       if ( msg == WM_SOCKET )
-
-       {
-
-               SocketMap::iterator it;
-
-                       
-
-               it = m_socketMap.find( ( SOCKET ) wParam );
-
-               check( it != m_socketMap.end() );
-
-
-
-               if ( it != m_socketMap.end() )
-
-               {
-
-                       DNSServiceProcessResult( it->second->m_primary );
-
-               }
-
-       }
-
-
-
-       return DefWindowProc(hWnd, msg, wParam, lParam);;
-
-}
-
diff --git a/mDNSWindows/DLLX/DNSSDService.h b/mDNSWindows/DLLX/DNSSDService.h
deleted file mode 100755 (executable)
index 5eb8dcb..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#pragma once
-
-#include "resource.h"       // main symbols
-
-
-
-#include "DLLX.h"
-
-#include "DNSSDEventManager.h"
-
-#include <CommonServices.h>
-
-#include <DebugServices.h>
-
-#include <dns_sd.h>
-
-#include <map>
-
-
-
-
-
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
-
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
-
-#endif
-
-
-
-
-
-
-
-// CDNSSDService
-
-
-
-class ATL_NO_VTABLE CDNSSDService :
-
-       public CComObjectRootEx<CComSingleThreadModel>,
-
-       public CComCoClass<CDNSSDService, &CLSID_DNSSDService>,
-
-       public IDispatchImpl<IDNSSDService, &IID_IDNSSDService, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-public:
-
-
-
-       typedef CComObjectRootEx<CComSingleThreadModel> Super;
-
-
-
-       CDNSSDService()
-
-       :
-
-               m_isPrimary( FALSE ),
-
-               m_eventManager( NULL ),
-
-               m_stopped( FALSE ),
-
-               m_primary( NULL ),
-
-               m_subord( NULL )
-
-       {
-
-       }
-
-
-
-DECLARE_REGISTRY_RESOURCEID(IDR_DNSSDSERVICE)
-
-
-
-
-
-BEGIN_COM_MAP(CDNSSDService)
-
-       COM_INTERFACE_ENTRY(IDNSSDService)
-
-       COM_INTERFACE_ENTRY(IDispatch)
-
-END_COM_MAP()
-
-
-
-       DECLARE_PROTECT_FINAL_CONSTRUCT()
-
-
-
-       HRESULT
-
-       FinalConstruct();
-
-
-
-       void 
-
-       FinalRelease();
-
-
-
-public:
-
-
-
-       inline DNSServiceRef
-
-       GetPrimaryRef()
-
-       {
-
-               return m_primary;
-
-       }
-
-
-
-       inline void
-
-       SetPrimaryRef( DNSServiceRef primary )
-
-       {
-
-               m_primary = primary;
-
-       }
-
-
-
-       inline DNSServiceRef
-
-       GetSubordRef()
-
-       {
-
-               return m_subord;
-
-       }
-
-
-
-       inline void
-
-       SetSubordRef( DNSServiceRef subord )
-
-       {
-
-               m_subord = subord;
-
-       }
-
-
-
-       inline CDNSSDEventManager*
-
-       GetEventManager()
-
-       {
-
-               return m_eventManager;
-
-       }
-
-
-
-       inline void
-
-       SetEventManager( IDNSSDEventManager * eventManager )
-
-       {
-
-               if ( m_eventManager )
-
-               {
-
-                       m_eventManager->Release();
-
-                       m_eventManager = NULL;
-
-               }
-
-
-
-               if ( eventManager )
-
-               {
-
-                       m_eventManager = dynamic_cast< CDNSSDEventManager* >( eventManager );
-
-                       check( m_eventManager );
-
-                       m_eventManager->AddRef();
-
-               }
-
-       }
-
-
-
-       inline BOOL
-
-       Stopped()
-
-       {
-
-               return m_stopped;
-
-       }
-
-
-
-private:
-
-
-
-       static void DNSSD_API
-       DomainEnumReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            ifIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *replyDomain,
-               void                                *context
-               );
-
-
-
-       static void DNSSD_API
-       BrowseReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *serviceName,
-               const char                          *regtype,
-               const char                          *replyDomain,
-               void                                *context
-               );
-
-
-
-       static void DNSSD_API
-
-       ResolveReply
-
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *fullname,
-               const char                          *hosttarget,
-               uint16_t                            port,
-               uint16_t                            txtLen,
-               const unsigned char                 *txtRecord,
-               void                                *context
-
-               );
-
-
-
-       static void DNSSD_API
-       RegisterReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               DNSServiceErrorType                 errorCode,
-               const char                          *name,
-               const char                          *regtype,
-               const char                          *domain,
-               void                                *context
-               );
-
-
-
-       static void DNSSD_API
-       QueryRecordReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSServiceFlags                     flags,
-               uint32_t                            interfaceIndex,
-               DNSServiceErrorType                 errorCode,
-               const char                          *fullname,
-               uint16_t                            rrtype,
-               uint16_t                            rrclass,
-               uint16_t                            rdlen,
-               const void                          *rdata,
-               uint32_t                            ttl,
-               void                                *context
-               );
-
-
-
-       static void DNSSD_API
-    GetAddrInfoReply
-               (
-               DNSServiceRef                    sdRef,
-               DNSServiceFlags                  flags,
-               uint32_t                         interfaceIndex,
-               DNSServiceErrorType              errorCode,
-               const char                       *hostname,
-               const struct sockaddr            *address,
-               uint32_t                         ttl,
-               void                             *context
-               );
-
-
-
-       static void DNSSD_API
-       NATPortMappingReply
-               (
-               DNSServiceRef                    sdRef,
-               DNSServiceFlags                  flags,
-               uint32_t                         interfaceIndex,
-               DNSServiceErrorType              errorCode,
-               uint32_t                         externalAddress,   /* four byte IPv4 address in network byte order */
-               DNSServiceProtocol               protocol,
-               uint16_t                         internalPort,
-               uint16_t                         externalPort,      /* may be different than the requested port     */
-               uint32_t                         ttl,               /* may be different than the requested ttl      */
-               void                             *context
-               );
-
-
-
-       static void DNSSD_API
-       RegisterRecordReply
-               (
-               DNSServiceRef                       sdRef,
-               DNSRecordRef                        RecordRef,
-               DNSServiceFlags                     flags,
-               DNSServiceErrorType                 errorCode,
-               void                                *context
-               );
-
-
-
-       inline BOOL
-
-       ShouldHandleReply( DNSServiceErrorType errorCode, CDNSSDEventManager *& eventManager );
-
-       
-
-       static LRESULT CALLBACK
-
-       WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
-
-
-
-       typedef std::map< SOCKET, CDNSSDService* > SocketMap;
-
-
-
-       static BOOL                             m_registeredWindowClass;
-
-       static HWND                             m_hiddenWindow;
-
-       static SocketMap                m_socketMap;
-
-       CDNSSDEventManager      *       m_eventManager;
-
-       BOOL                                    m_stopped;
-
-       BOOL                                    m_isPrimary;
-
-       DNSServiceRef                   m_primary;
-
-       DNSServiceRef                   m_subord;
-
-public:
-
-       STDMETHOD(EnumerateDomains)(DNSSDFlags flags, ULONG ifIndex, IDNSSDEventManager *eventManager, IDNSSDService **service);  
-
-       STDMETHOD(Browse)(DNSSDFlags flags, ULONG interfaceIndex, BSTR regtype, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** sdref);
-
-       STDMETHOD(Resolve)(DNSSDFlags flags, ULONG ifIndex, BSTR serviceName, BSTR regType, BSTR domain, IDNSSDEventManager* eventManager, IDNSSDService** service);
-
-       STDMETHOD(Register)(DNSSDFlags flags, ULONG ifIndex, BSTR name, BSTR regType, BSTR domain, BSTR host, USHORT port, ITXTRecord *record, IDNSSDEventManager *eventManager, IDNSSDService **service);
-
-       STDMETHOD(QueryRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, IDNSSDEventManager *eventManager, IDNSSDService **service);      
-
-       STDMETHOD(RegisterRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata, ULONG ttl, IDNSSDEventManager* eventManager, IDNSSDRecord** record);
-
-       STDMETHOD(AddRecord)(DNSSDFlags flags, DNSSDRRType rrtype, VARIANT rdata, ULONG ttl, IDNSSDRecord ** record);
-
-       STDMETHOD(ReconfirmRecord)(DNSSDFlags flags, ULONG ifIndex, BSTR fullname, DNSSDRRType rrtype, DNSSDRRClass rrclass, VARIANT rdata);
-
-       STDMETHOD(GetProperty)(BSTR prop, VARIANT * value);
-
-       STDMETHOD(GetAddrInfo)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, BSTR hostname, IDNSSDEventManager *eventManager, IDNSSDService **service);      
-
-       STDMETHOD(NATPortMappingCreate)(DNSSDFlags flags, ULONG ifIndex, DNSSDAddressFamily addressFamily, DNSSDProtocol protocol, USHORT internalPort, USHORT externalPort, ULONG ttl, IDNSSDEventManager *eventManager, IDNSSDService **service);
-
-       STDMETHOD(Stop)(void);
-
-};
-
-
-
-OBJECT_ENTRY_AUTO(__uuidof(DNSSDService), CDNSSDService)
-
diff --git a/mDNSWindows/DLLX/DNSSDService.rgs b/mDNSWindows/DLLX/DNSSDService.rgs
deleted file mode 100755 (executable)
index 8a84297..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-HKCR\r
-{\r
-       Bonjour.DNSSDService.1 = s 'DNSSDService Class'\r
-       {\r
-               CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}'\r
-       }\r
-       Bonjour.DNSSDService = s 'DNSSDService Class'\r
-       {\r
-               CLSID = s '{24CD4DE9-FF84-4701-9DC1-9B69E0D1090A}'\r
-               CurVer = s 'Bonjour.DNSSDService.1'\r
-       }\r
-       NoRemove CLSID\r
-       {\r
-               ForceRemove {24CD4DE9-FF84-4701-9DC1-9B69E0D1090A} = s 'DNSSDService Class'\r
-               {\r
-                       ProgID = s 'Bonjour.DNSSDService.1'\r
-                       VersionIndependentProgID = s 'Bonjour.DNSSDService'\r
-                       ForceRemove 'Programmable'\r
-                       InprocServer32 = s '%MODULE%'\r
-                       {\r
-                               val ThreadingModel = s 'Apartment'\r
-                       }\r
-                       val AppID = s '%APPID%'\r
-                       'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
-               }\r
-       }\r
-}\r
diff --git a/mDNSWindows/DLLX/StringServices.cpp b/mDNSWindows/DLLX/StringServices.cpp
deleted file mode 100755 (executable)
index 87f7aa9..0000000
+++ /dev/null
@@ -1,344 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-extern BOOL
-
-BSTRToUTF8
-
-       (
-
-       BSTR                    inString,
-
-       std::string     &       outString
-
-       )
-
-{
-
-       USES_CONVERSION;
-
-       
-
-       char    *       utf8String      = NULL;
-
-       OSStatus    err                 = kNoErr;
-
-
-
-       outString = "";
-
-       if ( inString )
-
-       {
-               TCHAR   *       utf16String     = NULL;
-               size_t      size                = 0;
-
-
-               utf16String = OLE2T( inString );
-
-               require_action( utf16String != NULL, exit, err = kUnknownErr );
-
-
-
-               if ( wcslen( utf16String ) > 0 )
-
-               {
-
-                       size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), NULL, 0, NULL, NULL );
-
-                       err = translate_errno( size != 0, GetLastError(), kUnknownErr );
-
-                       require_noerr( err, exit );
-
-
-
-                       try
-
-                       {
-
-                               utf8String = new char[ size + 1 ];
-
-                       }
-
-                       catch ( ... )
-
-                       {
-
-                               utf8String = NULL;
-
-                       }
-
-
-
-                       require_action( utf8String != NULL, exit, err = kNoMemoryErr );
-
-                       size = (size_t) WideCharToMultiByte( CP_UTF8, 0, utf16String, ( int ) wcslen( utf16String ), utf8String, (int) size, NULL, NULL);
-
-                       err = translate_errno( size != 0, GetLastError(), kUnknownErr );
-
-                       require_noerr( err, exit );
-
-
-
-                       // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
-
-                       // although it does return the correct size
-
-
-
-                       utf8String[size] = '\0';
-
-                       outString = utf8String;
-
-               }
-       }
-
-
-
-exit:
-
-
-
-       if ( utf8String != NULL )
-
-       {
-
-               delete [] utf8String;
-
-       }
-
-
-
-       return ( !err ) ? TRUE : FALSE;
-
-}
-
-
-
-
-
-extern BOOL
-
-UTF8ToBSTR
-
-       (
-
-       const char      *       inString,
-
-       CComBSTR        &       outString
-
-       )
-
-{
-
-       wchar_t *       unicode = NULL;
-
-       OSStatus        err             = 0;
-
-
-
-       if ( inString )
-
-       {
-               int n;
-
-               n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, NULL, 0 );
-
-           
-
-               if ( n > 0 )
-
-               {
-
-                       try
-
-                       {
-
-                               unicode = new wchar_t[ n ];
-
-                       }
-
-                       catch ( ... )
-
-                       {
-
-                               unicode = NULL;
-
-                       }
-
-
-
-                       require_action( unicode, exit, err = ERROR_INSUFFICIENT_BUFFER );
-
-
-
-                       n = MultiByteToWideChar( CP_UTF8, 0, inString, -1, unicode, n );
-
-               }
-
-
-
-               outString = unicode;
-
-       }
-
-
-exit:
-
-
-
-    if ( unicode != NULL )
-
-    {
-
-        delete [] unicode;
-
-       }
-
-
-
-       return ( !err ) ? TRUE : FALSE;
-
-}
-
-
-
-
-
-BOOL
-
-ByteArrayToVariant
-
-       (
-
-       const void      *       inArray,
-
-       size_t                  inArrayLen,
-
-       VARIANT         *       outVariant
-
-       )
-
-{
-
-       LPBYTE                  buf     = NULL;
-
-       HRESULT                 hr      = 0;
-
-       BOOL                    ok      = TRUE;
-
-
-
-       VariantClear( outVariant );
-
-       outVariant->vt          = VT_ARRAY|VT_UI1;
-
-       outVariant->parray      = SafeArrayCreateVector( VT_UI1, 0, ( ULONG ) inArrayLen );
-
-       require_action( outVariant->parray, exit, ok = FALSE );
-
-       hr = SafeArrayAccessData( outVariant->parray, (LPVOID *)&buf );
-
-       require_action( hr == S_OK, exit, ok = FALSE );
-
-       memcpy( buf, inArray, inArrayLen );
-
-       hr = SafeArrayUnaccessData( outVariant->parray );
-
-       require_action( hr == S_OK, exit, ok = FALSE );
-
-
-
-exit:
-
-
-
-       return ok;
-
-}
-
-
-
-
-
-extern BOOL
-
-VariantToByteArray
-       (
-       VARIANT                         *       inVariant,
-       std::vector< BYTE >     &       outArray
-       )
-{
-       BOOL ok = TRUE;
-
-       if ( V_VT( inVariant ) == VT_BSTR )
-       {
-               BSTR bstr = V_BSTR( inVariant );
-               std::string utf8;
-
-               BSTRToUTF8( bstr, utf8 );
-
-               outArray.reserve( utf8.size() );
-               outArray.assign( utf8.begin(), utf8.end() );
-       }
-       else if ( V_VT( inVariant ) == VT_ARRAY )
-       {
-               SAFEARRAY       *       psa                     = NULL;
-               BYTE            *       pData           = NULL;
-               ULONG                   cElements       = 0;
-               HRESULT                 hr;
-               
-               psa = V_ARRAY( inVariant );
-
-               require_action( psa, exit, ok = FALSE );
-
-               require_action( SafeArrayGetDim( psa ) == 1, exit, ok = FALSE );
-
-               hr = SafeArrayAccessData( psa, ( LPVOID* )&pData );
-
-               require_action( hr == S_OK, exit, ok = FALSE );
-
-               cElements = psa->rgsabound[0].cElements;
-
-               outArray.reserve( cElements );
-
-               outArray.assign( cElements, 0 );
-
-               memcpy( &outArray[ 0 ], pData, cElements );
-
-               SafeArrayUnaccessData( psa );
-       }
-       else
-       {
-               ok = FALSE;
-       }
-
-exit:
-
-       return ok;
-
-}
\ No newline at end of file
diff --git a/mDNSWindows/DLLX/StringServices.h b/mDNSWindows/DLLX/StringServices.h
deleted file mode 100755 (executable)
index 12aa996..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#ifndef _StringServices_h
-
-#define _StringServices_h
-
-
-
-#include <atlbase.h>
-
-#include <vector>
-
-#include <string>
-
-
-
-
-
-extern BOOL
-
-BSTRToUTF8
-
-       (
-
-       BSTR                    inString,
-
-       std::string     &       outString
-
-       );
-
-
-
-
-
-extern BOOL
-
-UTF8ToBSTR
-
-       (
-
-       const char      *       inString,
-
-       CComBSTR        &       outString
-
-       );
-
-
-
-
-
-extern BOOL
-
-ByteArrayToVariant
-
-       (
-
-       const void      *       inArray,
-
-       size_t                  inArrayLen,
-
-       VARIANT         *       outVariant
-
-       );
-
-
-
-
-
-extern BOOL
-
-VariantToByteArray
-
-       (
-
-       VARIANT                         *       inVariant,
-
-       std::vector< BYTE >     &       outArray
-
-       );
-
-
-
-
-
-#endif
\ No newline at end of file
diff --git a/mDNSWindows/DLLX/TXTRecord.cpp b/mDNSWindows/DLLX/TXTRecord.cpp
deleted file mode 100755 (executable)
index 2ebb67e..0000000
+++ /dev/null
@@ -1,382 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#include "stdafx.h"
-
-#include "TXTRecord.h"
-
-#include "StringServices.h"
-
-#include <DebugServices.h>
-
-
-
-
-
-// CTXTRecord
-
-
-
-
-
-STDMETHODIMP CTXTRecord::SetValue(BSTR key, VARIANT value)
-
-{
-
-       std::string                     keyUTF8;
-
-       ByteArray                       valueArray;
-
-       BOOL                            ok;
-
-       DNSServiceErrorType     err;
-
-       HRESULT                         hr = S_OK;
-
-
-
-       if ( !m_allocated )
-
-       {
-
-               TXTRecordCreate( &m_tref, 0, NULL );
-
-               m_allocated = TRUE;
-
-       }
-
-
-
-       ok = BSTRToUTF8( key, keyUTF8 );
-
-       require_action( ok, exit, hr = S_FALSE );
-
-
-
-       ok = VariantToByteArray( &value, valueArray );
-
-       require_action( ok, exit, hr = S_FALSE );
-
-
-
-       err = TXTRecordSetValue( &m_tref, keyUTF8.c_str(), ( uint8_t ) valueArray.size(), &valueArray[ 0 ] );
-
-       require_action( !err, exit, hr = S_FALSE );
-
-
-
-exit:
-
-
-
-       return hr;
-
-}
-
-
-
-STDMETHODIMP CTXTRecord::RemoveValue(BSTR key)
-
-{
-
-       HRESULT hr = S_OK;
-
-
-
-       if ( m_allocated )
-
-       {
-
-               std::string                     keyUTF8;
-
-               BOOL                            ok;
-
-               DNSServiceErrorType     err;
-
-
-
-               ok = BSTRToUTF8( key, keyUTF8 );
-
-               require_action( ok, exit, hr = S_FALSE );
-
-
-
-               err = TXTRecordRemoveValue( &m_tref, keyUTF8.c_str() );
-
-               require_action( !err, exit, hr = S_FALSE );
-
-       }
-
-
-
-exit:
-
-
-
-       return hr;
-
-}
-
-
-
-STDMETHODIMP CTXTRecord::ContainsKey(BSTR key, VARIANT_BOOL* retval)
-
-{
-
-       std::string keyUTF8;
-
-       int                     ret     = 0;
-
-       HRESULT         err     = S_OK;
-
-
-
-       if ( m_byteArray.size() > 0 )
-
-       {
-
-               BOOL ok;
-
-
-
-               ok = BSTRToUTF8( key, keyUTF8 );
-
-               require_action( ok, exit, err = S_FALSE );
-
-
-
-               ret = TXTRecordContainsKey( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str() );
-
-       }
-
-
-
-       *retval = ( ret ) ? VARIANT_TRUE : VARIANT_FALSE;
-
-
-
-exit:
-
-
-
-       return err;
-
-}
-
-
-
-STDMETHODIMP CTXTRecord::GetValueForKey(BSTR key, VARIANT* value)
-
-{
-
-       std::string             keyUTF8;
-
-       const void      *       rawValue;
-
-       uint8_t                 rawValueLen;
-
-       BOOL                    ok      = TRUE;
-
-       HRESULT                 hr      = S_OK;
-
-
-
-       VariantClear( value );
-
-
-
-       if ( m_byteArray.size() > 0 )
-
-       {
-
-               ok = BSTRToUTF8( key, keyUTF8 );
-
-               require_action( ok, exit, hr = S_FALSE );
-
-
-
-               rawValue = TXTRecordGetValuePtr( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], keyUTF8.c_str(), &rawValueLen );
-
-
-
-               if ( rawValue )
-
-               {
-
-                       ok = ByteArrayToVariant( rawValue, rawValueLen, value );
-
-                       require_action( ok, exit, hr = S_FALSE );
-
-               }
-
-       }
-
-
-
-exit:
-
-
-
-       return hr;
-
-}
-
-
-
-STDMETHODIMP CTXTRecord::GetCount(ULONG* count)
-
-{
-
-       *count = 0;
-
-       if ( m_allocated )
-       {
-               *count = TXTRecordGetCount( TXTRecordGetLength( &m_tref ), TXTRecordGetBytesPtr( &m_tref ) );
-       }
-       else if ( m_byteArray.size() > 0 )
-       {
-
-               *count = TXTRecordGetCount( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ] );
-
-       }
-
-
-
-       return S_OK;
-
-}
-
-
-
-STDMETHODIMP CTXTRecord::GetKeyAtIndex(ULONG index, BSTR* retval)
-
-{
-
-       char                            keyBuf[ 64 ];
-
-       uint8_t                         rawValueLen;
-
-       const void              *       rawValue;
-
-       CComBSTR                        temp;
-
-       DNSServiceErrorType     err;
-
-       BOOL                            ok;
-
-       HRESULT                         hr = S_OK;
-
-
-
-       err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue );
-
-       require_action( !err, exit, hr = S_FALSE );
-
-
-
-       ok = UTF8ToBSTR( keyBuf, temp );
-
-       require_action( ok, exit, hr = S_FALSE );
-
-
-
-       *retval = temp;
-
-
-
-exit:
-
-
-
-       return hr;
-
-}
-
-
-
-STDMETHODIMP CTXTRecord::GetValueAtIndex(ULONG index, VARIANT* retval)
-
-{
-
-       char                            keyBuf[ 64 ];
-
-       uint8_t                         rawValueLen;
-
-       const void              *       rawValue;
-
-       CComBSTR                        temp;
-
-       DNSServiceErrorType     err;
-
-       BOOL                            ok;
-
-       HRESULT                         hr = S_OK;
-
-
-
-       err = TXTRecordGetItemAtIndex( ( uint16_t ) m_byteArray.size(), &m_byteArray[ 0 ], ( uint16_t ) index, sizeof( keyBuf ), keyBuf, &rawValueLen, &rawValue );
-
-       require_action( !err, exit, hr = S_FALSE );
-
-
-
-       ok = ByteArrayToVariant( rawValue, rawValueLen, retval );
-
-       require_action( ok, exit, hr = S_FALSE );
-
-
-
-exit:
-
-
-
-       return hr;
-
-}
-
-
-
-
-
-void
-
-CTXTRecord::SetBytes
-
-       (
-
-       const unsigned char     *       bytes,
-
-       uint16_t                                len
-
-       )
-
-{
-
-       check ( bytes != NULL );
-
-       check( len );
-
-
-
-       m_byteArray.reserve( len );
-
-       m_byteArray.assign( bytes, bytes + len );
-
-}
-
diff --git a/mDNSWindows/DLLX/TXTRecord.h b/mDNSWindows/DLLX/TXTRecord.h
deleted file mode 100755 (executable)
index 67f3bdc..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#pragma once
-
-#include "resource.h"       // main symbols
-
-#include "DLLX.h"
-
-#include <vector>
-
-#include <dns_sd.h>
-
-
-
-
-
-#if defined(_WIN32_WCE) && !defined(_CE_DCOM) && !defined(_CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA)
-
-#error "Single-threaded COM objects are not properly supported on Windows CE platform, such as the Windows Mobile platforms that do not include full DCOM support. Define _CE_ALLOW_SINGLE_THREADED_OBJECTS_IN_MTA to force ATL to support creating single-thread COM object's and allow use of it's single-threaded COM object implementations. The threading model in your rgs file was set to 'Free' as that is the only threading model supported in non DCOM Windows CE platforms."
-
-#endif
-
-
-
-
-
-
-
-// CTXTRecord
-
-
-
-class ATL_NO_VTABLE CTXTRecord :
-
-       public CComObjectRootEx<CComSingleThreadModel>,
-
-       public CComCoClass<CTXTRecord, &CLSID_TXTRecord>,
-
-       public IDispatchImpl<ITXTRecord, &IID_ITXTRecord, &LIBID_Bonjour, /*wMajor =*/ 1, /*wMinor =*/ 0>
-
-{
-
-public:
-
-       CTXTRecord()
-
-       :
-
-               m_allocated( FALSE )
-
-       {
-
-       }
-
-
-
-DECLARE_REGISTRY_RESOURCEID(IDR_TXTRECORD)
-
-
-
-
-
-BEGIN_COM_MAP(CTXTRecord)
-
-       COM_INTERFACE_ENTRY(ITXTRecord)
-
-       COM_INTERFACE_ENTRY(IDispatch)
-
-END_COM_MAP()
-
-
-
-
-
-
-
-       DECLARE_PROTECT_FINAL_CONSTRUCT()
-
-
-
-       HRESULT FinalConstruct()
-
-       {
-
-               return S_OK;
-
-       }
-
-
-
-       void FinalRelease()
-
-       {
-
-               if ( m_allocated )
-
-               {
-
-                       TXTRecordDeallocate( &m_tref );
-
-               }
-
-       }
-
-
-
-public:
-
-
-
-       STDMETHOD(SetValue)(BSTR key, VARIANT value);
-
-       STDMETHOD(RemoveValue)(BSTR key);
-
-       STDMETHOD(ContainsKey)(BSTR key, VARIANT_BOOL* retval);
-
-       STDMETHOD(GetValueForKey)(BSTR key, VARIANT* value);
-
-       STDMETHOD(GetCount)(ULONG* count);
-
-       STDMETHOD(GetKeyAtIndex)(ULONG index, BSTR* retval);
-
-       STDMETHOD(GetValueAtIndex)(ULONG index, VARIANT* retval);
-
-
-
-private:
-
-
-
-       typedef std::vector< BYTE > ByteArray;
-
-       ByteArray               m_byteArray;
-
-       BOOL                    m_allocated;
-
-       TXTRecordRef    m_tref;
-
-
-
-public:
-
-
-
-       uint16_t
-
-       GetLen()
-
-       {
-
-               return TXTRecordGetLength( &m_tref );
-
-       }
-
-
-
-       const void*
-
-       GetBytes()
-
-       {
-
-               return TXTRecordGetBytesPtr( &m_tref );
-
-       }
-
-
-
-       void
-
-       SetBytes
-
-               (
-
-               const unsigned char     *       bytes,
-
-               uint16_t                                len
-
-               );
-
-};
-
-
-
-OBJECT_ENTRY_AUTO(__uuidof(TXTRecord), CTXTRecord)
-
diff --git a/mDNSWindows/DLLX/TXTRecord.rgs b/mDNSWindows/DLLX/TXTRecord.rgs
deleted file mode 100755 (executable)
index ce2fe1e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-HKCR\r
-{\r
-       Bonjour.TXTRecord.1 = s 'TXTRecord Class'\r
-       {\r
-               CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}'\r
-       }\r
-       Bonjour.TXTRecord = s 'TXTRecord Class'\r
-       {\r
-               CLSID = s '{AFEE063C-05BA-4248-A26E-168477F49734}'\r
-               CurVer = s 'Bonjour.TXTRecord.1'\r
-       }\r
-       NoRemove CLSID\r
-       {\r
-               ForceRemove {AFEE063C-05BA-4248-A26E-168477F49734} = s 'TXTRecord Class'\r
-               {\r
-                       ProgID = s 'Bonjour.TXTRecord.1'\r
-                       VersionIndependentProgID = s 'Bonjour.TXTRecord'\r
-                       ForceRemove 'Programmable'\r
-                       InprocServer32 = s '%MODULE%'\r
-                       {\r
-                               val ThreadingModel = s 'Apartment'\r
-                       }\r
-                       val AppID = s '%APPID%'\r
-                       'TypeLib' = s '{18FBED6D-F2B7-4EC8-A4A4-46282E635308}'\r
-               }\r
-       }\r
-}\r
diff --git a/mDNSWindows/DLLX/_IDNSSDEvents_CP.h b/mDNSWindows/DLLX/_IDNSSDEvents_CP.h
deleted file mode 100755 (executable)
index 90d778f..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-
-// Wizard-generated connection point proxy class
-// WARNING: This file may be regenerated by the wizard
-
-
-#pragma once
-
-template<class T>
-class CProxy_IDNSSDEvents :
-       public IConnectionPointImpl<T, &__uuidof(_IDNSSDEvents)>
-{
-public:
-       HRESULT Fire_DomainFound( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR domain)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[4];
-                               avarParams[3] = service;
-                               avarParams[2] = flags;
-                               avarParams[1] = ifIndex;
-                               avarParams[1].vt = VT_UI4;
-                               avarParams[0] = domain;
-                               avarParams[0].vt = VT_BSTR;
-                               DISPPARAMS params = { avarParams, NULL, 4, 0 };
-                               hr = pConnection->Invoke(1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_DomainLost( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR domain)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[4];
-                               avarParams[3] = service;
-                               avarParams[2] = flags;
-                               avarParams[1] = ifIndex;
-                               avarParams[1].vt = VT_UI4;
-                               avarParams[0] = domain;
-                               avarParams[0].vt = VT_BSTR;
-                               DISPPARAMS params = { avarParams, NULL, 4, 0 };
-                               hr = pConnection->Invoke(2, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_ServiceFound( IDNSSDService * browser,  DNSSDFlags flags,  ULONG ifIndex,  BSTR serviceName,  BSTR regType,  BSTR domain)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[6];
-                               avarParams[5] = browser;
-                               avarParams[4] = flags;
-                               avarParams[3] = ifIndex;
-                               avarParams[3].vt = VT_UI4;
-                               avarParams[2] = serviceName;
-                               avarParams[2].vt = VT_BSTR;
-                               avarParams[1] = regType;
-                               avarParams[1].vt = VT_BSTR;
-                               avarParams[0] = domain;
-                               avarParams[0].vt = VT_BSTR;
-                               DISPPARAMS params = { avarParams, NULL, 6, 0 };
-                               hr = pConnection->Invoke(3, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_ServiceLost( IDNSSDService * browser,  DNSSDFlags flags,  ULONG ifIndex,  BSTR serviceName,  BSTR regType,  BSTR domain)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[6];
-                               avarParams[5] = browser;
-                               avarParams[4] = flags;
-                               avarParams[3] = ifIndex;
-                               avarParams[3].vt = VT_UI4;
-                               avarParams[2] = serviceName;
-                               avarParams[2].vt = VT_BSTR;
-                               avarParams[1] = regType;
-                               avarParams[1].vt = VT_BSTR;
-                               avarParams[0] = domain;
-                               avarParams[0].vt = VT_BSTR;
-                               DISPPARAMS params = { avarParams, NULL, 6, 0 };
-                               hr = pConnection->Invoke(4, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_ServiceResolved( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR fullName,  BSTR hostName,  USHORT port,  ITXTRecord * record)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[7];
-                               avarParams[6] = service;
-                               avarParams[5] = flags;
-                               avarParams[4] = ifIndex;
-                               avarParams[4].vt = VT_UI4;
-                               avarParams[3] = fullName;
-                               avarParams[3].vt = VT_BSTR;
-                               avarParams[2] = hostName;
-                               avarParams[2].vt = VT_BSTR;
-                               avarParams[1] = port;
-                               avarParams[1].vt = VT_UI2;
-                               avarParams[0] = record;
-                               DISPPARAMS params = { avarParams, NULL, 7, 0 };
-                               hr = pConnection->Invoke(5, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_ServiceRegistered( IDNSSDService * service,  DNSSDFlags flags,  BSTR name,  BSTR regType,  BSTR domain)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[5];
-                               avarParams[4] = service;
-                               avarParams[3] = flags;
-                               avarParams[2] = name;
-                               avarParams[2].vt = VT_BSTR;
-                               avarParams[1] = regType;
-                               avarParams[1].vt = VT_BSTR;
-                               avarParams[0] = domain;
-                               avarParams[0].vt = VT_BSTR;
-                               DISPPARAMS params = { avarParams, NULL, 5, 0 };
-                               hr = pConnection->Invoke(6, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_QueryRecordAnswered( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR fullName,  DNSSDRRType rrtype,  DNSSDRRClass rrclass,  VARIANT rdata,  ULONG ttl)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[8];
-                               avarParams[7] = service;
-                               avarParams[6] = flags;
-                               avarParams[5] = ifIndex;
-                               avarParams[5].vt = VT_UI4;
-                               avarParams[4] = fullName;
-                               avarParams[4].vt = VT_BSTR;
-                               avarParams[3] = rrtype;
-                               avarParams[2] = rrclass;
-                               avarParams[1] = rdata;
-                               avarParams[0] = ttl;
-                               avarParams[0].vt = VT_UI4;
-                               DISPPARAMS params = { avarParams, NULL, 8, 0 };
-                               hr = pConnection->Invoke(7, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_RecordRegistered( IDNSSDRecord * record,  DNSSDFlags flags)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[2];
-                               avarParams[1] = record;
-                               avarParams[0] = flags;
-                               DISPPARAMS params = { avarParams, NULL, 2, 0 };
-                               hr = pConnection->Invoke(8, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_AddressFound( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  BSTR hostname,  DNSSDAddressFamily addressFamily,  BSTR address,  ULONG ttl)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[7];
-                               avarParams[6] = service;
-                               avarParams[5] = flags;
-                               avarParams[4] = ifIndex;
-                               avarParams[4].vt = VT_UI4;
-                               avarParams[3] = hostname;
-                               avarParams[3].vt = VT_BSTR;
-                               avarParams[2] = addressFamily;
-                               avarParams[1] = address;
-                               avarParams[1].vt = VT_BSTR;
-                               avarParams[0] = ttl;
-                               avarParams[0].vt = VT_UI4;
-                               DISPPARAMS params = { avarParams, NULL, 7, 0 };
-                               hr = pConnection->Invoke(9, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_MappingCreated( IDNSSDService * service,  DNSSDFlags flags,  ULONG ifIndex,  ULONG externalAddress,  DNSSDAddressFamily addressFamily,  DNSSDProtocol protocol,  USHORT internalPort,  USHORT externalPort,  ULONG ttl)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[9];
-                               avarParams[8] = service;
-                               avarParams[7] = flags;
-                               avarParams[6] = ifIndex;
-                               avarParams[6].vt = VT_UI4;
-                               avarParams[5] = externalAddress;
-                               avarParams[5].vt = VT_UI4;
-                               avarParams[4] = addressFamily;
-                               avarParams[3] = protocol;
-                               avarParams[2] = internalPort;
-                               avarParams[2].vt = VT_UI2;
-                               avarParams[1] = externalPort;
-                               avarParams[1].vt = VT_UI2;
-                               avarParams[0] = ttl;
-                               avarParams[0].vt = VT_UI4;
-                               DISPPARAMS params = { avarParams, NULL, 9, 0 };
-                               hr = pConnection->Invoke(10, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-       HRESULT Fire_OperationFailed( IDNSSDService * service,  DNSSDError error)
-       {
-               HRESULT hr = S_OK;
-               T * pThis = static_cast<T *>(this);
-               int cConnections = m_vec.GetSize();
-
-               for (int iConnection = 0; iConnection < cConnections; iConnection++)
-               {
-                       pThis->Lock();
-                       CComPtr<IUnknown> punkConnection = m_vec.GetAt(iConnection);
-                       pThis->Unlock();
-
-                       IDispatch * pConnection = static_cast<IDispatch *>(punkConnection.p);
-
-                       if (pConnection)
-                       {
-                               CComVariant avarParams[2];
-                               avarParams[1] = service;
-                               avarParams[0] = error;
-                               DISPPARAMS params = { avarParams, NULL, 2, 0 };
-                               hr = pConnection->Invoke(11, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &params, NULL, NULL, NULL);
-                       }
-               }
-               return hr;
-       }
-};
-
diff --git a/mDNSWindows/DLLX/dlldatax.c b/mDNSWindows/DLLX/dlldatax.c
deleted file mode 100755 (executable)
index a581532..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#ifdef _MERGE_PROXYSTUB // merge proxy stub DLL
-
-
-
-#define REGISTER_PROXY_DLL //DllRegisterServer, etc.
-
-
-
-#define _WIN32_WINNT 0x0500    //for WinNT 4.0 or Win95 with DCOM
-
-#define USE_STUBLESS_PROXY     //defined only with MIDL switch /Oicf
-
-
-
-#pragma comment(lib, "rpcns4.lib")
-
-#pragma comment(lib, "rpcrt4.lib")
-
-
-
-#define ENTRY_PREFIX   Prx
-
-
-
-#include "dlldata.c"
-
-#include "DLLX_p.c"
-
-
-
-#endif //_MERGE_PROXYSTUB
-
diff --git a/mDNSWindows/DLLX/dlldatax.h b/mDNSWindows/DLLX/dlldatax.h
deleted file mode 100755 (executable)
index f8816a3..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#pragma once
-
-
-
-#ifdef _MERGE_PROXYSTUB
-
-
-
-extern "C" 
-
-{
-
-BOOL WINAPI PrxDllMain(HINSTANCE hInstance, DWORD dwReason, 
-
-       LPVOID lpReserved);
-
-STDAPI PrxDllCanUnloadNow(void);
-
-STDAPI PrxDllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);
-
-STDAPI PrxDllRegisterServer(void);
-
-STDAPI PrxDllUnregisterServer(void);
-
-}
-
-
-
-#endif
-
diff --git a/mDNSWindows/DLLX/resource.h b/mDNSWindows/DLLX/resource.h
deleted file mode 100755 (executable)
index d8a0cbc..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by DLLX.rc
-//
-#define IDS_PROJNAME                    100
-#define IDR_DLLX                               101
-#define IDR_DNSSD                       102
-#define IDR_DNSSDSERVICE                103
-#define IDR_BROWSELISTENER              104
-#define IDR_RESOLVELISTENER             105
-#define IDR_TXTRECORD                   106
-#define IDR_ENUMERATEDOMAINSLISTENER    107
-#define IDR_REGISTERLISTENER            108
-#define IDR_QUERYRECORDLISTENER         109
-#define IDR_GETADDRINFOLISTENER         110
-#define IDR_DNSSDRECORD                 111
-#define IDR_REGISTERRECORDLISTENER      112
-#define IDR_NATPORTMAPPINGLISTENER      113
-#define IDR_DNSSDEVENTMANAGER           114
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        201
-#define _APS_NEXT_COMMAND_VALUE         32768
-#define _APS_NEXT_CONTROL_VALUE         201
-#define _APS_NEXT_SYMED_VALUE           115
-#endif
-#endif
diff --git a/mDNSWindows/DLLX/stdafx.h b/mDNSWindows/DLLX/stdafx.h
deleted file mode 100755 (executable)
index 66fb37b..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2009 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#pragma once
-
-
-
-#ifndef STRICT
-
-#define STRICT
-
-#endif
-
-
-
-// Modify the following defines if you have to target a platform prior to the ones specified below.
-
-// Refer to MSDN for the latest info on corresponding values for different platforms.
-
-#ifndef WINVER                         // Allow use of features specific to Windows XP or later.
-
-#define WINVER 0x0501          // Change this to the appropriate value to target other versions of Windows.
-
-#endif
-
-
-
-#ifndef _WIN32_WINNT           // Allow use of features specific to Windows XP or later.                   
-
-#define _WIN32_WINNT 0x0501    // Change this to the appropriate value to target other versions of Windows.
-
-#endif                                         
-
-
-
-#ifndef _WIN32_WINDOWS         // Allow use of features specific to Windows 98 or later.
-
-#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
-
-#endif
-
-
-
-#ifndef _WIN32_IE                      // Allow use of features specific to IE 6.0 or later.
-
-#define _WIN32_IE 0x0600       // Change this to the appropriate value to target other versions of IE.
-
-#endif
-
-
-
-#define _ATL_APARTMENT_THREADED
-
-#define _ATL_NO_AUTOMATIC_NAMESPACE
-
-
-
-#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS     // some CString constructors will be explicit
-
-
-
-
-
-#include "resource.h"
-
-#include <atlbase.h>
-
-#include <atlcom.h>
-
-
-
-using namespace ATL;
\ No newline at end of file
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.sln b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.sln
deleted file mode 100644 (file)
index 5ce1a0a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 7.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "ApplicationVS2002.vcproj", "{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
-EndProject
-Global
-       GlobalSection(SolutionConfiguration) = preSolution
-               ConfigName.0 = Debug
-               ConfigName.1 = Release
-       EndGlobalSection
-       GlobalSection(ProjectDependencies) = postSolution
-       EndGlobalSection
-       GlobalSection(ProjectConfiguration) = postSolution
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.ActiveCfg = Debug|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.Build.0 = Debug|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.ActiveCfg = Release|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.Build.0 = Release|Win32
-       EndGlobalSection
-       GlobalSection(ExtensibilityGlobals) = postSolution
-       EndGlobalSection
-       GlobalSection(ExtensibilityAddIns) = postSolution
-       EndGlobalSection
-EndGlobal
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2002.vcproj
deleted file mode 100644 (file)
index c1a2424..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-<?xml version="1.0" encoding = "Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.00"
-       Name="Application"
-       ProjectGUID="{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
-       Keyword="MFCProj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory="Debug"
-                       IntermediateDirectory="Debug"
-                       ConfigurationType="1"
-                       UseOfMFC="1"
-                       CharacterSet="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1"
-                               StringPooling="TRUE"
-                               MinimalRebuild="FALSE"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="FALSE"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               EnableFunctionLevelLinking="FALSE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               RuntimeTypeInfo="TRUE"
-                               UsePrecompiledHeader="2"
-                               PrecompiledHeaderThrough="StdAfx.h"
-                               PrecompiledHeaderFile=".\Debug/Application.pch"
-                               AssemblerListingLocation=".\Debug/"
-                               ObjectFile=".\Debug/"
-                               ProgramDataBaseFileName=".\Debug/"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"
-                               CompileAs="2"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="DNSServiceBrowser Debug.exe"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile=".\Debug/Application.pdb"
-                               SubSystem="2"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               MkTypLibCompatible="FALSE"
-                               SuppressStartupBanner="TRUE"
-                               TargetEnvironment="1"
-                               TypeLibraryName=".\Debug/Application.tlb"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_AFXDLL;_DEBUG"
-                               Culture="1033"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-               <Configuration
-                       Name="Release|Win32"
-                       OutputDirectory=".\Release"
-                       IntermediateDirectory=".\Release"
-                       ConfigurationType="1"
-                       UseOfMFC="1"
-                       CharacterSet="1"
-                       WholeProgramOptimization="FALSE">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="2"
-                               GlobalOptimizations="TRUE"
-                               InlineFunctionExpansion="0"
-                               FavorSizeOrSpeed="2"
-                               OmitFramePointers="TRUE"
-                               OptimizeForWindowsApplication="FALSE"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
-                               StringPooling="TRUE"
-                               MinimalRebuild="FALSE"
-                               RuntimeLibrary="0"
-                               BufferSecurityCheck="FALSE"
-                               EnableFunctionLevelLinking="FALSE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               RuntimeTypeInfo="TRUE"
-                               UsePrecompiledHeader="2"
-                               PrecompiledHeaderThrough="stdafx.h"
-                               PrecompiledHeaderFile=".\Release/Application.pch"
-                               AssemblerListingLocation=".\Release/"
-                               ObjectFile=".\Release/"
-                               ProgramDataBaseFileName=".\Release/"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               CompileAs="2"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="DNSServiceBrowser.exe"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib"
-                               ProgramDatabaseFile=".\Release/Application.pdb"
-                               SubSystem="2"
-                               OptimizeReferences="2"
-                               EnableCOMDATFolding="2"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               MkTypLibCompatible="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               TargetEnvironment="1"
-                               TypeLibraryName=".\Release/Application.tlb"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_AFXDLL;NDEBUG"
-                               Culture="1033"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-               </Configuration>
-       </Configurations>
-       <Files>
-               <Filter
-                       Name="Source Files"
-                       Filter="">
-                       <File
-                               RelativePath="Sources\AboutDialog.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\AboutDialog.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\Application.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\Application.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\ChooserDialog.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\ChooserDialog.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\LoginDialog.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\LoginDialog.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\StdAfx.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\StdAfx.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;rc">
-                       <File
-                               RelativePath="Resources\Application.ico">
-                       </File>
-                       <File
-                               RelativePath="Resources\Application.rc">
-                       </File>
-                       <File
-                               RelativePath="Resources\Application.rc2">
-                       </File>
-                       <File
-                               RelativePath=".\Resources\Resource.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Support"
-                       Filter="">
-                       <File
-                               RelativePath="..\..\..\CommonServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\DNSCommon.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\DNSCommon.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\DNSDigest.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\DNSServices\DNSServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\DebugServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\DebugServices.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="..\..\..\..\mDNSCore\uDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\uDNS.h">
-                       </File>
-               </Filter>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.sln b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.sln
deleted file mode 100644 (file)
index bdaaa3b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 8.00
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Application", "ApplicationVS2003.vcproj", "{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
-       ProjectSection(ProjectDependencies) = postProject
-       EndProjectSection
-EndProject
-Global
-       GlobalSection(SolutionConfiguration) = preSolution
-               Debug = Debug
-               Release = Release
-       EndGlobalSection
-       GlobalSection(ProjectConfiguration) = postSolution
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.ActiveCfg = Debug|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Debug.Build.0 = Debug|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.ActiveCfg = Release|Win32
-               {EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}.Release.Build.0 = Release|Win32
-       EndGlobalSection
-       GlobalSection(ExtensibilityGlobals) = postSolution
-       EndGlobalSection
-       GlobalSection(ExtensibilityAddIns) = postSolution
-       EndGlobalSection
-EndGlobal
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj b/mDNSWindows/DNSServiceBrowser/Windows/ApplicationVS2003.vcproj
deleted file mode 100644 (file)
index 3c8cb1c..0000000
+++ /dev/null
@@ -1,267 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>
-<VisualStudioProject
-       ProjectType="Visual C++"
-       Version="7.10"
-       Name="Application"
-       ProjectGUID="{EDE4B529-4CF5-4A49-9B6F-C10F0EA24278}"
-       Keyword="MFCProj">
-       <Platforms>
-               <Platform
-                       Name="Win32"/>
-       </Platforms>
-       <Configurations>
-               <Configuration
-                       Name="Debug|Win32"
-                       OutputDirectory="Debug"
-                       IntermediateDirectory="Debug"
-                       ConfigurationType="1"
-                       UseOfMFC="1"
-                       CharacterSet="1">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="0"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;DEBUG=1"
-                               StringPooling="TRUE"
-                               MinimalRebuild="FALSE"
-                               BasicRuntimeChecks="3"
-                               SmallerTypeCheck="FALSE"
-                               RuntimeLibrary="1"
-                               BufferSecurityCheck="TRUE"
-                               EnableFunctionLevelLinking="FALSE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               RuntimeTypeInfo="TRUE"
-                               UsePrecompiledHeader="2"
-                               PrecompiledHeaderThrough="StdAfx.h"
-                               PrecompiledHeaderFile=".\Debug/Application.pch"
-                               AssemblerListingLocation=".\Debug/"
-                               ObjectFile=".\Debug/"
-                               ProgramDataBaseFileName=".\Debug/"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               DebugInformationFormat="3"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="DNSServiceBrowser Debug.exe"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib"
-                               GenerateDebugInformation="TRUE"
-                               ProgramDatabaseFile=".\Debug/Application.pdb"
-                               SubSystem="2"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="_DEBUG"
-                               MkTypLibCompatible="FALSE"
-                               SuppressStartupBanner="TRUE"
-                               TargetEnvironment="1"
-                               TypeLibraryName=".\Debug/Application.tlb"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_AFXDLL;_DEBUG"
-                               Culture="1033"/>
-                       <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"
-                       UseOfMFC="1"
-                       CharacterSet="1"
-                       WholeProgramOptimization="FALSE">
-                       <Tool
-                               Name="VCCLCompilerTool"
-                               Optimization="2"
-                               GlobalOptimizations="TRUE"
-                               InlineFunctionExpansion="0"
-                               FavorSizeOrSpeed="2"
-                               OmitFramePointers="TRUE"
-                               OptimizeForWindowsApplication="FALSE"
-                               AdditionalIncludeDirectories=".\Resources;..\;..\..\..\;..\..\..\..\mDNSCore;..\..\..\DNSServices"
-                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
-                               StringPooling="TRUE"
-                               MinimalRebuild="FALSE"
-                               RuntimeLibrary="0"
-                               BufferSecurityCheck="FALSE"
-                               EnableFunctionLevelLinking="FALSE"
-                               ForceConformanceInForLoopScope="TRUE"
-                               RuntimeTypeInfo="TRUE"
-                               UsePrecompiledHeader="2"
-                               PrecompiledHeaderThrough="stdafx.h"
-                               PrecompiledHeaderFile=".\Release/Application.pch"
-                               AssemblerListingLocation=".\Release/"
-                               ObjectFile=".\Release/"
-                               ProgramDataBaseFileName=".\Release/"
-                               BrowseInformation="1"
-                               WarningLevel="4"
-                               WarnAsError="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               Detect64BitPortabilityProblems="TRUE"
-                               CompileAs="0"/>
-                       <Tool
-                               Name="VCCustomBuildTool"/>
-                       <Tool
-                               Name="VCLinkerTool"
-                               AdditionalOptions="/MACHINE:I386 /IGNORE:4089"
-                               AdditionalDependencies="ws2_32.lib"
-                               OutputFile="DNSServiceBrowser.exe"
-                               LinkIncremental="1"
-                               SuppressStartupBanner="TRUE"
-                               IgnoreDefaultLibraryNames="wsock32.lib"
-                               ProgramDatabaseFile=".\Release/Application.pdb"
-                               SubSystem="2"
-                               OptimizeReferences="2"
-                               EnableCOMDATFolding="2"/>
-                       <Tool
-                               Name="VCMIDLTool"
-                               PreprocessorDefinitions="NDEBUG"
-                               MkTypLibCompatible="TRUE"
-                               SuppressStartupBanner="TRUE"
-                               TargetEnvironment="1"
-                               TypeLibraryName=".\Release/Application.tlb"/>
-                       <Tool
-                               Name="VCPostBuildEventTool"/>
-                       <Tool
-                               Name="VCPreBuildEventTool"/>
-                       <Tool
-                               Name="VCPreLinkEventTool"/>
-                       <Tool
-                               Name="VCResourceCompilerTool"
-                               PreprocessorDefinitions="_AFXDLL;NDEBUG"
-                               Culture="1033"/>
-                       <Tool
-                               Name="VCWebServiceProxyGeneratorTool"/>
-                       <Tool
-                               Name="VCXMLDataGeneratorTool"/>
-                       <Tool
-                               Name="VCWebDeploymentTool"/>
-                       <Tool
-                               Name="VCManagedWrapperGeneratorTool"/>
-                       <Tool
-                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
-               </Configuration>
-       </Configurations>
-       <References>
-       </References>
-       <Files>
-               <Filter
-                       Name="Source Files"
-                       Filter="">
-                       <File
-                               RelativePath="Sources\AboutDialog.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\AboutDialog.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\Application.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\Application.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\ChooserDialog.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\ChooserDialog.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\LoginDialog.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\LoginDialog.h">
-                       </File>
-                       <File
-                               RelativePath="Sources\StdAfx.cpp">
-                       </File>
-                       <File
-                               RelativePath="Sources\StdAfx.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Resource Files"
-                       Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;rc">
-                       <File
-                               RelativePath="Resources\Application.ico">
-                       </File>
-                       <File
-                               RelativePath="Resources\Application.rc">
-                       </File>
-                       <File
-                               RelativePath="Resources\Application.rc2">
-                       </File>
-                       <File
-                               RelativePath=".\Resources\Resource.h">
-                       </File>
-               </Filter>
-               <Filter
-                       Name="Support"
-                       Filter="">
-                       <File
-                               RelativePath="..\..\..\CommonServices.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\DNSCommon.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\DNSCommon.h">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\DNSDigest.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\DNSServices\DNSServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\DebugServices.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\DebugServices.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="..\..\..\..\mDNSCore\uDNS.c">
-                       </File>
-                       <File
-                               RelativePath="..\..\..\..\mDNSCore\uDNS.h">
-                       </File>
-               </Filter>
-       </Files>
-       <Globals>
-       </Globals>
-</VisualStudioProject>
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.ico b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.ico
deleted file mode 100644 (file)
index b0a8639..0000000
Binary files a/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.ico and /dev/null differ
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc
deleted file mode 100644 (file)
index 3943139..0000000
+++ /dev/null
@@ -1,323 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "Resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "Resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
-    "#define _AFX_NO_OLE_RESOURCES\r\n"
-    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
-    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
-    "\r\n"
-    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
-    "#ifdef _WIN32\r\n"
-    "LANGUAGE 9, 1\r\n"
-    "#pragma code_page(1252)\r\n"
-    "#endif //_WIN32\r\n"
-    "#include ""Resources\\Application.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
-    "#include ""afxres.rc""         // Standard components\r\n"
-    "#endif\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDR_MAIN_ICON           ICON                    "Application.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_CHOOSER_DIALOG DIALOGEX 0, 0, 512, 316
-STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | 
-    WS_CAPTION | WS_SYSMENU
-EXSTYLE WS_EX_APPWINDOW
-CAPTION "DNSServiceBrowser"
-MENU IDR_CHOOSER_DIALOG_MENU
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
-    CONTROL         "",IDC_SERVICE_LIST,"SysListView32",LVS_REPORT | 
-                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
-                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,8,8,268,256
-    CONTROL         "",IDC_CHOOSER_LIST,"SysListView32",LVS_REPORT | 
-                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
-                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,282,8,224,170
-    CONTROL         "",IDC_DOMAIN_LIST,"SysListView32",LVS_REPORT | 
-                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | 
-                    LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,8,272,268,38
-    GROUPBOX        "Information",IDC_STATIC,282,182,224,128
-    RTEXT           "Name:",IDC_STATIC,288,195,38,8
-    EDITTEXT        IDC_INFO_NAME_TEXT,330,195,168,10,ES_AUTOHSCROLL | 
-                    ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
-    RTEXT           "IP address:",IDC_STATIC,288,208,38,8
-    EDITTEXT        IDC_INFO_IP_TEXT,330,208,168,10,ES_AUTOHSCROLL | 
-                    ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
-    RTEXT           "Interface:",IDC_STATIC,288,221,38,8
-    EDITTEXT        IDC_INFO_INTERFACE_TEXT,330,221,168,10,ES_AUTOHSCROLL | 
-                    ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
-    RTEXT           "Host Name:",IDC_STATIC,287,234,38,8
-    EDITTEXT        IDC_INFO_HOST_NAME_TEXT,330,234,168,10,ES_AUTOHSCROLL | 
-                    ES_READONLY | NOT WS_BORDER,WS_EX_STATICEDGE
-    RTEXT           "Text:",IDC_STATIC,288,247,38,8
-    EDITTEXT        IDC_INFO_TEXT_TEXT,330,247,168,57,ES_MULTILINE | 
-                    ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | NOT 
-                    WS_BORDER,WS_EX_STATICEDGE
-END
-
-IDD_ABOUT_DIALOG DIALOGEX 0, 0, 244, 73
-STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
-CAPTION "About DNSServiceBrowser"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
-    ICON            IDR_MAIN_ICON,IDC_ABOUT_APP_ICON,12,12,20,20
-    LTEXT           "DNSServiceBrowser",IDC_ABOUT_APP_NAME_TEXT,44,11,192,
-                    12
-    LTEXT           "Version 1.2d1",IDC_ABOUT_APP_VERSION_TEXT,44,25,192,8
-    LTEXT           "Copyright (C) 2002-2004 Apple Computer, Inc.",
-                    IDC_ABOUT_COPYRIGHT_TEXT,4,60,156,8
-    DEFPUSHBUTTON   "OK",IDOK,192,52,44,14
-END
-
-IDD_LOGIN DIALOGEX 0, 0, 180, 89
-STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION
-CAPTION "Login"
-FONT 8, "MS Shell Dlg", 0, 0, 0x0
-BEGIN
-    LTEXT           "Enter a username and password. Leave blank to use the default username and/or password.",
-                    IDC_STATIC,8,8,156,16,NOT WS_GROUP
-    RTEXT           "Username:",IDC_STATIC,10,34,36,8,NOT WS_GROUP
-    EDITTEXT        IDC_LOGIN_USERNAME_TEXT,50,32,118,12,ES_AUTOHSCROLL
-    RTEXT           "Password:",IDC_STATIC,10,50,36,8,NOT WS_GROUP
-    EDITTEXT        IDC_LOGIN_PASSWORD_TEXT,50,48,118,12,ES_PASSWORD | 
-                    ES_AUTOHSCROLL
-    DEFPUSHBUTTON   "OK",IDOK,129,70,44,14
-    PUSHBUTTON      "Cancel",IDCANCEL,77,70,44,14
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", "Apple Computer, Inc."
-            VALUE "FileDescription", "DNSServiceBrowser for Windows"
-            VALUE "FileVersion", "1, 0, 0, 1"
-            VALUE "InternalName", "DNSServiceBrowser for Windows"
-            VALUE "LegalCopyright", "Copyright (C) 2002-2004 Apple Computer, Inc."
-            VALUE "OriginalFilename", "DNSServiceBrowser.exe"
-            VALUE "ProductName", "DNSServiceBrowser for Windows"
-            VALUE "ProductVersion", "1, 0, 0, 1"
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Menu
-//
-
-IDR_CHOOSER_DIALOG_MENU MENU 
-BEGIN
-    POPUP "File"
-    BEGIN
-        MENUITEM "Close &Window\tCtrl+W",       ID_FILE_CLOSE
-        MENUITEM SEPARATOR
-        MENUITEM "Exit",                        ID_FILE_EXIT
-    END
-    POPUP "Help"
-    BEGIN
-        MENUITEM "About DNSServiceBrowser...", ID_HELP_ABOUT
-    END
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Accelerator
-//
-
-IDR_CHOOSER_DIALOG_MENU_ACCELERATORS ACCELERATORS 
-BEGIN
-    "S",            ID_FILE_SAVE,           VIRTKEY, CONTROL, NOINVERT
-    "W",            ID_FILE_CLOSE,          VIRTKEY, CONTROL, NOINVERT
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// RT_MANIFEST
-//
-
-1 RT_MANIFEST 
-BEGIN
-    0x3f3c, 0x6d78, 0x206c, 0x6576, 0x7372, 0x6f69, 0x3d6e, 0x3122, 0x302e, 
-    0x2022, 0x6e65, 0x6f63, 0x6964, 0x676e, 0x223d, 0x5455, 0x2d46, 0x2238, 
-    0x7320, 0x6174, 0x646e, 0x6c61, 0x6e6f, 0x3d65, 0x7922, 0x7365, 0x3f22, 
-    0x203e, 0x0a0d, 0x613c, 0x7373, 0x6d65, 0x6c62, 0x2079, 0x0a0d, 0x2020, 
-    0x7820, 0x6c6d, 0x736e, 0x223d, 0x7275, 0x3a6e, 0x6373, 0x6568, 0x616d, 
-    0x2d73, 0x696d, 0x7263, 0x736f, 0x666f, 0x2d74, 0x6f63, 0x3a6d, 0x7361, 
-    0x2e6d, 0x3176, 0x2022, 0x0a0d, 0x2020, 0x6d20, 0x6e61, 0x6669, 0x7365, 
-    0x5674, 0x7265, 0x6973, 0x6e6f, 0x223d, 0x2e31, 0x2230, 0x0d3e, 0x3c0a, 
-    0x7361, 0x6573, 0x626d, 0x796c, 0x6449, 0x6e65, 0x6974, 0x7974, 0x0d20, 
-    0x200a, 0x2020, 0x7020, 0x6f72, 0x6563, 0x7373, 0x726f, 0x7241, 0x6863, 
-    0x7469, 0x6365, 0x7574, 0x6572, 0x223d, 0x3878, 0x2236, 0x0d20, 0x200a, 
-    0x2020, 0x7620, 0x7265, 0x6973, 0x6e6f, 0x223d, 0x2e35, 0x2e31, 0x2e30, 
-    0x2230, 0x0a0d, 0x2020, 0x2020, 0x7974, 0x6570, 0x223d, 0x6977, 0x336e, 
-    0x2232, 0x0a0d, 0x2020, 0x2020, 0x616e, 0x656d, 0x223d, 0x7041, 0x2e70, 
-    0x7865, 0x2265, 0x3e2f, 0x0a0d, 0x2020, 0x2020, 0x643c, 0x7365, 0x7263, 
-    0x7069, 0x6974, 0x6e6f, 0x413e, 0x7269, 0x6f50, 0x7472, 0x4120, 0x6d64, 
-    0x6e69, 0x5520, 0x6974, 0x696c, 0x7974, 0x2f3c, 0x6564, 0x6373, 0x6972, 
-    0x7470, 0x6f69, 0x3e6e, 0x0a0d, 0x2020, 0x2020, 0x643c, 0x7065, 0x6e65, 
-    0x6564, 0x636e, 0x3e79, 0x0a0d, 0x2020, 0x2020, 0x643c, 0x7065, 0x6e65, 
-    0x6564, 0x746e, 0x7341, 0x6573, 0x626d, 0x796c, 0x0d3e, 0x200a, 0x2020, 
-    0x3c20, 0x7361, 0x6573, 0x626d, 0x796c, 0x6449, 0x6e65, 0x6974, 0x7974, 
-    0x0a0d, 0x2020, 0x2020, 0x2020, 0x2020, 0x7420, 0x7079, 0x3d65, 0x7722, 
-    0x6e69, 0x3233, 0x0d22, 0x200a, 0x2020, 0x2020, 0x2020, 0x2020, 0x616e, 
-    0x656d, 0x223d, 0x694d, 0x7263, 0x736f, 0x666f, 0x2e74, 0x6957, 0x646e, 
-    0x776f, 0x2e73, 0x6f43, 0x6d6d, 0x6e6f, 0x432d, 0x6e6f, 0x7274, 0x6c6f, 
-    0x2273, 0x0a0d, 0x2020, 0x2020, 0x2020, 0x2020, 0x7620, 0x7265, 0x6973, 
-    0x6e6f, 0x223d, 0x2e36, 0x2e30, 0x2e30, 0x2230, 0x0a0d, 0x2020, 0x2020, 
-    0x2020, 0x2020, 0x7020, 0x6275, 0x696c, 0x4b63, 0x7965, 0x6f54, 0x656b, 
-    0x3d6e, 0x3622, 0x3935, 0x6235, 0x3436, 0x3431, 0x6334, 0x6663, 0x6431, 
-    0x2266, 0x0a0d, 0x2020, 0x2020, 0x2020, 0x2020, 0x6c20, 0x6e61, 0x7567, 
-    0x6761, 0x3d65, 0x2a22, 0x0d22, 0x200a, 0x2020, 0x2020, 0x2020, 0x2020, 
-    0x7270, 0x636f, 0x7365, 0x6f73, 0x4172, 0x6372, 0x6968, 0x6574, 0x7463, 
-    0x7275, 0x3d65, 0x7822, 0x3638, 0x2f22, 0x0d3e, 0x200a, 0x2020, 0x3c20, 
-    0x642f, 0x7065, 0x6e65, 0x6564, 0x746e, 0x7341, 0x6573, 0x626d, 0x796c, 
-    0x0d3e, 0x200a, 0x2020, 0x3c20, 0x642f, 0x7065, 0x6e65, 0x6564, 0x636e, 
-    0x3e79, 0x0a0d, 0x2f3c, 0x7361, 0x6573, 0x626d, 0x796c, 0x0d3e, "\012" 
-END
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO 
-BEGIN
-    IDD_CHOOSER_DIALOG, DIALOG
-    BEGIN
-        RIGHTMARGIN, 468
-    END
-
-    IDD_LOGIN, DIALOG
-    BEGIN
-        BOTTOMMARGIN, 62
-    END
-END
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE 
-BEGIN
-    IDS_ABOUTBOX            "&About DNSServiceBrowser"
-    IDS_CHOOSER_DOMAIN_COLUMN_NAME "Domains"
-    IDP_SOCKETS_INIT_FAILED "Windows sockets initialization failed."
-    IDS_CHOOSER_SERVICE_COLUMN_TYPE "Services"
-    IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME "Name"
-    IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME "IP Address"
-    IDS_CHOOSER_SERVICE_COLUMN_DESC "Description"
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-#define _AFX_NO_SPLITTER_RESOURCES
-#define _AFX_NO_OLE_RESOURCES
-#define _AFX_NO_TRACKER_RESOURCES
-#define _AFX_NO_PROPERTY_RESOURCES
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE 9, 1
-#pragma code_page(1252)
-#endif //_WIN32
-#include "Resources\Application.rc2"  // non-Microsoft Visual C++ edited resources
-#include "afxres.rc"         // Standard components
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2 b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Application.rc2
deleted file mode 100644 (file)
index ec5e69f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef APSTUDIO_INVOKED
-       #error this file is not editable by Microsoft Visual C++
-#endif //APSTUDIO_INVOKED
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Resources/Resource.h b/mDNSWindows/DNSServiceBrowser/Windows/Resources/Resource.h
deleted file mode 100644 (file)
index 62602a4..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Application.rc
-//
-#define IDS_ABOUTBOX                    101
-#define IDS_CHOOSER_DOMAIN_COLUMN_NAME  102
-#define IDP_SOCKETS_INIT_FAILED         103
-#define IDS_CHOOSER_SERVICE_COLUMN_NAME 104
-#define IDS_CHOOSER_SERVICE_COLUMN_TYPE 104
-#define IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME 105
-#define IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME 106
-#define IDS_CHOOSER_SERVICE_COLUMN_DESC 107
-#define IDC_NAME_TEXT2                  124
-#define IDC_INFO_NAME_TEXT              124
-#define IDC_DESCRIPTION_TEXT2           125
-#define IDC_INFO_TEXT_TEXT              125
-#define IDC_IP_TEXT2                    126
-#define IDC_INFO_IP_TEXT                126
-#define IDC_IP_TEXT3                    127
-#define IDC_INFO_INTERFACE_TEXT         127
-#define IDR_MAIN_ICON                   128
-#define IDC_INFO_INTERFACE_TEXT2        128
-#define IDC_INFO_HOST_NAME_TEXT         128
-#define IDR_CHOOSER_DIALOG_MENU         136
-#define IDD_CHOOSER_DIALOG              143
-#define IDD_ABOUT_DIALOG                144
-#define IDD_LOGIN                       145
-#define IDR_CHOOSER_DIALOG_MENU_ACCELERATORS 146
-#define IDC_CHOOSER_LIST                1000
-#define IDC_SERVICE_LIST2               1001
-#define IDC_SERVICE_LIST                1001
-#define IDC_SERVICE_LIST3               1002
-#define IDC_DOMAIN_LIST                 1002
-#define IDC_ABOUT_APP_NAME_TEXT         1105
-#define IDC_ABOUT_APP_VERSION_TEXT      1106
-#define IDC_ABOUT_COPYRIGHT_TEXT        1107
-#define IDC_ABOUT_APP_ICON              1108
-#define IDC_LOGIN_USERNAME_TEXT         1182
-#define IDC_EDIT2                       1183
-#define IDC_LOGIN_PASSWORD_TEXT         1183
-#define ID_FILE_EXIT                    32771
-#define ID_HELP_ABOUT                   32806
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        164
-#define _APS_NEXT_COMMAND_VALUE         32809
-#define _APS_NEXT_CONTROL_VALUE         1185
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.cpp
deleted file mode 100644 (file)
index 8dd6b09..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       <stdlib.h>
-
-#include       "stdafx.h"
-
-#include       "AboutDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-//     Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(AboutDialog, CDialog)
-       //{{AFX_MSG_MAP(AboutDialog)
-       //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-//     AboutDialog
-//===========================================================================================================================
-
-AboutDialog::AboutDialog(CWnd* pParent /*=NULL*/)
-       : CDialog(AboutDialog::IDD, pParent)
-{
-       //{{AFX_DATA_INIT(AboutDialog)
-               // Note: the ClassWizard will add member initialization here
-       //}}AFX_DATA_INIT
-}
-
-//===========================================================================================================================
-//     OnInitDialog
-//===========================================================================================================================
-
-BOOL   AboutDialog::OnInitDialog() 
-{
-       CDialog::OnInitDialog();
-       return( true );
-}
-
-//===========================================================================================================================
-//     DoDataExchange
-//===========================================================================================================================
-
-void   AboutDialog::DoDataExchange(CDataExchange* pDX)
-{
-       CDialog::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(AboutDialog)
-               // Note: the ClassWizard will add DDX and DDV calls here
-       //}}AFX_DATA_MAP
-}
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/AboutDialog.h
deleted file mode 100644 (file)
index cdd257c..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !defined(AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_)
-#define AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include       "Resource.h"
-
-//===========================================================================================================================
-//     AboutDialog
-//===========================================================================================================================
-
-class  AboutDialog : public CDialog
-{
-       public:
-               
-               // Creation/Deletion
-               
-               AboutDialog(CWnd* pParent = NULL);   // standard constructor
-               
-               //{{AFX_DATA(AboutDialog)
-               enum { IDD = IDD_ABOUT_DIALOG };
-                       // Note: the ClassWizard will add data members here
-               //}}AFX_DATA
-               
-               // ClassWizard generated virtual function overrides
-               //{{AFX_VIRTUAL(AboutDialog)
-               protected:
-               virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-               //}}AFX_VIRTUAL
-
-       protected:
-
-               // Generated message map functions
-               //{{AFX_MSG(AboutDialog)
-               virtual BOOL OnInitDialog();
-               //}}AFX_MSG
-               DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_ABOUTDIALOG_H__4B8A04B2_9735_4F4A_AFCA_15F85FB3D763__INCLUDED_)
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.cpp
deleted file mode 100644 (file)
index f7f4b03..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       <assert.h>
-
-#include       "StdAfx.h"
-
-#include       "DNSServices.h"
-
-#include       "Application.h"
-
-#include       "ChooserDialog.h"
-
-#include       "stdafx.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-//     Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(Application, CWinApp)
-       //{{AFX_MSG_MAP(Application)
-               // NOTE - the ClassWizard will add and remove mapping macros here.
-               //    DO NOT EDIT what you see in these blocks of generated code!
-       //}}AFX_MSG
-       ON_COMMAND(ID_HELP, CWinApp::OnHelp)
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-Application            gApp;
-
-//===========================================================================================================================
-//     Application
-//===========================================================================================================================
-
-Application::Application( void )
-{
-       //
-}
-
-//===========================================================================================================================
-//     InitInstance
-//===========================================================================================================================
-
-BOOL   Application::InitInstance()
-{
-       DNSStatus               err;
-       
-       // Standard MFC initialization.
-
-#if( !defined( AFX_DEPRECATED ) )
-       #ifdef _AFXDLL
-               Enable3dControls();                     // Call this when using MFC in a shared DLL
-       #else
-               Enable3dControlsStatic();       // Call this when linking to MFC statically
-       #endif
-#endif
-
-       InitCommonControls();
-       
-       // Set up DNS Services.
-       
-       err = DNSServicesInitialize( 0, 512 );
-       assert( err == kDNSNoErr );
-       
-       // Create the chooser dialog.
-       
-       ChooserDialog *         dialog;
-       
-       m_pMainWnd = NULL;
-       dialog = new ChooserDialog;
-       dialog->Create( IDD_CHOOSER_DIALOG );
-       m_pMainWnd = dialog;
-       dialog->ShowWindow( SW_SHOW );
-       
-       return( true );
-}
-
-//===========================================================================================================================
-//     ExitInstance
-//===========================================================================================================================
-
-int    Application::ExitInstance( void )
-{
-       // Clean up DNS Services.
-       
-       DNSServicesFinalize();
-       return( 0 );
-}
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/Application.h
deleted file mode 100644 (file)
index 8368a49..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !defined(AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_)
-#define AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include       "stdafx.h"
-
-#ifndef __AFXWIN_H__
-       #error include 'stdafx.h' before including this file for PCH
-#endif
-
-#include       "Resource.h"
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-extern class Application               gApp;
-
-//===========================================================================================================================
-//     Application
-//===========================================================================================================================
-
-class  Application : public CWinApp
-{
-       public:
-               
-               // Creation/Deletion
-               
-               Application();
-               
-               // ClassWizard generated virtual function overrides
-               //{{AFX_VIRTUAL(Application)
-               public:
-               virtual BOOL InitInstance();
-               virtual int ExitInstance( void );
-               //}}AFX_VIRTUAL
-               
-               //{{AFX_MSG(Application)
-                       // NOTE - the ClassWizard will add and remove member functions here.
-                       //    DO NOT EDIT what you see in these blocks of generated code !
-               //}}AFX_MSG
-               DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_ADMIN_H__8663733F_6A15_439F_B568_F5A0125CD572__INCLUDED_)
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.cpp
deleted file mode 100644 (file)
index fe46be0..0000000
+++ /dev/null
@@ -1,1426 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       <assert.h>
-#include       <stdio.h>
-#include       <stdlib.h>
-#include       <string.h>
-#include       <time.h>
-
-#include       <algorithm>
-#include       <memory>
-
-#include       "stdafx.h"
-
-#include       "DNSServices.h"
-
-#include       "Application.h"
-#include       "AboutDialog.h"
-#include       "LoginDialog.h"
-#include       "Resource.h"
-
-#include       "ChooserDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-// Menus
-
-enum
-{
-       kChooserMenuIndexFile   = 0, 
-       kChooserMenuIndexHelp   = 1 
-};
-
-// Domain List
-       
-#define kDomainListDefaultDomainColumnWidth                            164 
-       
-// Service List
-
-#define kServiceListDefaultServiceColumnTypeWidth              146
-#define kServiceListDefaultServiceColumnDescWidth              230
-       
-// Chooser List
-       
-#define kChooserListDefaultNameColumnWidth                             190
-#define kChooserListDefaultIPColumnWidth                               120
-
-// Windows User Messages
-
-#define        WM_USER_DOMAIN_ADD                                                              ( WM_USER + 0x100 )
-#define        WM_USER_DOMAIN_REMOVE                                                   ( WM_USER + 0x101 )
-#define        WM_USER_SERVICE_ADD                                                             ( WM_USER + 0x102 )
-#define        WM_USER_SERVICE_REMOVE                                                  ( WM_USER + 0x103 )
-#define        WM_USER_RESOLVE                                                                 ( WM_USER + 0x104 )
-
-#if 0
-#pragma mark == Constants - Service Table ==
-#endif
-
-//===========================================================================================================================
-//     Constants - Service Table
-//===========================================================================================================================
-
-struct KnownServiceEntry
-{
-       const char *            serviceType;
-       const char *            description;
-       const char *            urlScheme;
-       bool                            useText;
-};
-
-static const KnownServiceEntry         kKnownServiceTable[] =
-{
-       { "_accountedge._tcp.",                 "MYOB AccountEdge",                                                                             "",                     false },
-       { "_aecoretech._tcp.",                  "Apple Application Engineering Services",                                       "",                     false },
-       { "_afpovertcp._tcp.",                  "Apple File Sharing (AFP)",                                                             "afp://",               false },
-       { "_airport._tcp.",                     "AirPort Base Station",                                                                         "",                     false }, 
-       { "_apple-sasl._tcp.",                  "Apple Password Server",                                                                        "",                     false },
-       { "_aquamon._tcp.",                     "AquaMon",                                                                                                      "",                     false },
-       { "_async._tcp",                                "address-o-sync",                                                                                       "",                     false },
-       { "_auth._tcp.",                                "Authentication Service",                                                                       "",                     false },
-       { "_bootps._tcp.",                              "Bootstrap Protocol Server",                                                            "",                     false },
-       { "_bousg._tcp.",                               "Bag Of Unusual Strategy Games",                                                        "",                     false },
-       { "_browse._udp.",                              "DNS Service Discovery",                                                                        "",                     false },
-       { "_cheat._tcp.",                               "The Cheat",                                                                                            "",                     false },
-       { "_chess._tcp",                                "Project Gridlock",                                                                             "",                     false },
-       { "_chfts._tcp",                                "Fluid Theme Server",                                                                           "",                     false },
-       { "_clipboard._tcp",                    "Clipboard Sharing",                                                                            "",                     false },
-       { "_contactserver._tcp.",               "Now Up-to-Date & Contact",                                                                     "",                     false },
-       { "_cvspserver._tcp",                   "CVS PServer",                                                                                          "",                     false },
-       { "_cytv._tcp.",                                "CyTV Network streaming for Elgato EyeTV",                                      "",                     false },
-       { "_daap._tcp.",                                "Digital Audio Access Protocol (iTunes)",                                       "daap://",              false }, 
-       { "_distcc._tcp",                               "Distributed Compiler",                                                                         "",                     false },
-       { "_dns-sd._udp",                               "DNS Service Discovery",                                                                        "",                     false },
-       { "_dpap._tcp.",                                "Digital Picture Access Protocol (iPhoto)",                                     "",                     false },
-       { "_earphoria._tcp.",                   "Earphoria",                                                                                            "",                     false },
-       { "_ecbyesfsgksc._tcp.",                "Net Monitor Anti-Piracy Service",                                                      "",                             false },
-       { "_eheap._tcp.",                               "Interactive Room Software",                                                            "",                             false },
-       { "_embrace._tcp.",                     "DataEnvoy",                                                                                            "",                             false },
-       { "_eppc._tcp.",                                "Remote AppleEvents",                                                                           "eppc://",              false }, 
-       { "_exec._tcp.",                                "Remote Process Execution",                                                                     "",                             false },
-       { "_facespan._tcp.",                    "FaceSpan",                                                                                                     "",                             false },
-       { "_fjork._tcp.",                               "Fjork",                                                                                                        "",                             false },
-       { "_ftp._tcp.",                                 "File Transfer (FTP)",                                                                          "ftp://",               false }, 
-       { "_ftpcroco._tcp.",                    "Crocodile FTP Server",                                                                         "",                             false },
-       { "_gbs-smp._tcp.",                     "SnapMail",                                                                                                     "",                             false },
-       { "_gbs-stp._tcp.",                     "SnapTalk",                                                                                                     "",                             false },
-       { "_grillezvous._tcp.",                 "Roxio ToastAnywhere(tm) Recorder Sharing",                                     "",                             false },
-       { "_h323._tcp.",                                "H.323",                                                                                                        "",                             false },
-       { "_hotwayd._tcp",                              "Hotwayd",                                                                                                      "",                     false },
-       { "_http._tcp.",                                "Web Server (HTTP)",                                                                            "http://",              true  }, 
-       { "_hydra._tcp",                                "SubEthaEdit",                                                                                          "",                     false },
-       { "_ica-networking._tcp.",              "Image Capture Networking",                                                                     "",                     false }, 
-       { "_ichalkboard._tcp.",                 "iChalk",                                                                                                       "",                     false }, 
-       { "_ichat._tcp.",                               "iChat",                                                                                                        "ichat://",             false }, 
-       { "_iconquer._tcp.",                    "iConquer",                                                                                                     "",                     false }, 
-       { "_imap._tcp.",                                "Internet Message Access Protocol",                                                     "",                             false },
-       { "_imidi._tcp.",                               "iMidi",                                                                                                        "",                             false },
-       { "_ipp._tcp.",                                 "Printer (IPP)",                                                                                        "ipp://",               false },
-       { "_ishare._tcp.",                              "iShare",                                                                                                       "",                             false },
-       { "_isparx._tcp.",                              "iSparx",                                                                                                       "",                             false },
-       { "_istorm._tcp",                               "iStorm",                                                                                                       "",                     false },
-       { "_iwork._tcp.",                               "iWork Server",                                                                                         "",                             false },
-       { "_liaison._tcp.",                     "Liaison",                                                                                                      "",                             false },
-       { "_login._tcp.",                               "Remote Login a la Telnet",                                                                     "",                             false },
-       { "_lontalk._tcp.",                     "LonTalk over IP (ANSI 852)",                                                           "",                             false },
-       { "_lonworks._tcp.",                    "Echelon LNS Remote Client",                                                            "",                             false },
-       { "_macfoh-remote._tcp.",               "MacFOH Remote",                                                                                        "",                             false },
-       { "_moneyworks._tcp.",                  "MoneyWorks",                                                                                           "",                             false },
-       { "_mp3sushi._tcp",                     "MP3 Sushi",                                                                                            "",                     false },
-       { "_mttp._tcp.",                                "MenuTunes Sharing",                                                                            "",                             false },
-       { "_ncbroadcast._tcp.",                 "Network Clipboard Broadcasts",                                                         "",                             false },
-       { "_ncdirect._tcp.",                    "Network Clipboard Direct Transfers",                                           "",                             false },
-       { "_ncsyncserver._tcp.",                "Network Clipboard Sync Server",                                                        "",                             false },
-       { "_newton-dock._tcp.",                 "Escale",                                                                                                       "",                             false },
-       { "_nfs._tcp",                                  "NFS",                                                                                                          "",                     false },
-       { "_nssocketport._tcp.",                "DO over NSSocketPort",                                                                         "",                             false },
-       { "_omni-bookmark._tcp.",               "OmniWeb",                                                                                                      "",                             false },
-       { "_openbase._tcp.",                    "OpenBase SQL",                                                                                         "",                             false },
-       { "_p2pchat._tcp.",                     "Peer-to-Peer Chat",                                                                            "",                             false },
-       { "_pdl-datastream._tcp.",              "Printer (PDL)",                                                                                        "pdl://",               false }, 
-       { "_poch._tcp.",                                "Parallel OperatiOn and Control Heuristic",                                     "",                             false },
-       { "_pop_2_ambrosia._tcp.",              "Pop-Pop",                                                                                                      "",                             false },
-       { "_pop3._tcp",                                 "POP3 Server",                                                                                          "",                     false },
-       { "_postgresql._tcp",                   "PostgreSQL Server",                                                                            "",                     false },
-       { "_presence._tcp",                     "iChat AV",                                                                                             "",                     false },
-       { "_printer._tcp.",                     "Printer (LPR)",                                                                                        "lpr://",               false }, 
-       { "_ptp._tcp.",                                 "Picture Transfer (PTP)",                                                                       "ptp://",               false },
-       { "_register._tcp",                     "DNS Service Discovery",                                                                        "",                     false },
-       { "_rfb._tcp.",                                 "Remote Frame Buffer",                                                                          "",                             false },
-       { "_riousbprint._tcp.",                 "Remote I/O USB Printer Protocol",                                                      "",                             false },
-       { "_rtsp._tcp.",                                "Real Time Stream Control Protocol",                                            "",                             false },
-       { "_safarimenu._tcp",                   "Safari Menu",                                                                                          "",                     false },
-       { "_scone._tcp",                                "Scone",                                                                                                        "",                     false },
-       { "_sdsharing._tcp.",                   "Speed Download",                                                                                       "",                             false },
-       { "_seeCard._tcp.",                     "seeCard",                                                                                                      "",                             false },
-       { "_services._udp.",                    "DNS Service Discovery",                                                                        "",                             false },
-       { "_shell._tcp.",                               "like exec, but automatic authentication",                                      "",                             false },
-       { "_shout._tcp.",                               "Shout",                                                                                                        "",                             false },
-       { "_shoutcast._tcp",                    "Nicecast",                                                                                             "",                     false },
-       { "_smb._tcp.",                                 "Windows File Sharing (SMB)",                                                           "smb://",               false }, 
-       { "_soap._tcp.",                                "Simple Object Access Protocol",                                                        "",                     false }, 
-       { "_spincrisis._tcp.",                  "Spin Crisis",                                                                                          "",                             false },
-       { "_spl-itunes._tcp.",                  "launchTunes",                                                                                          "",                             false },
-       { "_spr-itunes._tcp.",                  "netTunes",                                                                                                     "",                             false },
-       { "_ssh._tcp.",                                 "Secure Shell (SSH)",                                                                           "ssh://",               false }, 
-       { "_ssscreenshare._tcp",                "Screen Sharing",                                                                                       "",                     false },
-       { "_sge-exec._tcp",                     "Sun Grid Engine (Execution Host)",                                             "",                     false },
-       { "_sge-qmaster._tcp",                  "Sun Grid Engine (Master)",                                                             "",                     false },
-       { "_stickynotes._tcp",                  "Sticky Notes",                                                                                         "",                     false },
-       { "_strateges._tcp",                    "Strateges",                                                                                            "",                     false },
-       { "_sxqdea._tcp",                               "Synchronize! Pro X",                                                                           "",                     false },
-       { "_sybase-tds._tcp",                   "Sybase Server",                                                                                        "",                     false },
-       { "_tce._tcp",                                  "Power Card",                                                                                           "",                     false },
-       { "_teamlist._tcp",                     "ARTIS Team Task",                                                                                      "",                     false },
-       { "_teleport._tcp",                     "teleport",                                                                                                     "",                     false },
-       { "_telnet._tcp.",                              "Telnet",                                                                                                       "telnet://",    false }, 
-       { "_tftp._tcp.",                                "Trivial File Transfer (TFTP)",                                                         "tftp://",              false }, 
-       { "_tinavigator._tcp.",                 "TI Navigator",                                                                                         "",                     false }, 
-       { "_tivo_servemedia._tcp",              "TiVo",                                                                                                         "",                     false },
-       { "_upnp._tcp.",                                "Universal Plug and Play",                                                                      "",                     false }, 
-       { "_utest._tcp.",                               "uTest",                                                                                                        "",                     false }, 
-       { "_vue4rendercow._tcp",                "VueProRenderCow",                                                                                      "",                     false },
-       { "_webdav._tcp.",                              "WebDAV",                                                                                                       "webdav://",    false }, 
-       { "_whamb._tcp.",                               "Whamb",                                                                                                        "",                             false }, 
-       { "_workstation._tcp",                  "Macintosh Manager",                                                                            "",                     false },
-       { "_ws._tcp",                                   "Web Services",                                                                                         "",                     false },
-       { "_xserveraid._tcp.",                  "Xserve RAID",                                                                                          "xsr://",               false }, 
-       { "_xsync._tcp.",                               "Xserve RAID Synchronization",                                                          "",                             false }, 
-       
-       { "",                                                   "",                                                                                                                     "",                             false }, 
-       
-       // Unofficial and invalid service types that will be phased out:
-       
-       { "_clipboardsharing._tcp.",                    "ClipboardSharing",                                                                     "",                             false }, 
-       { "_MacOSXDupSuppress._tcp.",                   "Mac OS X Duplicate Suppression",                                       "",                             false }, 
-       { "_netmonitorserver._tcp.",                    "Net Monitor Server",                                                           "",                             false }, 
-       { "_networkclipboard._tcp.",                    "Network Clipboard",                                                            "",                             false }, 
-       { "_slimdevices_slimp3_cli._tcp.",              "SliMP3 Server Command-Line Interface",                         "",                             false }, 
-       { "_slimdevices_slimp3_http._tcp.",             "SliMP3 Server Web Interface",                                          "",                             false }, 
-       { "_tieducationalhandhelddevice._tcp.", "TI Connect Manager",                                                           "",                             false }, 
-       { "_tivo_servemedia._tcp.",                             "TiVo",                                                                                         "",                             false }, 
-       
-       { NULL,                                                 NULL,                                                                                                           NULL,                   false }, 
-};
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-//     Structures
-//===========================================================================================================================
-
-struct DomainEventInfo
-{
-       DNSBrowserEventType             eventType;
-       CString                                 domain;
-       DNSNetworkAddress               ifIP;
-};
-
-struct ServiceEventInfo
-{
-       DNSBrowserEventType             eventType;
-       std::string                             name;
-       std::string                             type;
-       std::string                             domain;
-       DNSNetworkAddress               ifIP;
-};
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-static void
-       BrowserCallBack( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode,
-               const DNSBrowserEvent * inEvent );
-
-static char *  DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, size_t inLen, char *outString );
-
-static DWORD   UTF8StringToStringObject( const char *inUTF8, CString &inObject );
-static DWORD   StringObjectToUTF8String( CString &inObject, std::string &outUTF8 );
-
-#if 0
-#pragma mark == Message Map ==
-#endif
-
-//===========================================================================================================================
-//     Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(ChooserDialog, CDialog)
-       //{{AFX_MSG_MAP(ChooserDialog)
-       ON_WM_SYSCOMMAND()
-       ON_NOTIFY(LVN_ITEMCHANGED, IDC_DOMAIN_LIST, OnDomainListChanged)
-       ON_NOTIFY(LVN_ITEMCHANGED, IDC_SERVICE_LIST, OnServiceListChanged)
-       ON_NOTIFY(LVN_ITEMCHANGED, IDC_CHOOSER_LIST, OnChooserListChanged)
-       ON_NOTIFY(NM_DBLCLK, IDC_CHOOSER_LIST, OnChooserListDoubleClick)
-       ON_COMMAND(ID_HELP_ABOUT, OnAbout)
-       ON_WM_INITMENUPOPUP()
-       ON_WM_ACTIVATE()
-       ON_COMMAND(ID_FILE_CLOSE, OnFileClose)
-       ON_COMMAND(ID_FILE_EXIT, OnExit)
-       ON_WM_CLOSE()
-       ON_WM_NCDESTROY()
-       //}}AFX_MSG_MAP
-       ON_MESSAGE( WM_USER_DOMAIN_ADD, OnDomainAdd )
-       ON_MESSAGE( WM_USER_DOMAIN_REMOVE, OnDomainRemove )
-       ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
-       ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
-       ON_MESSAGE( WM_USER_RESOLVE, OnResolve )
-END_MESSAGE_MAP()
-
-#if 0
-#pragma mark == Routines ==
-#endif
-
-//===========================================================================================================================
-//     ChooserDialog
-//===========================================================================================================================
-
-ChooserDialog::ChooserDialog( CWnd *inParent )
-       : CDialog( ChooserDialog::IDD, inParent)
-{
-       //{{AFX_DATA_INIT(ChooserDialog)
-               // Note: the ClassWizard will add member initialization here
-       //}}AFX_DATA_INIT
-       
-       // Load menu accelerator table.
-
-       mMenuAcceleratorTable = ::LoadAccelerators( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDR_CHOOSER_DIALOG_MENU_ACCELERATORS ) );
-       assert( mMenuAcceleratorTable );
-       
-       mBrowser                        = NULL;
-       mIsServiceBrowsing      = false;
-}
-
-//===========================================================================================================================
-//     ~ChooserDialog
-//===========================================================================================================================
-
-ChooserDialog::~ChooserDialog( void )
-{
-       if( mBrowser )
-       {
-               DNSStatus               err;
-               
-               err = DNSBrowserRelease( mBrowser, 0 );
-               assert( err == kDNSNoErr );
-       }
-}
-
-//===========================================================================================================================
-//     DoDataExchange
-//===========================================================================================================================
-
-void ChooserDialog::DoDataExchange( CDataExchange *pDX )
-{
-       CDialog::DoDataExchange(pDX);
-
-       //{{AFX_DATA_MAP(ChooserDialog)
-       DDX_Control(pDX, IDC_SERVICE_LIST, mServiceList);
-       DDX_Control(pDX, IDC_DOMAIN_LIST, mDomainList);
-       DDX_Control(pDX, IDC_CHOOSER_LIST, mChooserList);
-       //}}AFX_DATA_MAP
-}
-
-//===========================================================================================================================
-//     OnInitDialog
-//===========================================================================================================================
-
-BOOL   ChooserDialog::OnInitDialog( void )
-{
-       HICON                   icon;
-       BOOL                    result;
-       CString                 tempString;
-       DNSStatus               err;
-       
-       // Initialize our parent.
-
-       CDialog::OnInitDialog();
-       
-       // Set up the window icon.
-       
-       icon = AfxGetApp()->LoadIcon( IDR_MAIN_ICON );
-       assert( icon );
-       if( icon )
-       {
-               SetIcon( icon, TRUE );          // Set big icon
-               SetIcon( icon, FALSE );         // Set small icon
-       }
-       
-       // Set up the Domain List.
-       
-       result = tempString.LoadString( IDS_CHOOSER_DOMAIN_COLUMN_NAME );
-       assert( result );
-       mDomainList.InsertColumn( 0, tempString, LVCFMT_LEFT, kDomainListDefaultDomainColumnWidth );
-       
-       // Set up the Service List.
-       
-       result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_TYPE );
-       assert( result );
-       mServiceList.InsertColumn( 0, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnTypeWidth );
-       
-       result = tempString.LoadString( IDS_CHOOSER_SERVICE_COLUMN_DESC );
-       assert( result );
-       mServiceList.InsertColumn( 1, tempString, LVCFMT_LEFT, kServiceListDefaultServiceColumnDescWidth );
-       
-       PopulateServicesList();
-       
-       // Set up the Chooser List.
-       
-       result = tempString.LoadString( IDS_CHOOSER_CHOOSER_NAME_COLUMN_NAME );
-       assert( result );
-       mChooserList.InsertColumn( 0, tempString, LVCFMT_LEFT, kChooserListDefaultNameColumnWidth );
-       
-       result = tempString.LoadString( IDS_CHOOSER_CHOOSER_IP_COLUMN_NAME );
-       assert( result );
-       mChooserList.InsertColumn( 1, tempString, LVCFMT_LEFT, kChooserListDefaultIPColumnWidth );
-       
-       // Set up the other controls.
-       
-       UpdateInfoDisplay();
-       
-       // Start browsing for domains.
-       
-       err = DNSBrowserCreate( 0, BrowserCallBack, this, &mBrowser );
-       assert( err == kDNSNoErr );
-       
-       err = DNSBrowserStartDomainSearch( mBrowser, 0 );
-       assert( err == kDNSNoErr );
-       
-       return( true );
-}
-
-//===========================================================================================================================
-//     OnFileClose
-//===========================================================================================================================
-
-void ChooserDialog::OnFileClose() 
-{
-       OnClose();
-}
-
-//===========================================================================================================================
-//     OnActivate
-//===========================================================================================================================
-
-void ChooserDialog::OnActivate( UINT nState, CWnd* pWndOther, BOOL bMinimized )
-{
-       // Always make the active window the "main" window so modal dialogs work better and the app quits after closing 
-       // the last window.
-
-       gApp.m_pMainWnd = this;
-
-       CDialog::OnActivate(nState, pWndOther, bMinimized);
-}
-
-//===========================================================================================================================
-//     PostNcDestroy
-//===========================================================================================================================
-
-void   ChooserDialog::PostNcDestroy() 
-{
-       // Call the base class to do the normal cleanup.
-
-       delete this;
-}
-
-//===========================================================================================================================
-//     PreTranslateMessage
-//===========================================================================================================================
-
-BOOL   ChooserDialog::PreTranslateMessage(MSG* pMsg) 
-{
-       BOOL            result;
-       
-       result = false;
-       assert( mMenuAcceleratorTable );
-       if( mMenuAcceleratorTable )
-       {
-               result = ::TranslateAccelerator( m_hWnd, mMenuAcceleratorTable, pMsg );
-       }
-       if( !result )
-       {
-               result = CDialog::PreTranslateMessage( pMsg );
-       }
-       return( result );
-}
-
-//===========================================================================================================================
-//     OnInitMenuPopup
-//===========================================================================================================================
-
-void   ChooserDialog::OnInitMenuPopup( CMenu *pPopupMenu, UINT nIndex, BOOL bSysMenu ) 
-{
-       CDialog::OnInitMenuPopup( pPopupMenu, nIndex, bSysMenu );
-
-       switch( nIndex )
-       {
-               case kChooserMenuIndexFile:
-                       break;
-
-               case kChooserMenuIndexHelp:
-                       break;
-
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     OnExit
-//===========================================================================================================================
-
-void ChooserDialog::OnExit() 
-{
-       OnClose();
-}
-
-//===========================================================================================================================
-//     OnAbout
-//===========================================================================================================================
-
-void   ChooserDialog::OnAbout() 
-{
-       AboutDialog             dialog;
-       
-       dialog.DoModal();
-}
-
-//===========================================================================================================================
-//     OnSysCommand
-//===========================================================================================================================
-
-void   ChooserDialog::OnSysCommand( UINT inID, LPARAM inParam ) 
-{
-       CDialog::OnSysCommand( inID, inParam );
-}
-
-//===========================================================================================================================
-//     OnClose
-//===========================================================================================================================
-
-void ChooserDialog::OnClose() 
-{
-       StopBrowsing();
-       
-       gApp.m_pMainWnd = this;
-       DestroyWindow();
-}
-
-//===========================================================================================================================
-//     OnNcDestroy
-//===========================================================================================================================
-
-void ChooserDialog::OnNcDestroy() 
-{
-       gApp.m_pMainWnd = this;
-
-       CDialog::OnNcDestroy();
-}
-
-//===========================================================================================================================
-//     OnDomainListChanged
-//===========================================================================================================================
-
-void   ChooserDialog::OnDomainListChanged( NMHDR *pNMHDR, LRESULT *pResult ) 
-{
-       UNUSED_ALWAYS( pNMHDR );
-       
-       // Domain list changes have similar effects to service list changes so reuse that code path by calling it here.
-       
-       OnServiceListChanged( NULL, NULL );
-       
-       *pResult = 0;
-}
-
-//===========================================================================================================================
-//     OnServiceListChanged
-//===========================================================================================================================
-
-void   ChooserDialog::OnServiceListChanged( NMHDR *pNMHDR, LRESULT *pResult ) 
-{
-       int                             selectedType;
-       int                             selectedDomain;
-       
-       UNUSED_ALWAYS( pNMHDR );
-       
-       // Stop any existing service search.
-       
-       StopBrowsing();
-       
-       // If a domain and service type are selected, start searching for the service type on the domain.
-       
-       selectedType    = mServiceList.GetNextItem( -1, LVNI_SELECTED );
-       selectedDomain  = mDomainList.GetNextItem( -1, LVNI_SELECTED );
-       
-       if( ( selectedType >= 0 ) && ( selectedDomain >= 0 ) )
-       {
-               CString                         s;
-               std::string                     utf8;
-               const char *            type;
-               
-               s = mDomainList.GetItemText( selectedDomain, 0 );
-               StringObjectToUTF8String( s, utf8 );
-               type = mServiceTypes[ selectedType ].serviceType.c_str();
-               if( *type != '\0' )
-               {
-                       StartBrowsing( type, utf8.c_str() );
-               }
-       }
-       
-       if( pResult )
-       {
-               *pResult = 0;
-       }
-}
-
-//===========================================================================================================================
-//     OnChooserListChanged
-//===========================================================================================================================
-
-void   ChooserDialog::OnChooserListChanged( NMHDR *pNMHDR, LRESULT *pResult ) 
-{
-       UNUSED_ALWAYS( pNMHDR );
-       
-       UpdateInfoDisplay();
-       *pResult = 0;
-}
-
-//===========================================================================================================================
-//     OnChooserListDoubleClick
-//===========================================================================================================================
-
-void   ChooserDialog::OnChooserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult )
-{
-       int             selectedItem;
-       
-       UNUSED_ALWAYS( pNMHDR );
-       
-       // Display the service instance if it is selected. Otherwise, clear all the info.
-       
-       selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
-       if( selectedItem >= 0 )
-       {
-               ServiceInstanceInfo *                   p;
-               CString                                                 url;
-               const KnownServiceEntry *               service;
-               
-               assert( selectedItem < (int) mServiceInstances.size() );
-               p = &mServiceInstances[ selectedItem ];
-               
-               // Search for a known service type entry that matches.
-               
-               for( service = kKnownServiceTable; service->serviceType; ++service )
-               {
-                       if( p->type == service->serviceType )
-                       {
-                               break;
-                       }
-               }
-               if( service->serviceType )
-               {
-                       const char *            text;
-                       
-                       // Create a URL representing the service instance.
-                       
-                       if( strcmp( service->serviceType, "_smb._tcp." ) == 0 )
-                       {
-                               // Special case for SMB (no port number).
-                               
-                               url.Format( TEXT( "%s%s/" ), service->urlScheme, (const char *) p->ip.c_str() ); 
-                       }
-                       else if( strcmp( service->serviceType, "_ftp._tcp." ) == 0 )
-                       {
-                               // Special case for FTP to get login info.
-
-                               LoginDialog             dialog;
-                               CString                 username;
-                               CString                 password;
-                               
-                               if( !dialog.GetLogin( username, password ) )
-                               {
-                                       goto exit;
-                               }
-                               
-                               // Build URL in the following format:
-                               //
-                               // ftp://[username[:password]@]<ip>
-                               
-                               url += service->urlScheme;
-                               if( username.GetLength() > 0 )
-                               {
-                                       url += username;
-                                       if( password.GetLength() > 0 )
-                                       {
-                                               url += ':';
-                                               url += password;
-                                       }
-                                       url += '@';
-                               }
-                               url += p->ip.c_str();
-                       }
-                       else if( strcmp( service->serviceType, "_http._tcp." ) == 0 )
-                       {
-                               // Special case for HTTP to exclude "path=" if present.
-                               
-                               text = service->useText ? p->text.c_str() : "";
-                               if( strncmp( text, "path=", 5 ) == 0 )
-                               {
-                                       text += 5;
-                               }
-                               if( *text != '/' )
-                               {
-                                       url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
-                               }
-                               else
-                               {
-                                       url.Format( TEXT( "%s%s%s" ), service->urlScheme, (const char *) p->ip.c_str(), text );
-                               }
-                       }
-                       else
-                       {
-                               text = service->useText ? p->text.c_str() : "";
-                               url.Format( TEXT( "%s%s/%s" ), service->urlScheme, (const char *) p->ip.c_str(), text ); 
-                       }
-                       
-                       // Let the system open the URL in the correct app.
-                       
-                       {
-                               CWaitCursor             waitCursor;
-                               
-                               ShellExecute( NULL, TEXT( "open" ), url, TEXT( "" ), TEXT( "c:\\" ), SW_SHOWNORMAL );
-                       }
-               }
-       }
-
-exit:
-       *pResult = 0;
-}
-
-//===========================================================================================================================
-//     OnCancel
-//===========================================================================================================================
-
-void ChooserDialog::OnCancel() 
-{
-       // Do nothing.
-}
-
-//===========================================================================================================================
-//     PopulateServicesList
-//===========================================================================================================================
-
-void   ChooserDialog::PopulateServicesList( void )
-{
-       ServiceTypeVector::iterator             i;
-       CString                                                 type;
-       CString                                                 desc;
-       std::string                                             tmp;
-       
-       // Add a fixed list of known services.
-       
-       if( mServiceTypes.empty() )
-       {
-               const KnownServiceEntry *               service;
-               
-               for( service = kKnownServiceTable; service->serviceType; ++service )
-               {
-                       ServiceTypeInfo         info;
-                       
-                       info.serviceType        = service->serviceType;
-                       info.description        = service->description;
-                       info.urlScheme          = service->urlScheme;
-                       mServiceTypes.push_back( info );
-               }
-       }
-       
-       // Add each service to the list.
-       
-       for( i = mServiceTypes.begin(); i != mServiceTypes.end(); ++i )
-       {
-               const char *            p;
-               const char *            q;
-               
-               p  = ( *i ).serviceType.c_str();
-               if( *p == '_' ) ++p;                                                    // Skip leading '_'.
-               q  = strchr( p, '.' );                                                  // Find first '.'.
-               if( q ) tmp.assign( p, (size_t)( q - p ) );             // Use only up to the first '.'.
-               else    tmp.assign( p );                                                // No '.' so use the entire string.
-               UTF8StringToStringObject( tmp.c_str(), type );
-               UTF8StringToStringObject( ( *i ).description.c_str(), desc );
-               
-               int             n;
-               
-               n = mServiceList.GetItemCount();
-               mServiceList.InsertItem( n, type );
-               mServiceList.SetItemText( n, 1, desc );
-       }
-       
-       // Select the first service type by default.
-       
-       if( !mServiceTypes.empty() )
-       {
-               mServiceList.SetItemState( 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
-       }
-}
-
-//===========================================================================================================================
-//     UpdateInfoDisplay
-//===========================================================================================================================
-
-void   ChooserDialog::UpdateInfoDisplay( void )
-{
-       int                                                     selectedItem;
-       std::string                                     name;
-       CString                                         s;
-       std::string                                     ip;
-       std::string                                     ifIP;
-       std::string                                     text;
-       std::string                                     textNewLines;
-       std::string                                     hostName;
-       CWnd *                                          item;
-       std::string::iterator           i;
-       
-       // Display the service instance if it is selected. Otherwise, clear all the info.
-       
-       selectedItem = mChooserList.GetNextItem( -1, LVNI_SELECTED );
-       if( selectedItem >= 0 )
-       {
-               ServiceInstanceInfo *           p;
-               
-               assert( selectedItem < (int) mServiceInstances.size() );
-               p = &mServiceInstances[ selectedItem ];
-               
-               name            = p->name;
-               ip                      = p->ip;
-               ifIP            = p->ifIP;
-               text            = p->text;
-               hostName        = p->hostName;
-
-               // Sync up the list items with the actual data (IP address may change).
-               
-               UTF8StringToStringObject( ip.c_str(), s );
-               mChooserList.SetItemText( selectedItem, 1, s );
-       }
-       
-       // Name
-       
-       item = (CWnd *) this->GetDlgItem( IDC_INFO_NAME_TEXT );
-       assert( item );
-       UTF8StringToStringObject( name.c_str(), s );
-       item->SetWindowText( s );
-       
-       // IP
-       
-       item = (CWnd *) this->GetDlgItem( IDC_INFO_IP_TEXT );
-       assert( item );
-       UTF8StringToStringObject( ip.c_str(), s );
-       item->SetWindowText( s );
-       
-       // Interface
-       
-       item = (CWnd *) this->GetDlgItem( IDC_INFO_INTERFACE_TEXT );
-       assert( item );
-       UTF8StringToStringObject( ifIP.c_str(), s );
-       item->SetWindowText( s );
-       
-
-       item = (CWnd *) this->GetDlgItem( IDC_INFO_HOST_NAME_TEXT );
-       assert( item );
-       UTF8StringToStringObject( hostName.c_str(), s );
-       item->SetWindowText( s );
-
-       // Text
-       
-       item = (CWnd *) this->GetDlgItem( IDC_INFO_TEXT_TEXT );
-       assert( item );
-       for( i = text.begin(); i != text.end(); ++i )
-       {
-               if( *i == '\1' )
-               {
-                       textNewLines += "\r\n";
-               }
-               else
-               {
-                       textNewLines += *i;
-               }
-       }
-       UTF8StringToStringObject( textNewLines.c_str(), s );
-       item->SetWindowText( s );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     OnDomainAdd
-//===========================================================================================================================
-
-LONG   ChooserDialog::OnDomainAdd( WPARAM inWParam, LPARAM inLParam )
-{
-       DomainEventInfo *                                               p;
-       std::auto_ptr < DomainEventInfo >               pAutoPtr;
-       int                                                                             n;
-       int                                                                             i;
-       CString                                                                 domain;
-       CString                                                                 s;
-       bool                                                                    found;
-       
-       UNUSED_ALWAYS( inWParam );
-       
-       assert( inLParam );
-       p = reinterpret_cast <DomainEventInfo *> ( inLParam );
-       pAutoPtr.reset( p );
-       
-       // Search to see if we already know about this domain. If not, add it to the list.
-       
-       found = false;
-       domain = p->domain;
-       n = mDomainList.GetItemCount();
-       for( i = 0; i < n; ++i )
-       {
-               s = mDomainList.GetItemText( i, 0 );
-               if( s == domain )
-               {
-                       found = true;
-                       break;
-               }
-       }
-       if( !found )
-       {
-               int             selectedItem;
-               
-               mDomainList.InsertItem( n, domain );
-               
-               // If no domains are selected and the domain being added is a default domain, select it.
-               
-               selectedItem = mDomainList.GetNextItem( -1, LVNI_SELECTED );
-               if( ( selectedItem < 0 ) && ( p->eventType == kDNSBrowserEventTypeAddDefaultDomain ) )
-               {
-                       mDomainList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
-               }
-       }
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     OnDomainRemove
-//===========================================================================================================================
-
-LONG   ChooserDialog::OnDomainRemove( WPARAM inWParam, LPARAM inLParam )
-{
-       DomainEventInfo *                                               p;
-       std::auto_ptr < DomainEventInfo >               pAutoPtr;
-       int                                                                             n;
-       int                                                                             i;
-       CString                                                                 domain;
-       CString                                                                 s;
-       bool                                                                    found;
-       
-       UNUSED_ALWAYS( inWParam );
-       
-       assert( inLParam );
-       p = reinterpret_cast <DomainEventInfo *> ( inLParam );
-       pAutoPtr.reset( p );
-       
-       // Search to see if we know about this domain. If so, remove it from the list.
-       
-       found = false;
-       domain = p->domain;
-       n = mDomainList.GetItemCount();
-       for( i = 0; i < n; ++i )
-       {
-               s = mDomainList.GetItemText( i, 0 );
-               if( s == domain )
-               {
-                       found = true;
-                       break;
-               }
-       }
-       if( found )
-       {
-               mDomainList.DeleteItem( i );
-       }
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     OnServiceAdd
-//===========================================================================================================================
-
-LONG   ChooserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
-{
-       ServiceEventInfo *                                              p;
-       std::auto_ptr < ServiceEventInfo >              pAutoPtr;
-       
-       UNUSED_ALWAYS( inWParam );
-       
-       assert( inLParam );
-       p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
-       pAutoPtr.reset( p );
-       
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     OnServiceRemove
-//===========================================================================================================================
-
-LONG   ChooserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
-{
-       ServiceEventInfo *                                              p;
-       std::auto_ptr < ServiceEventInfo >              pAutoPtr;
-       bool                                                                    found;
-       int                                                                             n;
-       int                                                                             i;
-       
-       UNUSED_ALWAYS( inWParam );
-       
-       assert( inLParam );
-       p = reinterpret_cast <ServiceEventInfo *> ( inLParam );
-       pAutoPtr.reset( p );
-       
-       // Search to see if we know about this service instance. If so, remove it from the list.
-       
-       found = false;
-       n = (int) mServiceInstances.size();
-       for( i = 0; i < n; ++i )
-       {
-               ServiceInstanceInfo *           q;
-               
-               // If the name, type, domain, and interface match, treat it as the same service instance.
-               
-               q = &mServiceInstances[ i ];
-               if( ( p->name   == q->name )    && 
-                       ( p->type       == q->type )    && 
-                       ( p->domain     == q->domain ) )
-               {
-                       found = true;
-                       break;
-               }
-       }
-       if( found )
-       {
-               mChooserList.DeleteItem( i );
-               assert( i < (int) mServiceInstances.size() );
-               mServiceInstances.erase( mServiceInstances.begin() + i );
-       }
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     OnResolve
-//===========================================================================================================================
-
-LONG   ChooserDialog::OnResolve( WPARAM inWParam, LPARAM inLParam )
-{
-       ServiceInstanceInfo *                                           p;
-       std::auto_ptr < ServiceInstanceInfo >           pAutoPtr;
-       int                                                                                     selectedType;
-       int                                                                                     n;
-       int                                                                                     i;
-       bool                                                                            found;
-       
-       UNUSED_ALWAYS( inWParam );
-       
-       assert( inLParam );
-       p = reinterpret_cast <ServiceInstanceInfo *> ( inLParam );
-       pAutoPtr.reset( p );
-       
-       // Make sure it is for an item of the correct type. This handles any resolves that may have been queued up.
-       
-       selectedType = mServiceList.GetNextItem( -1, LVNI_SELECTED );
-       assert( selectedType >= 0 );
-       if( selectedType >= 0 )
-       {
-               assert( selectedType <= (int) mServiceTypes.size() );
-               if( p->type != mServiceTypes[ selectedType ].serviceType )
-               {
-                       goto exit;
-               }
-       }
-       
-       // Search to see if we know about this service instance. If so, update its info. Otherwise, add it to the list.
-       
-       found = false;
-       n = (int) mServiceInstances.size();
-       for( i = 0; i < n; ++i )
-       {
-               ServiceInstanceInfo *           q;
-               
-               // If the name, type, domain, and interface matches, treat it as the same service instance.
-                               
-               q = &mServiceInstances[ i ];
-               if( ( p->name   == q->name )    && 
-                       ( p->type       == q->type )    && 
-                       ( p->domain     == q->domain )  && 
-                       ( p->ifIP       == q->ifIP ) )
-               {
-                       found = true;
-                       break;
-               }
-       }
-       if( found )
-       {
-               mServiceInstances[ i ] = *p;
-       }
-       else
-       {
-               CString         s;
-               
-               mServiceInstances.push_back( *p );
-               UTF8StringToStringObject( p->name.c_str(), s );
-               mChooserList.InsertItem( n, s );
-               
-               UTF8StringToStringObject( p->ip.c_str(), s );
-               mChooserList.SetItemText( n, 1, s );
-               
-               // If this is the only item, select it.
-               
-               if( n == 0 )
-               {
-                       mChooserList.SetItemState( n, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED );
-               }
-       }
-       UpdateInfoDisplay();
-
-exit:
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     StartBrowsing
-//===========================================================================================================================
-
-void   ChooserDialog::StartBrowsing( const char *inType, const char *inDomain )
-{
-       DNSStatus               err;
-       
-       assert( mServiceInstances.empty() );
-       assert( mChooserList.GetItemCount() == 0 );
-       assert( !mIsServiceBrowsing );
-       
-       mChooserList.DeleteAllItems();
-       mServiceInstances.clear();
-       
-       mIsServiceBrowsing = true;
-       err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, inType, inDomain );
-       assert( err == kDNSNoErr );
-}
-
-//===========================================================================================================================
-//     StopBrowsing
-//===========================================================================================================================
-
-void   ChooserDialog::StopBrowsing( void )
-{
-       // If searching, stop.
-       
-       if( mIsServiceBrowsing )
-       {
-               DNSStatus               err;
-               
-               mIsServiceBrowsing = false;
-               err = DNSBrowserStopServiceSearch( mBrowser, 0 );
-               assert( err == kDNSNoErr );
-       }
-       
-       // Remove all service instances.
-       
-       mChooserList.DeleteAllItems();
-       assert( mChooserList.GetItemCount() == 0 );
-       mServiceInstances.clear();
-       assert( mServiceInstances.empty() );
-       UpdateInfoDisplay();
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     BrowserCallBack
-//===========================================================================================================================
-
-static void
-       BrowserCallBack( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode,
-               const DNSBrowserEvent * inEvent )
-{
-       ChooserDialog *         dialog;
-       UINT                            message;
-       BOOL                            posted;
-       
-       UNUSED_ALWAYS( inStatusCode );
-       UNUSED_ALWAYS( inRef );
-       
-       // Check parameters.
-       
-       assert( inContext );
-       dialog = reinterpret_cast <ChooserDialog *> ( inContext );
-       
-       try
-       {
-               switch( inEvent->type )
-               {
-                       case kDNSBrowserEventTypeRelease:
-                               break;
-                       
-                       // Domains
-                       
-                       case kDNSBrowserEventTypeAddDomain:
-                       case kDNSBrowserEventTypeAddDefaultDomain:
-                       case kDNSBrowserEventTypeRemoveDomain:
-                       {
-                               DomainEventInfo *                                               domain;
-                               std::auto_ptr < DomainEventInfo >               domainAutoPtr;
-                               
-                               domain = new DomainEventInfo;
-                               domainAutoPtr.reset( domain );
-                               
-                               domain->eventType       = inEvent->type;
-                               domain->domain          = inEvent->data.addDomain.domain;
-                               domain->ifIP            = inEvent->data.addDomain.interfaceIP;
-                               
-                               message = ( inEvent->type == kDNSBrowserEventTypeRemoveDomain ) ? WM_USER_DOMAIN_REMOVE : WM_USER_DOMAIN_ADD;
-                               posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) domain );
-                               assert( posted );
-                               if( posted )
-                               {
-                                       domainAutoPtr.release();
-                               }
-                               break;
-                       }
-                       
-                       // Services
-                       
-                       case kDNSBrowserEventTypeAddService:
-                       case kDNSBrowserEventTypeRemoveService:
-                       {
-                               ServiceEventInfo *                                              service;
-                               std::auto_ptr < ServiceEventInfo >              serviceAutoPtr;
-                               
-                               service = new ServiceEventInfo;
-                               serviceAutoPtr.reset( service );
-                               
-                               service->eventType      = inEvent->type;
-                               service->name           = inEvent->data.addService.name;
-                               service->type           = inEvent->data.addService.type;
-                               service->domain         = inEvent->data.addService.domain;
-                               service->ifIP           = inEvent->data.addService.interfaceIP;
-                               
-                               message = ( inEvent->type == kDNSBrowserEventTypeAddService ) ? WM_USER_SERVICE_ADD : WM_USER_SERVICE_REMOVE;
-                               posted = ::PostMessage( dialog->GetSafeHwnd(), message, 0, (LPARAM) service );
-                               assert( posted );
-                               if( posted )
-                               {
-                                       serviceAutoPtr.release();
-                               }
-                               break;
-                       }
-                       
-                       // Resolves
-                       
-                       case kDNSBrowserEventTypeResolved:
-                               if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4  )
-                               {
-                                       ServiceInstanceInfo *                                           serviceInstance;
-                                       std::auto_ptr < ServiceInstanceInfo >           serviceInstanceAutoPtr;
-                                       char                                                                            s[ 32 ];
-                                       
-                                       serviceInstance = new ServiceInstanceInfo;
-                                       serviceInstanceAutoPtr.reset( serviceInstance );
-                                       
-                                       serviceInstance->name           = inEvent->data.resolved->name;
-                                       serviceInstance->type           = inEvent->data.resolved->type;
-                                       serviceInstance->domain         = inEvent->data.resolved->domain;
-                                       serviceInstance->ip                     = DNSNetworkAddressToString( &inEvent->data.resolved->address, sizeof( s ), s );
-                                       serviceInstance->ifIP           = DNSNetworkAddressToString( &inEvent->data.resolved->interfaceIP, sizeof( s ), s );
-                                       serviceInstance->text           = inEvent->data.resolved->textRecord;
-                                       serviceInstance->hostName       = inEvent->data.resolved->hostName;
-
-                                       posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_RESOLVE, 0, (LPARAM) serviceInstance );
-                                       assert( posted );
-                                       if( posted )
-                                       {
-                                               serviceInstanceAutoPtr.release();
-                                       }
-                               }
-                               break;
-                       
-                       default:
-                               break;
-               }
-       }
-       catch( ... )
-       {
-               // Don't let exceptions escape.
-       }
-}
-
-//===========================================================================================================================
-//     DNSNetworkAddressToString
-//
-//     Note: Currently only supports IPv4 network addresses.
-//===========================================================================================================================
-
-static char *  DNSNetworkAddressToString( const DNSNetworkAddress *inAddr, size_t inLen, char *outString )
-{
-       const DNSUInt8 *                p;
-       DNSUInt16                               port;
-       
-       p = inAddr->u.ipv4.addr.v8;
-       port = ntohs( inAddr->u.ipv4.port.v16 );
-       if( port != kDNSPortInvalid )
-       {
-               snprintf( outString, inLen, "%u.%u.%u.%u:%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ], port );
-       }
-       else
-       {
-               snprintf( outString, inLen, "%u.%u.%u.%u", p[ 0 ], p[ 1 ], p[ 2 ], p[ 3 ] );
-       }
-       return( outString );
-}
-
-//===========================================================================================================================
-//     UTF8StringToStringObject
-//===========================================================================================================================
-
-static DWORD   UTF8StringToStringObject( const char *inUTF8, CString &inObject )
-{
-       DWORD           err;
-       int                     n;
-       BSTR            unicode;
-       
-       unicode = NULL;
-       
-       n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
-       if( n > 0 )
-       {
-               unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
-               if( !unicode )
-               {
-                       err = ERROR_INSUFFICIENT_BUFFER;
-                       goto exit;
-               }
-
-               n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
-               try
-               {
-                       inObject = unicode;
-               }
-               catch( ... )
-               {
-                       err = ERROR_NO_UNICODE_TRANSLATION;
-                       goto exit;
-               }
-       }
-       else
-       {
-               inObject = "";
-       }
-       err = 0;
-       
-exit:
-       if( unicode )
-       {
-               free( unicode );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     StringObjectToUTF8String
-//===========================================================================================================================
-
-static DWORD   StringObjectToUTF8String( CString &inObject, std::string &outUTF8 )
-{
-       DWORD           err;
-       BSTR            unicode;
-       int                     nUnicode;
-       int                     n;
-       char *          utf8;
-       
-       unicode = NULL;
-       utf8    = NULL;
-       
-       nUnicode = inObject.GetLength();
-       if( nUnicode > 0 )
-       {
-               unicode = inObject.AllocSysString();
-               n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, NULL, 0, NULL, NULL );
-               assert( n > 0 );
-               
-               utf8 = (char *) malloc( (size_t) n );
-               assert( utf8 );
-               if( !utf8 ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; }
-               
-               n = WideCharToMultiByte( CP_UTF8, 0, unicode, nUnicode, utf8, n, NULL, NULL );
-               assert( n > 0 );
-               
-               try
-               {
-                       outUTF8.assign( utf8, n );
-               }
-               catch( ... )
-               {
-                       err = ERROR_NO_UNICODE_TRANSLATION;
-                       goto exit;
-               }
-       }
-       else
-       {
-               outUTF8.clear();
-       }
-       err = 0;
-       
-exit:
-       if( unicode )
-       {
-               SysFreeString( unicode );
-       }
-       if( utf8 )
-       {
-               free( utf8 );
-       }
-       return( err );
-}
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/ChooserDialog.h
deleted file mode 100644 (file)
index 41fd827..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !defined(AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_)
-#define AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#include       <string>
-#include       <vector>
-
-#include       "afxcmn.h"
-
-#include       "Resource.h"
-
-#include       "DNSServices.h"
-
-//===========================================================================================================================
-//     Structures
-//===========================================================================================================================
-
-struct ServiceInstanceInfo
-{
-       std::string             name;
-       std::string             type;
-       std::string             domain;
-       std::string             ip;
-       std::string             text;
-       std::string             ifIP;
-       std::string             hostName;
-};
-
-struct ServiceTypeInfo
-{
-       std::string             serviceType;
-       std::string             description;
-       std::string             urlScheme;
-};
-
-//===========================================================================================================================
-//     ChooserDialog
-//===========================================================================================================================
-
-class  ChooserDialog : public CDialog
-{
-       public:
-
-               ChooserDialog(CWnd* pParent = NULL);
-               virtual ~ChooserDialog( void );
-               
-               //{{AFX_DATA(ChooserDialog)
-               enum { IDD = IDD_CHOOSER_DIALOG };
-               CListCtrl mServiceList;
-               CListCtrl mDomainList;
-               CListCtrl mChooserList;
-               //}}AFX_DATA
-
-               // ClassWizard generated virtual function overrides
-               //{{AFX_VIRTUAL(ChooserDialog)
-               public:
-               virtual BOOL PreTranslateMessage(MSG* pMsg);
-               protected:
-               virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
-               virtual void PostNcDestroy();
-               //}}AFX_VIRTUAL
-
-       protected:
-               
-               typedef std::vector < ServiceInstanceInfo >             ServiceInstanceVector;
-               typedef std::vector < ServiceTypeInfo >                 ServiceTypeVector;
-               
-               HACCEL                                          mMenuAcceleratorTable;
-               DNSBrowserRef                           mBrowser;
-               BOOL                                            mIsServiceBrowsing;
-               ServiceInstanceVector           mServiceInstances;
-               ServiceTypeVector                       mServiceTypes;
-               
-       public:
-
-               void    PopulateServicesList( void );
-               void    UpdateInfoDisplay( void );
-               
-               void    StartBrowsing( const char *inType, const char *inDomain );
-               void    StopBrowsing( void );
-
-       protected:
-
-               //{{AFX_MSG(ChooserDialog)
-               virtual BOOL OnInitDialog();
-               afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
-               afx_msg void OnDomainListChanged(NMHDR* pNMHDR, LRESULT* pResult);
-               afx_msg void OnServiceListChanged(NMHDR* pNMHDR, LRESULT* pResult);
-               afx_msg void OnChooserListChanged(NMHDR* pNMHDR, LRESULT* pResult);
-               afx_msg void OnChooserListDoubleClick(NMHDR* pNMHDR, LRESULT* pResult);
-               afx_msg void OnAbout();
-               afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu);
-               afx_msg void OnActivate(UINT nState, CWnd* pWndOther, BOOL bMinimized);
-               afx_msg void OnFileClose();
-               virtual void OnCancel();
-               afx_msg void OnExit();
-               afx_msg void OnClose();
-               afx_msg void OnNcDestroy();
-               //}}AFX_MSG
-               afx_msg LONG OnDomainAdd( WPARAM inWParam, LPARAM inLParam );
-               afx_msg LONG OnDomainRemove( WPARAM inWParam, LPARAM inLParam );
-               afx_msg LONG OnServiceAdd( WPARAM inWParam, LPARAM inLParam );
-               afx_msg LONG OnServiceRemove( WPARAM inWParam, LPARAM inLParam );
-               afx_msg LONG OnResolve( WPARAM inWParam, LPARAM inLParam );
-               DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_CHOOSERDIALOG_H__AC258704_B307_4901_9F98_A0AC022FD8AC__INCLUDED_)
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.cpp
deleted file mode 100644 (file)
index b9a9ec9..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       <assert.h>
-#include       <stdlib.h>
-
-#include       "stdafx.h"
-
-#include       "LoginDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-//     Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP( LoginDialog, CDialog )
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-//     LoginDialog
-//===========================================================================================================================
-
-LoginDialog::LoginDialog( CWnd *inParent )
-       : CDialog( LoginDialog::IDD, inParent )
-{
-       //
-}
-
-//===========================================================================================================================
-//     OnInitDialog
-//===========================================================================================================================
-
-BOOL   LoginDialog::OnInitDialog( void )
-{
-       CDialog::OnInitDialog();
-       return( TRUE );
-}
-
-//===========================================================================================================================
-//     DoDataExchange
-//===========================================================================================================================
-
-void   LoginDialog::DoDataExchange( CDataExchange *inDX )
-{
-       CDialog::DoDataExchange( inDX );
-}
-
-//===========================================================================================================================
-//     OnOK
-//===========================================================================================================================
-
-void   LoginDialog::OnOK( void )
-{
-       const CWnd *            control;
-               
-       // Username
-       
-       control = GetDlgItem( IDC_LOGIN_USERNAME_TEXT );
-       assert( control );
-       if( control )
-       {
-               control->GetWindowText( mUsername );
-       }
-       
-       // Password
-       
-       control = GetDlgItem( IDC_LOGIN_PASSWORD_TEXT );
-       assert( control );
-       if( control )
-       {
-               control->GetWindowText( mPassword );
-       }
-       
-       CDialog::OnOK();
-}
-
-//===========================================================================================================================
-//     GetLogin
-//===========================================================================================================================
-
-BOOL   LoginDialog::GetLogin( CString &outUsername, CString &outPassword )
-{
-       if( DoModal() == IDOK )
-       {
-               outUsername = mUsername;
-               outPassword = mPassword;
-               return( TRUE );
-       }
-       return( FALSE );
-}
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/LoginDialog.h
deleted file mode 100644 (file)
index e53beb6..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef        __LOGIN_DIALOG__
-#define        __LOGIN_DIALOG__
-
-#pragma once
-
-#include       "Resource.h"
-
-//===========================================================================================================================
-//     LoginDialog
-//===========================================================================================================================
-
-class  LoginDialog : public CDialog
-{
-       protected:
-       
-               CString         mUsername;
-               CString         mPassword;
-               
-       public:
-               
-               enum { IDD = IDD_LOGIN };
-               
-               LoginDialog( CWnd *inParent = NULL );
-               
-               virtual BOOL    GetLogin( CString &outUsername, CString &outPassword );
-       
-       protected:
-
-               virtual BOOL    OnInitDialog( void );
-               virtual void    DoDataExchange( CDataExchange *inDX );
-               virtual void    OnOK( void );
-               
-               DECLARE_MESSAGE_MAP()
-};
-
-#endif // __LOGIN_DIALOG__
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.cpp
deleted file mode 100644 (file)
index ae2ca2e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       "stdafx.h"
diff --git a/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h b/mDNSWindows/DNSServiceBrowser/Windows/Sources/StdAfx.h
deleted file mode 100644 (file)
index c62bd3e..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !defined(AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_)
-#define AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif // _MSC_VER > 1000
-
-#define VC_EXTRALEAN           // Exclude rarely-used stuff from Windows headers
-
-#ifndef WINVER                         // Allow use of features specific to Windows 95 and Windows NT 4 or later.
-       #define WINVER 0x0400   // Change this to the appropriate value to target Windows 98 and Windows 2000 or later.
-#endif
-
-#include       <afxwin.h>              // MFC core and standard components
-#include       <afxext.h>              // MFC extensions
-#include       <afxdtctl.h>    // MFC support for Internet Explorer 4 Common Controls
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-       #include        <afxcmn.h>      // MFC support for Windows Common Controls
-#endif // _AFX_NO_AFXCMN_SUPPORT
-
-#include       <winsock2.h>
-
-#include       <stdlib.h>
-
-#include       "DNSServices.h"
-
-#include       "Application.h"
-
-#include       "ChooserDialog.h"
-
-#endif // !defined(AFX_STDAFX_H__424305D2_0A97_4AA0_B9B1_A7D90D18EBA0__INCLUDED_)
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcc b/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcc
deleted file mode 100644 (file)
index 22f443d..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-; CLW file contains information for the MFC ClassWizard
-
-[General Info]
-Version=1
-LastClass=BrowserDialog
-LastTemplate=CDialog
-NewFileInclude1=#include "stdafx.h"
-NewFileInclude2=#include "Application.h"
-
-ClassCount=3
-Class1=Application
-Class2=BrowserDialog
-
-ResourceCount=3
-Resource2=IDR_MAINFRAME
-Resource3=IDD_APPLICATION_DIALOG
-
-[CLS:Application]
-Type=0
-HeaderFile=Application.h
-ImplementationFile=Application.cpp
-Filter=N
-
-[CLS:BrowserDialog]
-Type=0
-HeaderFile=BrowserDialog.h
-ImplementationFile=BrowserDialog.cpp
-Filter=D
-
-
-[DLG:IDD_APPLICATION_DIALOG]
-Type=1
-ControlCount=3
-Control1=IDOK,button,1342242817
-Control2=IDCANCEL,button,1342242816
-Control3=IDC_STATIC,static,1342308352
-Class=BrowserDialog
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcp
deleted file mode 100644 (file)
index 9c73567..0000000
+++ /dev/null
@@ -1,868 +0,0 @@
-# Microsoft eMbedded Visual Tools Project File - Name="Application" - Package Owner=<4>
-# Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (WCE ARMV4) Application" 0xa301
-# TARGTYPE "Win32 (WCE emulator) Application" 0xa601
-
-CFG=Application - Win32 (WCE emulator) Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE 
-!MESSAGE NMAKE /f "Application.vcn".
-!MESSAGE 
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE 
-!MESSAGE NMAKE /f "Application.vcn" CFG="Application - Win32 (WCE emulator) Debug"
-!MESSAGE 
-!MESSAGE Possible choices for configuration are:
-!MESSAGE 
-!MESSAGE "Application - Win32 (WCE emulator) Release" (based on "Win32 (WCE emulator) Application")
-!MESSAGE "Application - Win32 (WCE emulator) Debug" (based on "Win32 (WCE emulator) Application")
-!MESSAGE "Application - Win32 (WCE ARMV4) Release" (based on "Win32 (WCE ARMV4) Application")
-!MESSAGE "Application - Win32 (WCE ARMV4) Debug" (based on "Win32 (WCE ARMV4) Application")
-!MESSAGE 
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-# PROP ATL_Project 2
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "emulatorRel"
-# PROP BASE Intermediate_Dir "emulatorRel"
-# PROP BASE CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "emulatorRel"
-# PROP Intermediate_Dir "emulatorRel"
-# PROP CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /D "_i386_" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_WIN32_WCE_CEPC" /D "_AFXDLL" /Yu"stdafx.h" /Gs8192 /GF /O2 /c
-# ADD CPP /nologo /W3 /WX /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "_i386_" /D "_X86_" /D "x86" /D "NDEBUG" /D "_WIN32_WCE_CEPC" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /Gs8192 /GF /O2 /c
-# SUBTRACT CPP /YX /Yc /Yu
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /MACHINE:IX86
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /MACHINE:IX86
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "emulatorDbg"
-# PROP BASE Intermediate_Dir "emulatorDbg"
-# PROP BASE CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "emulatorDbg"
-# PROP Intermediate_Dir "emulatorDbg"
-# PROP CPU_ID "{32E52003-403E-442D-BE48-DE10F8C6131D}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /d "_AFXDLL" /r
-CPP=cl.exe
-# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D "_i386_" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_WIN32_WCE_CEPC" /D "_AFXDLL" /Yu"stdafx.h" /Gs8192 /GF /c
-# ADD CPP /nologo /W3 /WX /Zi /Od /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "_i386_" /D "_X86_" /D "x86" /D "_WIN32_WCE_CEPC" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /FR /Gs8192 /GF /c
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /MACHINE:IX86
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /MACHINE:IX86
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "ARMV4Rel"
-# PROP BASE Intermediate_Dir "ARMV4Rel"
-# PROP BASE CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "ARMV4Rel"
-# PROP Intermediate_Dir "ARMV4Rel"
-# PROP CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "NDEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "NDEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-CPP=clarm.exe
-# ADD BASE CPP /nologo /W3 /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_AFXDLL" /Yu"stdafx.h" /O2 /M$(CECrtMT) /c
-# ADD CPP /nologo /W3 /WX /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "ARM" /D "_ARM_" /D "ARMV4" /D "NDEBUG" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /O2 /M$(CECrtMT) /c
-# SUBTRACT CPP /YX /Yc /Yu
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-# PROP BASE Use_MFC 2
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "ARMV4Dbg"
-# PROP BASE Intermediate_Dir "ARMV4Dbg"
-# PROP BASE CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 2
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "ARMV4Dbg"
-# PROP Intermediate_Dir "ARMV4Dbg"
-# PROP CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}"
-# PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-RSC=rc.exe
-# ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "DEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-# ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "DEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /d "_AFXDLL" /r
-CPP=clarm.exe
-# ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /Yu"stdafx.h" /M$(CECrtMTDebug) /c
-# ADD CPP /nologo /W3 /WX /Zi /Od /I "Resources" /I "Sources" /I "..\..\..\DNSServices" /I "..\..\..\..\mDNSCore" /I "..\..\..\..\mDNSCore\PlatformSupport" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "UNICODE" /D "_UNICODE" /D "_AFXDLL" /D DNS_SD_CLIENT_ENABLED=0 /FR /M$(CECrtMTDebug) /c
-# SUBTRACT CPP /YX /Yc /Yu
-MTL=midl.exe
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-# ADD LINK32 ws2.lib /nologo /base:"0x00010000" /stack:0x10000,0x1000 /entry:"wWinMainCRTStartup" /debug /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM
-
-!ENDIF 
-
-# Begin Target
-
-# Name "Application - Win32 (WCE emulator) Release"
-# Name "Application - Win32 (WCE emulator) Debug"
-# Name "Application - Win32 (WCE ARMV4) Release"
-# Name "Application - Win32 (WCE ARMV4) Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\Sources\Application.cpp
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_APPLI=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_APPLI=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_APPLI=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_APPLI=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\Application.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\BrowserDialog.cpp
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_BROWS=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_BROWS=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_BROWS=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_BROWS=\
-       "..\..\..\DNSServices\DNSServices.h"\
-       ".\Sources\Application.h"\
-       ".\Sources\BrowserDialog.h"\
-       ".\Sources\StdAfx.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\BrowserDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\StdAfx.cpp
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_STDAF=\
-       ".\Sources\StdAfx.h"\
-       
-# ADD CPP /Yc"stdafx.h"
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_STDAF=\
-       ".\Sources\StdAfx.h"\
-       
-# ADD CPP /Yc"stdafx.h"
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_STDAF=\
-       ".\Sources\StdAfx.h"\
-       
-# ADD CPP /Yc"stdafx.h"
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_STDAF=\
-       ".\Sources\StdAfx.h"\
-       
-# ADD CPP /Yc"stdafx.h"
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Sources\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\Resources\Application.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\Application.rc
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\Application.rc2
-# PROP Exclude_From_Scan -1
-# PROP BASE Exclude_From_Build 1
-# PROP Exclude_From_Build 1
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\newres.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Resources\Resource.h
-# End Source File
-# End Group
-# Begin Group "Support"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\CommonServices.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DebugServices.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DEBUG=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       
-NODEP_CPP_DEBUG=\
-       "..\..\..\intLib.h"\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DEBUG=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       
-NODEP_CPP_DEBUG=\
-       "..\..\..\intLib.h"\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DEBUG=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       
-NODEP_CPP_DEBUG=\
-       "..\..\..\intLib.h"\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DEBUG=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       
-NODEP_CPP_DEBUG=\
-       "..\..\..\intLib.h"\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DebugServices.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\DNSCommon.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSCO=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSCO=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSCO=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSCO=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\DNSCommon.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\DNSDigest.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSDI=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSDI=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSDI=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSDI=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSD.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSSD=\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       "..\..\..\RMxClient.h"\
-       
-NODEP_CPP_DNSSD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSSD=\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       "..\..\..\RMxClient.h"\
-       
-NODEP_CPP_DNSSD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSSD=\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       "..\..\..\RMxClient.h"\
-       
-NODEP_CPP_DNSSD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSSD=\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       "..\..\..\RMxClient.h"\
-       
-NODEP_CPP_DNSSD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSD.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSDDirect.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSSDD=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       
-NODEP_CPP_DNSSDD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSSDD=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       
-NODEP_CPP_DNSSDD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSSDD=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       
-NODEP_CPP_DNSSDD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSSDD=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\DNSSD.h"\
-       "..\..\..\DNSSDDirect.h"\
-       
-NODEP_CPP_DNSSDD=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSSDDirect.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSServices\DNSServices.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_DNSSE=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\DNSServices\DNSServices.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_DNSSE=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\DNSServices\DNSServices.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_DNSSE=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\DNSServices\DNSServices.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_DNSSE=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\DNSServices\DNSServices.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\DNSServices\DNSServices.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\mDNS.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_MDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_MDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_MDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_MDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\mDNSClientAPI.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\mDNSDebug.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\mDNSWin32.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_MDNSW=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\mDNSWin32.h"\
-       {$(INCLUDE)}"ipexport.h"\
-       {$(INCLUDE)}"Iphlpapi.h"\
-       {$(INCLUDE)}"iptypes.h"\
-       
-NODEP_CPP_MDNSW=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_MDNSW=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\mDNSWin32.h"\
-       {$(INCLUDE)}"ipexport.h"\
-       {$(INCLUDE)}"Iphlpapi.h"\
-       {$(INCLUDE)}"iptypes.h"\
-       
-NODEP_CPP_MDNSW=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-# ADD CPP /W3
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_MDNSW=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\mDNSWin32.h"\
-       {$(INCLUDE)}"ipexport.h"\
-       {$(INCLUDE)}"Iphlpapi.h"\
-       {$(INCLUDE)}"iptypes.h"\
-       
-NODEP_CPP_MDNSW=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_MDNSW=\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\CommonServices.h"\
-       "..\..\..\DebugServices.h"\
-       "..\..\..\mDNSWin32.h"\
-       {$(INCLUDE)}"ipexport.h"\
-       {$(INCLUDE)}"Iphlpapi.h"\
-       {$(INCLUDE)}"iptypes.h"\
-       
-NODEP_CPP_MDNSW=\
-       "..\..\..\logLib.h"\
-       "..\..\..\vxWorks.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\mDNSWin32.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\uDNS.c
-
-!IF  "$(CFG)" == "Application - Win32 (WCE emulator) Release"
-
-DEP_CPP_UDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE emulator) Debug"
-
-DEP_CPP_UDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Release"
-
-DEP_CPP_UDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ELSEIF  "$(CFG)" == "Application - Win32 (WCE ARMV4) Debug"
-
-DEP_CPP_UDNS_=\
-       "..\..\..\..\mDNSCore\DNSCommon.h"\
-       "..\..\..\..\mDNSCore\mDNSClientAPI.h"\
-       "..\..\..\..\mDNSCore\mDNSDebug.h"\
-       "..\..\..\..\mDNSCore\uDNS.h"\
-       
-
-!ENDIF 
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\mDNSCore\uDNS.h
-# End Source File
-# End Group
-# End Target
-# End Project
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcw b/mDNSWindows/DNSServiceBrowser/WindowsCE/Application.vcw
deleted file mode 100644 (file)
index 11ef513..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Microsoft eMbedded Visual Tools Workspace File, Format Version 4.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "Application"=.\Application.vcp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.ico b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.ico
deleted file mode 100644 (file)
index 50fb08f..0000000
Binary files a/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.ico and /dev/null differ
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc
deleted file mode 100644 (file)
index c153326..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-//Microsoft eMbedded Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "newres.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE DISCARDABLE 
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE DISCARDABLE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "#include ""newres.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE DISCARDABLE 
-BEGIN
-    "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
-    "#define _AFX_NO_OLE_RESOURCES\r\n"
-    "#define _AFX_NO_TRACKER_RESOURCES\r\n"
-    "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
-    "\r\n"
-    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
-    "#ifdef _WIN32\r\n"
-    "LANGUAGE 9, 1\r\n"
-    "#pragma code_page(1252)\r\n"
-    "#endif //_WIN32\r\n"
-    "#include ""Resources\\Application.rc2""  // non-Microsoft eMbedded Visual C++ edited resources\r\n"
-    "#include ""afxres.rc""         // Standard components\r\n"
-    "#include ""wceres.rc""         // WCE-specific components\r\n"
-    "#endif\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-IDR_MAINFRAME           ICON    DISCARDABLE     "Application.ico"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Dialog
-//
-
-IDD_APPLICATION_DIALOG DIALOG DISCARDABLE  0, 0, 139, 153
-STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION
-EXSTYLE WS_EX_APPWINDOW | 0x80000000L
-CAPTION "DNSServiceBrowser"
-FONT 8, "System"
-BEGIN
-    CONTROL         "List1",IDC_BROWSE_LIST,"SysListView32",LVS_REPORT | 
-                    LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | 
-                    WS_BORDER | WS_TABSTOP,7,7,125,141
-END
-
-
-#ifndef _MAC
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION 1,0,0,1
- PRODUCTVERSION 1,0,0,1
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "Comments", "\0"
-            VALUE "CompanyName", "Apple Computer, Inc.\0"
-            VALUE "FileDescription", "DNSServiceBrowser for Windows CE\0"
-            VALUE "FileVersion", "1, 0, 0, 1\0"
-            VALUE "InternalName", "Application\0"
-            VALUE "LegalCopyright", "Copyright (C) 2003-2004 Apple Computer, Inc.\0"
-            VALUE "LegalTrademarks", "\0"
-            VALUE "OriginalFilename", "Application.exe\0"
-            VALUE "PrivateBuild", "\0"
-            VALUE "ProductName", "DNSServiceBrowser for Windows CE\0"
-            VALUE "ProductVersion", "1, 0, 0, 1\0"
-            VALUE "SpecialBuild", "\0"
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-#endif    // !_MAC
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// DESIGNINFO
-//
-
-#ifdef APSTUDIO_INVOKED
-GUIDELINES DESIGNINFO DISCARDABLE 
-BEGIN
-    IDD_APPLICATION_DIALOG, DIALOG
-    BEGIN
-        LEFTMARGIN, 7
-        RIGHTMARGIN, 132
-        TOPMARGIN, 7
-        BOTTOMMARGIN, 146
-    END
-END
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE DISCARDABLE 
-BEGIN
-    IDP_SOCKETS_INIT_FAILED "Windows CE sockets initialization failed."
-    IDS_BROWSER_LIST_COLUMN_NAME "Name"
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-#define _AFX_NO_SPLITTER_RESOURCES
-#define _AFX_NO_OLE_RESOURCES
-#define _AFX_NO_TRACKER_RESOURCES
-#define _AFX_NO_PROPERTY_RESOURCES
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE 9, 1
-#pragma code_page(1252)
-#endif //_WIN32
-#include "Resources\Application.rc2"  // non-Microsoft eMbedded Visual C++ edited resources
-#include "afxres.rc"         // Standard components
-#include "wceres.rc"         // WCE-specific components
-#endif
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc2 b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/Application.rc2
deleted file mode 100644 (file)
index 29c9fe7..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-//
-// APPLICATION.RC2 - resources Microsoft eMbedded Visual C++ does not edit directly
-//
-
-#ifdef APSTUDIO_INVOKED
-       #error this file is not editable by Microsoft eMbedded Visual C++
-#endif //APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-// Add manually edited resources here...
-
-/////////////////////////////////////////////////////////////////////////////
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/newres.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/newres.h
deleted file mode 100644 (file)
index 31c3a43..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __NEWRES_H__
-#define __NEWRES_H__
-
-#define  SHMENUBAR RCDATA
-#if !(defined(_WIN32_WCE_PSPC) && (_WIN32_WCE >= 300))
-       #undef HDS_HORZ  
-       #undef HDS_BUTTONS 
-       #undef HDS_HIDDEN 
-
-       #include <commctrl.h>
-       // for MenuBar
-       #define I_IMAGENONE             (-2)
-       #define NOMENU                  0xFFFF
-       #define IDS_SHNEW               1
-       #define IDM_SHAREDNEW        10
-       #define IDM_SHAREDNEWDEFAULT 11
-
-       // for Tab Control
-       #define TCS_SCROLLOPPOSITE      0x0001   // assumes multiline tab
-       #define TCS_BOTTOM              0x0002
-       #define TCS_RIGHT               0x0002
-       #define TCS_VERTICAL            0x0080
-       #define TCS_MULTISELECT         0x0004  // allow multi-select in button mode
-       #define TCS_FLATBUTTONS         0x0008  
-#endif //_WIN32_WCE_PSPC
-
-
-#endif //__NEWRES_H__
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/resource.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Resources/resource.h
deleted file mode 100644 (file)
index 0337c56..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft eMbedded Visual C++ generated include file.
-// Used by Application.rc
-//
-#define IDD_APPLICATION_DIALOG          102
-#define IDP_SOCKETS_INIT_FAILED         103
-#define IDS_BROWSER_LIST_COLUMN_NAME    104
-#define IDR_MAINFRAME                   128
-#define IDC_BROWSE_LIST                 1000
-#define IDC_IP_TEXT                     1003
-#define IDC_TXT_TEXT                    1004
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        129
-#define _APS_NEXT_COMMAND_VALUE         32771
-#define _APS_NEXT_CONTROL_VALUE         1005
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.cpp
deleted file mode 100644 (file)
index 931cd95..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       "stdafx.h"
-
-#include       "DNSServices.h"
-
-#include       "BrowserDialog.h"
-
-#include       "Application.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-//     Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(Application, CWinApp)
-       //{{AFX_MSG_MAP(Application)
-               // NOTE - the ClassWizard will add and remove mapping macros here.
-               //    DO NOT EDIT what you see in these blocks of generated code!
-       //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-Application            gApp;
-
-//===========================================================================================================================
-//     Application
-//===========================================================================================================================
-
-Application::Application()
-       : CWinApp()
-{
-       //
-}
-
-//===========================================================================================================================
-//     InitInstance
-//===========================================================================================================================
-
-BOOL Application::InitInstance()
-{
-       DNSStatus                       err;
-       BrowserDialog           dialog;
-       BOOL                            dnsInitialized;
-       
-       dnsInitialized = FALSE;
-       
-       err = DNSServicesInitialize( kDNSFlagAdvertise, 0 );
-       if( err )
-       {
-               AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
-               goto exit;
-       }
-       dnsInitialized = TRUE;
-
-       // Display the main browser dialog.
-       
-       m_pMainWnd = &dialog;
-       dialog.DoModal();
-
-       // Dialog has been closed. Return false to exit the app and not start the app's message pump.
-
-exit:
-       if( dnsInitialized )
-       {
-               DNSServicesFinalize();
-       }
-       return( FALSE );
-}
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/Application.h
deleted file mode 100644 (file)
index cfd5429..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !defined(AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_)
-#define AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#ifndef __AFXWIN_H__
-       #error include 'stdafx.h' before including this file for PCH
-#endif
-
-#include       "Resource.h"
-
-//===========================================================================================================================
-//     Application
-//===========================================================================================================================
-
-class  Application : public CWinApp
-{
-       public:
-               
-               Application();
-
-               // ClassWizard generated virtual function overrides
-               //{{AFX_VIRTUAL(Application)
-               public:
-               virtual BOOL InitInstance();
-               //}}AFX_VIRTUAL
-
-               //{{AFX_MSG(Application)
-                       // NOTE - the ClassWizard will add and remove member functions here.
-                       //    DO NOT EDIT what you see in these blocks of generated code !
-               //}}AFX_MSG
-               DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft eMbedded Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_APPLICATION_H__E2E51302_D643_458E_A7A5_5157233D1E5C__INCLUDED_)
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.cpp
deleted file mode 100644 (file)
index 67b9cb8..0000000
+++ /dev/null
@@ -1,394 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       "stdafx.h"
-
-#include       "Application.h"
-
-#include       "DNSServices.h"
-
-#include       "BrowserDialog.h"
-
-#ifdef _DEBUG
-#define new DEBUG_NEW
-#undef THIS_FILE
-static char THIS_FILE[] = __FILE__;
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#define        WM_USER_SERVICE_ADD                     ( WM_USER + 0x100 )
-#define        WM_USER_SERVICE_REMOVE          ( WM_USER + 0x101 )
-
-//===========================================================================================================================
-//     Message Map
-//===========================================================================================================================
-
-BEGIN_MESSAGE_MAP(BrowserDialog, CDialog)
-       //{{AFX_MSG_MAP(BrowserDialog)
-       ON_NOTIFY(NM_CLICK, IDC_BROWSE_LIST, OnBrowserListDoubleClick)
-       ON_MESSAGE( WM_USER_SERVICE_ADD, OnServiceAdd )
-       ON_MESSAGE( WM_USER_SERVICE_REMOVE, OnServiceRemove )
-       //}}AFX_MSG_MAP
-END_MESSAGE_MAP()
-
-static DWORD   UTF8StringToStringObject( const char *inUTF8, CString &inObject );
-
-//===========================================================================================================================
-//     BrowserDialog
-//===========================================================================================================================
-
-BrowserDialog::BrowserDialog( CWnd *inParent )
-       : CDialog( BrowserDialog::IDD, inParent )
-{
-       //{{AFX_DATA_INIT(BrowserDialog)
-               // Note: the ClassWizard will add member initialization here
-       //}}AFX_DATA_INIT
-       
-       // Note that LoadIcon does not require a subsequent DestroyIcon in Win32.
-       
-       mIcon = AfxGetApp()->LoadIcon( IDR_MAINFRAME );
-       ASSERT( mIcon );
-}
-
-//===========================================================================================================================
-//     DoDataExchange
-//===========================================================================================================================
-
-void   BrowserDialog::DoDataExchange( CDataExchange *pDX )
-{
-       CDialog::DoDataExchange(pDX);
-       //{{AFX_DATA_MAP(BrowserDialog)
-       DDX_Control(pDX, IDC_BROWSE_LIST, mBrowserList);
-       //}}AFX_DATA_MAP
-}
-
-//===========================================================================================================================
-//     OnInitDialog
-//===========================================================================================================================
-
-BOOL   BrowserDialog::OnInitDialog()
-{
-       CString         s;
-       
-       CDialog::OnInitDialog();
-
-       // Set the icon for this dialog. The framework does this automatically when the application's main window is not a dialog.
-       
-       SetIcon( mIcon, TRUE );         // Set big icon
-       SetIcon( mIcon, FALSE );        // Set small icon
-       
-       CenterWindow( GetDesktopWindow() );
-
-       // Set up the list.
-       
-       CRect           rect;
-       
-       s.LoadString( IDS_BROWSER_LIST_COLUMN_NAME );
-       mBrowserList.GetWindowRect( rect );
-       mBrowserList.InsertColumn( 0, s, LVCFMT_LEFT, rect.Width() - 8 );
-       
-       // Start browsing for services.
-
-       DNSStatus               err;
-
-       err = DNSBrowserCreate( 0, OnBrowserCallBack, this, &mBrowser );
-       if( err )
-       {
-               AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
-               goto exit;
-       }
-       
-       err = DNSBrowserStartServiceSearch( mBrowser, kDNSBrowserFlagAutoResolve, "_http._tcp", NULL );
-       if( err )
-       {
-               AfxMessageBox( IDP_SOCKETS_INIT_FAILED );
-               goto exit;
-       }
-       
-exit:
-       return( TRUE );
-}
-
-
-//===========================================================================================================================
-//     OnBrowserListDoubleClick
-//===========================================================================================================================
-
-void   BrowserDialog::OnBrowserListDoubleClick( NMHDR *pNMHDR, LRESULT *pResult ) 
-{
-       int             selectedItem;
-
-       (void) pNMHDR;  // Unused
-
-       selectedItem = mBrowserList.GetNextItem( -1, LVNI_SELECTED );
-       if( selectedItem >= 0 )
-       {
-               BrowserEntry *          entry;
-               CString                         temp;
-               CString                         url;
-               
-               // Build the URL from the IP and optional TXT record.
-
-               entry = &mBrowserEntries[ selectedItem ];
-               url += "http://" + entry->ip;
-               temp = entry->text;
-               if( temp.Find( TEXT( "path=" ) ) == 0 )
-               {
-                       temp.Delete( 0, 5 );
-               }
-               if( temp.Find( '/' ) != 0 )
-               {
-                       url += '/';
-               }
-               url += temp;
-
-               // Let the system open the URL in the correct app.
-               
-               SHELLEXECUTEINFO                info;
-
-               info.cbSize                     = sizeof( info );
-               info.fMask                      = 0;
-               info.hwnd                       = NULL;
-               info.lpVerb             = NULL;
-               info.lpFile             = url;
-               info.lpParameters       = NULL;
-               info.lpDirectory        = NULL;
-               info.nShow                      = SW_SHOWNORMAL;
-               info.hInstApp           = NULL;
-
-               ShellExecuteEx( &info );
-       }
-       *pResult = 0;
-}
-
-//===========================================================================================================================
-//     OnBrowserCallBack [static]
-//===========================================================================================================================
-
-void
-       BrowserDialog::OnBrowserCallBack( 
-               void *                                  inContext, 
-               DNSBrowserRef                   inRef, 
-               DNSStatus                               inStatusCode,
-               const DNSBrowserEvent * inEvent )
-{
-       BrowserDialog *         dialog;
-       BrowserEntry *          entry;
-       BOOL                            posted;
-       
-       DNS_UNUSED( inStatusCode );
-       dialog = reinterpret_cast < BrowserDialog * > ( inContext );
-       ASSERT( dialog );
-       
-       switch( inEvent->type )
-       {
-               case kDNSBrowserEventTypeResolved:
-                       if( inEvent->data.resolved->address.addressType == kDNSNetworkAddressTypeIPv4  )
-                       {
-                               char            ip[ 64 ];
-
-                               snprintf( ip, sizeof( ip ), "%u.%u.%u.%u:%u", 
-                                       inEvent->data.resolved->address.u.ipv4.addr.v8[ 0 ], 
-                                       inEvent->data.resolved->address.u.ipv4.addr.v8[ 1 ], 
-                                       inEvent->data.resolved->address.u.ipv4.addr.v8[ 2 ], 
-                                       inEvent->data.resolved->address.u.ipv4.addr.v8[ 3 ], 
-                                       ( inEvent->data.resolved->address.u.ipv4.port.v8[ 0 ] << 8 ) | 
-                                         inEvent->data.resolved->address.u.ipv4.port.v8[ 1 ] );
-                               
-                               entry = new BrowserEntry;
-                               ASSERT( entry );
-                               if( entry )
-                               {
-                                       UTF8StringToStringObject( inEvent->data.resolved->name, entry->name );
-                                       UTF8StringToStringObject( ip, entry->ip );
-                                       UTF8StringToStringObject( inEvent->data.resolved->textRecord, entry->text );
-                                       
-                                       posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_ADD, 0, (LPARAM) entry );
-                                       ASSERT( posted );
-                                       if( !posted )
-                                       {
-                                               delete entry;
-                                       }
-                               }
-                       }
-                       break;
-
-               case kDNSBrowserEventTypeRemoveService:
-                       entry = new BrowserEntry;
-                       ASSERT( entry );
-                       if( entry )
-                       {
-                               UTF8StringToStringObject( inEvent->data.removeService.name, entry->name );
-                               
-                               posted = ::PostMessage( dialog->GetSafeHwnd(), WM_USER_SERVICE_REMOVE, 0, (LPARAM) entry );
-                               ASSERT( posted );
-                               if( !posted )
-                               {
-                                       delete entry;
-                               }
-                       }
-                       break;
-               
-               default:
-                       break;
-       }
-}
-
-//===========================================================================================================================
-//     BrowserAddService
-//===========================================================================================================================
-
-LONG   BrowserDialog::OnServiceAdd( WPARAM inWParam, LPARAM inLParam )
-{
-       BrowserEntry *          entry;
-       INT_PTR                         lo;
-       INT_PTR                         hi;
-       INT_PTR                         mid;
-       int                                     result;
-       
-       (void) inWParam;        // Unused
-       
-       entry = reinterpret_cast < BrowserEntry * > ( inLParam );
-       ASSERT( entry );
-       
-       result  = -1;
-       mid             = 0;
-       lo              = 0;
-       hi              = mBrowserEntries.GetSize() - 1;
-       while( lo <= hi )
-       {
-               mid = ( lo + hi ) / 2;
-               result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
-               if( result == 0 )
-               {
-                       break;
-               }
-               else if( result < 0 )
-               {
-                       hi = mid - 1;
-               }
-               else
-               {
-                       lo = mid + 1;
-               }
-       }
-       if( result == 0 )
-       {
-               mBrowserEntries[ mid ].ip       = entry->ip;
-               mBrowserEntries[ mid ].text     = entry->text;
-       }
-       else
-       {
-               if( result > 0 )
-               {
-                       mid += 1;
-               }
-               mBrowserEntries.InsertAt( mid, *entry );
-               mBrowserList.InsertItem( mid, entry->name );
-       }
-       delete entry;
-       return( 0 );
-}
-
-//===========================================================================================================================
-//     OnServiceRemove
-//===========================================================================================================================
-
-LONG   BrowserDialog::OnServiceRemove( WPARAM inWParam, LPARAM inLParam )
-{
-       BrowserEntry *          entry;
-       INT_PTR                         hi;
-       INT_PTR                         lo;
-       INT_PTR                         mid;
-       int                                     result;
-
-       (void) inWParam;        // Unused
-       
-       entry = reinterpret_cast < BrowserEntry * > ( inLParam );
-       ASSERT( entry );
-       
-       result  = -1;
-       mid             = 0;
-       lo              = 0;
-       hi              = mBrowserEntries.GetSize() - 1;
-       while( lo <= hi )
-       {
-               mid = ( lo + hi ) / 2;
-               result = entry->name.CompareNoCase( mBrowserEntries[ mid ].name );
-               if( result == 0 )
-               {
-                       break;
-               }
-               else if( result < 0 )
-               {
-                       hi = mid - 1;
-               }
-               else
-               {
-                       lo = mid + 1;
-               }
-       }
-       if( result == 0 )
-       {
-               mBrowserList.DeleteItem( mid );
-               mBrowserEntries.RemoveAt( mid );
-       }
-       delete entry;
-       return( 0 );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     UTF8StringToStringObject
-//===========================================================================================================================
-
-static DWORD   UTF8StringToStringObject( const char *inUTF8, CString &inObject )
-{
-       DWORD                   err;
-       int                             n;
-       wchar_t *               unicode;
-       
-       unicode = NULL;
-       
-       n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
-       if( n > 0 )
-       {
-               unicode = (wchar_t *) malloc( (size_t)( n * sizeof( wchar_t ) ) );
-               if( !unicode ) { err = ERROR_INSUFFICIENT_BUFFER; goto exit; };
-               
-               n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
-               inObject = unicode;
-       }
-       else
-       {
-               inObject = "";
-       }
-       err = 0;
-       
-exit:
-       if( unicode )
-       {
-               free( unicode );
-       }
-       return( err );
-}
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/BrowserDialog.h
deleted file mode 100644 (file)
index a27df91..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !defined(AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_)
-#define AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-#include       "afxtempl.h"
-#include       "Resource.h"
-
-#include       "DNSServices.h"
-
-//===========================================================================================================================
-//     BrowserDialog
-//===========================================================================================================================
-
-class  BrowserDialog : public CDialog
-{
-       public:
-               
-               BrowserDialog( CWnd *inParent = NULL );
-               
-               //{{AFX_DATA(BrowserDialog)
-               enum { IDD = IDD_APPLICATION_DIALOG };
-               CListCtrl       mBrowserList;
-               //}}AFX_DATA
-
-               // ClassWizard generated virtual function overrides
-               //{{AFX_VIRTUAL(BrowserDialog)
-               protected:
-               virtual void DoDataExchange(CDataExchange* pDX);        // DDX/DDV support
-               //}}AFX_VIRTUAL
-               
-               static void
-                       OnBrowserCallBack( 
-                               void *                                  inContext, 
-                               DNSBrowserRef                   inRef, 
-                               DNSStatus                               inStatusCode,  
-                               const DNSBrowserEvent * inEvent );
-               
-       protected:
-               
-               struct  BrowserEntry
-               {
-                       CString         name;
-                       CString         ip;
-                       CString         text;
-               };
-               
-               HICON                                                                           mIcon;
-               DNSBrowserRef                                                           mBrowser;
-               CArray < BrowserEntry, BrowserEntry >           mBrowserEntries;
-               
-               // Generated message map functions
-               //{{AFX_MSG(BrowserDialog)
-               virtual BOOL OnInitDialog();
-               afx_msg void OnBrowserListDoubleClick(NMHDR* pNMHDR, LRESULT* pResult);
-               afx_msg LONG OnServiceAdd( WPARAM inWParam, LPARAM inLParam );
-               afx_msg LONG OnServiceRemove( WPARAM inWParam, LPARAM inLParam );
-               //}}AFX_MSG
-               DECLARE_MESSAGE_MAP()
-};
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft eMbedded Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_BROWSERDIALOG_H__DECC5C82_C1C6_4630_B8D5_E1DDE570A061__INCLUDED_)
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.cpp
deleted file mode 100644 (file)
index ae2ca2e..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       "stdafx.h"
diff --git a/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h b/mDNSWindows/DNSServiceBrowser/WindowsCE/Sources/StdAfx.h
deleted file mode 100644 (file)
index 4b14a0b..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#if !defined(AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_)
-#define AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_
-
-#if _MSC_VER >= 1000
-#pragma once
-#endif // _MSC_VER >= 1000
-
-
-
-#define VC_EXTRALEAN           // Exclude rarely-used stuff from Windows headers
-
-#include <afxwin.h>         // MFC core and standard components
-#include <afxext.h>         // MFC extensions
-
-#if defined(_AFXDLL)
-#include <afxdtctl.h>          // MFC support for Internet Explorer 4 Common Controls
-#endif
-
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-#include <afxcmn.h>                    // MFC support for Windows Common Controls
-#endif // _AFX_NO_AFXCMN_SUPPORT
-
-#include <winsock2.h>
-//#include <afxsock.h>         // MFC socket extensions
-
-//{{AFX_INSERT_LOCATION}}
-// Microsoft eMbedded Visual C++ will insert additional declarations immediately before the previous line.
-
-#endif // !defined(AFX_STDAFX_H__7F91E52B_CF39_429D_837D_599CE0B2B3D6__INCLUDED_)
diff --git a/mDNSWindows/Java/Java.vcproj b/mDNSWindows/Java/Java.vcproj
deleted file mode 100755 (executable)
index 1707ac5..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="Java"\r
-       ProjectGUID="{9CE2568A-3170-41C6-9F20-A0188A9EC114}"\r
-       Keyword="MakeFileProj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="Debug"\r
-                       IntermediateDirectory="Debug"\r
-                       ConfigurationType="0"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       >\r
-                       <Tool\r
-                               Name="VCNMakeTool"\r
-                               BuildCommandLine="nmake /f makefile DEBUG=1"\r
-                               ReBuildCommandLine="nmake /f makefile DEBUG=1"\r
-                               CleanCommandLine="nmake /f makefile DEBUG=1 clean"\r
-                               Output=""\r
-                               PreprocessorDefinitions=""\r
-                               IncludeSearchPath=""\r
-                               ForcedIncludes=""\r
-                               AssemblySearchPath=""\r
-                               ForcedUsingAssemblies=""\r
-                               CompileAsManaged=""\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="0"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       >\r
-                       <Tool\r
-                               Name="VCNMakeTool"\r
-                               BuildCommandLine="nmake /f makefile64 DEBUG=1"\r
-                               ReBuildCommandLine="nmake /f makefile64 DEBUG=1"\r
-                               CleanCommandLine="nmake /f makefile64 DEBUG=1 clean"\r
-                               Output=""\r
-                               PreprocessorDefinitions=""\r
-                               IncludeSearchPath=""\r
-                               ForcedIncludes=""\r
-                               AssemblySearchPath=""\r
-                               ForcedUsingAssemblies=""\r
-                               CompileAsManaged=""\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="Release"\r
-                       IntermediateDirectory="Release"\r
-                       ConfigurationType="0"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       >\r
-                       <Tool\r
-                               Name="VCNMakeTool"\r
-                               BuildCommandLine="nmake /f makefile"\r
-                               ReBuildCommandLine="nmake /f makefile"\r
-                               CleanCommandLine="nmake /f makefile clean"\r
-                               Output=""\r
-                               PreprocessorDefinitions=""\r
-                               IncludeSearchPath=""\r
-                               ForcedIncludes=""\r
-                               AssemblySearchPath=""\r
-                               ForcedUsingAssemblies=""\r
-                               CompileAsManaged=""\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="0"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       >\r
-                       <Tool\r
-                               Name="VCNMakeTool"\r
-                               BuildCommandLine="nmake /f makefile64"\r
-                               ReBuildCommandLine="nmake /f makefile64"\r
-                               CleanCommandLine="nmake /f makefile64 clean"\r
-                               Output=""\r
-                               PreprocessorDefinitions=""\r
-                               IncludeSearchPath=""\r
-                               ForcedIncludes=""\r
-                               AssemblySearchPath=""\r
-                               ForcedUsingAssemblies=""\r
-                               CompileAsManaged=""\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/Java/Java.vcxproj b/mDNSWindows/Java/Java.vcxproj
deleted file mode 100755 (executable)
index 9c63f87..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{9CE2568A-3170-41C6-9F20-A0188A9EC114}</ProjectGuid>\r
-    <Keyword>MakeFileProj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>Makefile</ConfigurationType>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>Makefile</ConfigurationType>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>Makefile</ConfigurationType>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>Makefile</ConfigurationType>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir>\r
-    <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f makefile DEBUG=1</NMakeBuildCommandLine>\r
-    <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f makefile DEBUG=1</NMakeReBuildCommandLine>\r
-    <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">nmake /f makefile DEBUG=1 clean</NMakeCleanCommandLine>\r
-    <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />\r
-    <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
-    <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
-    <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
-    <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
-    <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f makefile64 DEBUG=1</NMakeBuildCommandLine>\r
-    <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f makefile64 DEBUG=1</NMakeReBuildCommandLine>\r
-    <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">nmake /f makefile64 DEBUG=1 clean</NMakeCleanCommandLine>\r
-    <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" />\r
-    <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
-    <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
-    <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
-    <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
-    <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir>\r
-    <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f makefile</NMakeBuildCommandLine>\r
-    <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f makefile</NMakeReBuildCommandLine>\r
-    <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">nmake /f makefile clean</NMakeCleanCommandLine>\r
-    <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />\r
-    <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
-    <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
-    <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
-    <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
-    <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <NMakeBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f makefile64</NMakeBuildCommandLine>\r
-    <NMakeReBuildCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f makefile64</NMakeReBuildCommandLine>\r
-    <NMakeCleanCommandLine Condition="'$(Configuration)|$(Platform)'=='Release|x64'">nmake /f makefile64 clean</NMakeCleanCommandLine>\r
-    <NMakeOutput Condition="'$(Configuration)|$(Platform)'=='Release|x64'" />\r
-    <NMakePreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakePreprocessorDefinitions)</NMakePreprocessorDefinitions>\r
-    <NMakeIncludeSearchPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeIncludeSearchPath)</NMakeIncludeSearchPath>\r
-    <NMakeForcedIncludes Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeForcedIncludes)</NMakeForcedIncludes>\r
-    <NMakeAssemblySearchPath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeAssemblySearchPath)</NMakeAssemblySearchPath>\r
-    <NMakeForcedUsingAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(NMakeForcedUsingAssemblies)</NMakeForcedUsingAssemblies>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
-      <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
-      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/Java/jdns_sd.rc b/mDNSWindows/Java/jdns_sd.rc
deleted file mode 100644 (file)
index 79fdf14..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C; 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.
- */
-
-#ifndef JDNS_SD_RC
-#define JDNS_SD_RC
-
-#include "afxres.h"
-#include "../WinVersRes.h"
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", MASTER_COMPANY_NAME
-            VALUE "FileDescription", MASTER_PROD_NAME " support for Java"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "jdns_sd"
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
-            VALUE "OriginalFilename", "jdns_sd.dll"
-            VALUE "ProductName", MASTER_PROD_NAME
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-#endif // JDNS_SD_RC
diff --git a/mDNSWindows/Java/makefile b/mDNSWindows/Java/makefile
deleted file mode 100644 (file)
index da23797..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-# -*- tab-width: 4 -*-
-#
-# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-# 
-#     http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# This Makefile builds a .jar file and accompanying JNI support library
-# containing the DNSSD implementation for Java and support classes.
-#
-# Prior to building Java support, you must build DNSSD.dll.
-#
-# nmake with no arguments builds all production targets.
-# 'nmake DEBUG=1' to build debugging targets.
-# 'nmake clean' or 'nmake clean DEBUG=1' to delete prod/debug objects & targets
-#
-# To run nmake, you may need to set up your PATH correctly, using a script 
-# such as: "\Program Files\Microsoft Visual Studio .NET\Vc7\bin\vcvars32.bat"
-# 
-# The default location of the JDK is \javasdk. You can override this on the
-# command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
-
-############################################################################
-
-COREDIR = ..\..\mDNSCore
-SHAREDDIR = ..\..\mDNSShared
-
-JDK = "$(JAVA_HOME)"
-
-CC = cl
-RC = rc
-LD = ld
-CP = copy
-RM = del /Q
-RMDIR = rmdir /S /Q
-JAVAC = $(JDK)\bin\javac
-JAVAH = $(JDK)\bin\javah
-JAR = $(JDK)\bin\jar
-CFLAGS_COMMON = -LD -DAUTO_CALLBACKS=0 -I. -I..\.. \
-       -I$(COREDIR) -I$(SHAREDDIR) -I$(JDK)\include -I$(JDK)\include\win32
-
-# Set up diverging paths for debug vs. prod builds
-DEBUG=0
-!if $(DEBUG) == 1
-CFLAGS_DEBUG = -Zi -DMDNS_DEBUGMSGS=2 
-OBJDIR = objects\debug
-BUILDDIR = build\debug
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\Win32\Debug
-!else
-CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
-OBJDIR = objects\prod
-BUILDDIR = build\prod
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\Win32\Release
-!endif
-
-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG)
-JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS)
-
-#############################################################################
-
-all: setup Java postbuild
-
-# 'setup' sets up the build directory structure the way we want
-setup:
-       @if not exist objects           mkdir objects
-       @if not exist build                     mkdir build
-       @if not exist $(OBJDIR)         mkdir $(OBJDIR)
-       @if not exist $(BUILDDIR)       mkdir $(BUILDDIR)
-
-postbuild:
-       @if not "%RC_XBS%"=="YES" GOTO CONT
-       @if not exist "$(DSTROOT)\WINDOWS\system32\Win32"       mkdir "$(DSTROOT)\WINDOWS\system32\Win32"
-       @if not exist "$(DSTROOT)\Program Files\Bonjour\Win32"  mkdir "$(DSTROOT)\Program Files\Bonjour\Win32"
-       @copy $(BUILDDIR)\jdns_sd.dll "$(DSTROOT)\WINDOWS\system32\Win32"
-       @copy $(BUILDDIR)\dns_sd.jar  "$(DSTROOT)\Program Files\Bonjour\Win32"
-       @:CONT
-       @if not exist root                                      mkdir root
-       @if not exist root\"Program Files"      mkdir root\"Program Files"
-       @if not exist $(INSTALLDIR)                     mkdir $(INSTALLDIR)
-       copy $(BUILDDIR)\dns_sd.jar $(INSTALLDIR)
-       copy $(BUILDDIR)\jdns_sd.dll $(INSTALLDIR)
-
-# clean removes targets and objects
-clean:
-       @if exist $(OBJDIR)             $(RMDIR) $(OBJDIR)
-       @if exist $(BUILDDIR)   $(RMDIR) $(BUILDDIR)
-
-#############################################################################
-
-# The following targets build Java wrappers for the dns-sd.h API.
-
-Java: setup $(BUILDDIR)\dns_sd.jar $(BUILDDIR)\jdns_sd.dll postbuild
-       @echo "Java wrappers done"
-
-JAVASRC        = $(SHAREDDIR)\Java
-JARCONTENTS =  $(OBJDIR)\com\apple\dnssd\DNSSDService.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSDException.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSRecord.class \
-                               $(OBJDIR)\com\apple\dnssd\TXTRecord.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSDRegistration.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSDRecordRegistrar.class \
-                               $(OBJDIR)\com\apple\dnssd\BaseListener.class \
-                               $(OBJDIR)\com\apple\dnssd\BrowseListener.class \
-                               $(OBJDIR)\com\apple\dnssd\ResolveListener.class \
-                               $(OBJDIR)\com\apple\dnssd\RegisterListener.class \
-                               $(OBJDIR)\com\apple\dnssd\RegisterRecordListener.class \
-                               $(OBJDIR)\com\apple\dnssd\QueryListener.class \
-                               $(OBJDIR)\com\apple\dnssd\DomainListener.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSD.class
-
-$(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
-       $(JAR) -cf $@ -C $(OBJDIR) com
-
-$(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h $(OBJDIR)\jdns_sd.RES
-       $(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
-       $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES /link /NXCOMPAT /DYNAMICBASE /SAFESEH
-
-.SUFFIXES : .java
-{$(JAVASRC)}.java{$(OBJDIR)\com\apple\dnssd}.class:    
-       $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
-
-$(OBJDIR)\DNSSD.java.h: $(OBJDIR)\com\apple\dnssd\DNSSD.class
-       $(JAVAH) -classpath $(OBJDIR) -o $@ \
-               com.apple.dnssd.AppleBrowser \
-               com.apple.dnssd.AppleResolver \
-               com.apple.dnssd.AppleRegistration \
-               com.apple.dnssd.AppleQuery \
-               com.apple.dnssd.AppleService 
-
-$(OBJDIR)\jdns_sd.RES: jdns_sd.rc
-       $(RC) /fo $@ $?
-
diff --git a/mDNSWindows/Java/makefile64 b/mDNSWindows/Java/makefile64
deleted file mode 100644 (file)
index 5845ab5..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-# -*- tab-width: 4 -*-
-#
-# Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-# 
-#     http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-# This Makefile builds a .jar file and accompanying JNI support library
-# containing the DNSSD implementation for Java and support classes.
-#
-# Prior to building Java support, you must build DNSSD.dll.
-#
-# nmake with no arguments builds all production targets.
-# 'nmake DEBUG=1' to build debugging targets.
-# 'nmake clean' or 'nmake clean DEBUG=1' to delete prod/debug objects & targets
-#
-# To run nmake, you may need to set up your PATH correctly, using a script 
-# such as: "\Program Files\Microsoft Visual Studio .NET\Vc7\bin\vcvars32.bat"
-# 
-# The default location of the JDK is \javasdk. You can override this on the
-# command line (e.g. 'nmake JDK=\j2dk1.4.2_03').
-
-############################################################################
-
-COREDIR = ..\..\mDNSCore
-SHAREDDIR = ..\..\mDNSShared
-
-JDK = "$(JAVA_HOME)"
-
-CC = cl
-RC = rc
-LD = ld
-CP = copy
-RM = del /Q
-RMDIR = rmdir /S /Q
-JAVAC = $(JDK)\bin\javac
-JAVAH = $(JDK)\bin\javah
-JAR = $(JDK)\bin\jar
-CFLAGS_COMMON = -LD -DAUTO_CALLBACKS=0 -I. -I..\.. \
-       -I$(COREDIR) -I$(SHAREDDIR) -I$(JDK)\include -I$(JDK)\include\win32
-
-# Set up diverging paths for debug vs. prod builds
-DEBUG=0
-!if $(DEBUG) == 1
-CFLAGS_DEBUG = -Zi -DMDNS_DEBUGMSGS=2 
-OBJDIR = objects\debug\x64
-BUILDDIR = build\debug\x64
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\x64\Debug
-!else
-CFLAGS_DEBUG = -Os -DMDNS_DEBUGMSGS=0 
-OBJDIR = objects\prod\x64
-BUILDDIR = build\prod\x64
-INSTALLDIR = root\"Program Files"\Bonjour
-LIBDIR = ..\DLL\x64\Release
-!endif
-
-CFLAGS = $(CFLAGS_COMMON) $(CFLAGS_DEBUG)
-JAVACFLAGS = $(CFLAGS) $(JAVACFLAGS_OS)
-
-#############################################################################
-
-all: setup Java postbuild
-
-# 'setup' sets up the build directory structure the way we want
-setup:
-       @if not exist objects           mkdir objects
-       @if not exist build                     mkdir build
-       @if not exist $(OBJDIR)         mkdir $(OBJDIR)
-       @if not exist $(BUILDDIR)       mkdir $(BUILDDIR)
-
-postbuild:
-       @if not "%RC_XBS%"=="YES" GOTO CONT
-       @if not exist "$(DSTROOT)\WINDOWS\system32\x64" mkdir "$(DSTROOT)\WINDOWS\system32\x64"
-       @if not exist "$(DSTROOT)\Program Files\Bonjour\x64"    mkdir "$(DSTROOT)\Program Files\Bonjour\x64"
-       @copy $(BUILDDIR)\jdns_sd.dll "$(DSTROOT)\WINDOWS\system32\x64"
-       @copy $(BUILDDIR)\dns_sd.jar  "$(DSTROOT)\Program Files\Bonjour\x64"
-       @:CONT
-       @if not exist root                                      mkdir root
-       @if not exist root\"Program Files"      mkdir root\"Program Files"
-       @if not exist $(INSTALLDIR)                     mkdir $(INSTALLDIR)
-       copy $(BUILDDIR)\dns_sd.jar $(INSTALLDIR)
-       copy $(BUILDDIR)\jdns_sd.dll $(INSTALLDIR)
-
-# clean removes targets and objects
-clean:
-       @if exist $(OBJDIR)             $(RMDIR) $(OBJDIR)
-       @if exist $(BUILDDIR)   $(RMDIR) $(BUILDDIR)
-
-#############################################################################
-
-# The following targets build Java wrappers for the dns-sd.h API.
-
-Java: setup $(BUILDDIR)\dns_sd.jar $(BUILDDIR)\jdns_sd.dll postbuild
-       @echo "Java wrappers done"
-
-JAVASRC        = $(SHAREDDIR)\Java
-JARCONTENTS =  $(OBJDIR)\com\apple\dnssd\DNSSDService.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSDException.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSRecord.class \
-                               $(OBJDIR)\com\apple\dnssd\TXTRecord.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSDRegistration.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSDRecordRegistrar.class \
-                               $(OBJDIR)\com\apple\dnssd\BaseListener.class \
-                               $(OBJDIR)\com\apple\dnssd\BrowseListener.class \
-                               $(OBJDIR)\com\apple\dnssd\ResolveListener.class \
-                               $(OBJDIR)\com\apple\dnssd\RegisterListener.class \
-                               $(OBJDIR)\com\apple\dnssd\RegisterRecordListener.class \
-                               $(OBJDIR)\com\apple\dnssd\QueryListener.class \
-                               $(OBJDIR)\com\apple\dnssd\DomainListener.class \
-                               $(OBJDIR)\com\apple\dnssd\DNSSD.class
-
-$(BUILDDIR)\dns_sd.jar: $(JARCONTENTS)
-       $(JAR) -cf $@ -C $(OBJDIR) com
-
-$(BUILDDIR)\jdns_sd.dll: $(JAVASRC)\JNISupport.c $(OBJDIR)\DNSSD.java.h $(OBJDIR)\jdns_sd.RES
-       $(CC) -Fe$@ $(JAVASRC)\JNISupport.c $(CFLAGS) -I$(OBJDIR) \
-       $(LIBDIR)\DNSSD.lib $(JDK)\lib\jvm.lib ws2_32.lib iphlpapi.lib $(OBJDIR)\jdns_sd.RES /link /NXCOMPAT /DYNAMICBASE
-
-.SUFFIXES : .java
-{$(JAVASRC)}.java{$(OBJDIR)\com\apple\dnssd}.class:    
-       $(JAVAC) -d $(OBJDIR) -classpath $(OBJDIR) $<
-
-$(OBJDIR)\DNSSD.java.h: $(OBJDIR)\com\apple\dnssd\DNSSD.class
-       $(JAVAH) -classpath $(OBJDIR) -o $@ \
-               com.apple.dnssd.AppleBrowser \
-               com.apple.dnssd.AppleResolver \
-               com.apple.dnssd.AppleRegistration \
-               com.apple.dnssd.AppleQuery \
-               com.apple.dnssd.AppleService 
-
-$(OBJDIR)\jdns_sd.RES: jdns_sd.rc
-       $(RC) /fo $@ $?
-
diff --git a/mDNSWindows/NSPTool/NSPTool.aps b/mDNSWindows/NSPTool/NSPTool.aps
deleted file mode 100644 (file)
index 313f306..0000000
Binary files a/mDNSWindows/NSPTool/NSPTool.aps and /dev/null differ
diff --git a/mDNSWindows/NSPTool/NSPTool.c b/mDNSWindows/NSPTool/NSPTool.c
deleted file mode 100644 (file)
index 0be174d..0000000
+++ /dev/null
@@ -1,581 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       <stdio.h>
-#include       <stdlib.h>
-
-#include       "CommonServices.h"
-#include       "DebugServices.h"
-
-#include       <guiddef.h>
-#include       <ws2spi.h>
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-int                                    main( int argc, char *argv[] );
-DEBUG_LOCAL void               Usage( void );
-DEBUG_LOCAL int                        ProcessArgs( int argc, char *argv[] );
-DEBUG_LOCAL OSStatus   InstallNSP( const char *inName, const char *inGUID, const char *inPath );
-DEBUG_LOCAL OSStatus   RemoveNSP( const char *inGUID );
-DEBUG_LOCAL OSStatus   EnableNSP( const char *inGUID, BOOL inEnable );
-DEBUG_LOCAL OSStatus   ListNameSpaces( void );
-DEBUG_LOCAL OSStatus   ReorderNameSpaces( void );
-
-DEBUG_LOCAL WCHAR *            CharToWCharString( const char *inCharString, WCHAR *outWCharString );
-DEBUG_LOCAL char *             GUIDtoString( const GUID *inGUID, size_t inLen, char *outString );
-DEBUG_LOCAL OSStatus   StringToGUID( const char *inCharString, GUID *outGUID );
-
-DEBUG_LOCAL BOOL gToolQuietMode = FALSE;
-
-//===========================================================================================================================
-//     main
-//===========================================================================================================================
-
-int main( int argc, char *argv[] )
-{
-       OSStatus                err;
-       
-       debug_initialize( kDebugOutputTypeMetaConsole );
-       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
-       
-       err = ProcessArgs( argc, argv );
-       return( (int) err );
-}
-
-//===========================================================================================================================
-//     Usage
-//===========================================================================================================================
-
-DEBUG_LOCAL void       Usage( void )
-{
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "NSP Tool 1.0d1\n" );
-       fprintf( stderr, "  Name Space Provider Tool\n" );
-       fprintf( stderr, "\n" );
-       
-       fprintf( stderr, "  -install <name> <guid> <path>   - Installs a Name Space Provider\n" );
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "      <name> Name of the NSP\n" );
-       fprintf( stderr, "      <guid> GUID of the NSP\n" );
-       fprintf( stderr, "      <path> Path to the NSP file\n" );
-       fprintf( stderr, "\n" );
-       
-       fprintf( stderr, "  -remove <guid>                  - Removes a Name Space Provider\n" );
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "      <guid> GUID of the NSP\n" );
-       fprintf( stderr, "\n" );
-       
-       fprintf( stderr, "  -enable/-disable <guid>         - Enables or Disables a Name Space Provider\n" );
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "      <guid> GUID of the NSP\n" );
-       fprintf( stderr, "\n" );
-       
-       fprintf( stderr, "  -list                           - Lists Name Space Providers\n" );  
-       fprintf( stderr, "  -reorder                        - Reorders Name Space Providers\n" );
-       fprintf( stderr, "  -q                              - Enable quiet mode\n" );
-       fprintf( stderr, "  -h[elp]                         - Help\n" );
-       fprintf( stderr, "\n" );
-}
-
-//===========================================================================================================================
-//     ProcessArgs
-//===========================================================================================================================
-
-DEBUG_LOCAL int ProcessArgs( int argc, char* argv[] )
-{      
-       OSStatus                        err;
-       int                                     i;
-       const char *            name;
-       const char *            guid;
-       const char *            path;
-                       
-       if( argc <= 1 )
-       {
-               Usage();
-               err = 0;
-               goto exit;
-       }
-       for( i = 1; i < argc; ++i )
-       {
-               if( strcmp( argv[ i ], "-install" ) == 0 )
-               {
-                       // Install
-                       
-                       if( argc <= ( i + 3 ) )
-                       {
-                               fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
-                               Usage();
-                               err = kParamErr;
-                               goto exit;
-                       }
-                       name = argv[ ++i ];
-                       guid = argv[ ++i ];
-                       path = argv[ ++i ];
-                       
-                       if( *name == '\0' )
-                       {
-                               name = "DotLocalNSP";
-                       }
-                       if( *guid == '\0' )
-                       {
-                               guid = "B600E6E9-553B-4a19-8696-335E5C896153";
-                       }
-                       
-                       err = InstallNSP( name, guid, path );
-                       require_noerr( err, exit );
-               }
-               else if( strcmp( argv[ i ], "-remove" ) == 0 )
-               {
-                       // Remove
-                       
-                       if( argc <= ( i + 1 ) )
-                       {
-                               fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
-                               Usage();
-                               err = kParamErr;
-                               goto exit;
-                       }
-                       guid = argv[ ++i ];
-                       if( *guid == '\0' )
-                       {
-                               guid = "B600E6E9-553B-4a19-8696-335E5C896153";
-                       }
-                       
-                       err = RemoveNSP( guid );
-                       require_noerr( err, exit );
-               }
-               else if( ( strcmp( argv[ i ], "-enable" )  == 0 ) || 
-                                ( strcmp( argv[ i ], "-disable" ) == 0 ) )
-               {
-                       BOOL            enable;
-                       
-                       // Enable/Disable
-                       
-                       enable = ( strcmp( argv[ i ], "-enable" ) == 0 );
-                       if( argc <= ( i + 1 ) )
-                       {
-                               fprintf( stderr, "\n### ERROR: missing arguments for %s\n\n", argv[ i ] );
-                               Usage();
-                               err = kParamErr;
-                               goto exit;
-                       }
-                       guid = argv[ ++i ];
-                       
-                       err = EnableNSP( guid, enable );
-                       require_noerr( err, exit );
-               }
-               else if( strcmp( argv[ i ], "-list" ) == 0 )
-               {
-                       // List
-                                               
-                       err = ListNameSpaces();
-                       require_noerr( err, exit );
-               }
-               else if( strcmp( argv[ i ], "-reorder" ) == 0 )
-               {
-                       // Reorder
-                       
-                       err = ReorderNameSpaces();
-                       require_noerr( err, exit );
-               }
-               else if( strcmp( argv[ i ], "-q" ) == 0 )
-               {
-                       gToolQuietMode = TRUE;
-               }
-               else if( ( strcmp( argv[ i ], "-help" ) == 0 ) || 
-                                ( strcmp( argv[ i ], "-h" ) == 0 ) )
-               {
-                       // Help
-                       
-                       Usage();
-                       err = 0;
-                       goto exit;
-               }
-               else
-               {
-                       fprintf( stderr, "\n### ERROR: unknown argment: \"%s\"\n\n", argv[ i ] );
-                       Usage();
-                       err = kParamErr;
-                       goto exit;
-               }
-       }
-       err = kNoErr;
-       
-exit:
-       return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     InstallNSP
-//===========================================================================================================================
-
-OSStatus       InstallNSP( const char *inName, const char *inGUID, const char *inPath )
-{
-       OSStatus                err;
-       size_t                  size;
-       WSADATA                 wsd;
-       WCHAR                   name[ 256 ];
-       GUID                    guid;
-       WCHAR                   path[ MAX_PATH ];
-       
-       require_action( inName && ( *inName != '\0' ), exit, err = kParamErr );
-       require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
-       require_action( inPath && ( *inPath != '\0' ), exit, err = kParamErr );
-       
-       size = strlen( inName );
-       require_action( size < sizeof_array( name ), exit, err = kSizeErr );
-       CharToWCharString( inName, name );
-       
-       err = StringToGUID( inGUID, &guid );
-       require_noerr( err, exit );
-       
-       size = strlen( inPath );
-       require_action( size < sizeof_array( path ), exit, err = kSizeErr );
-       CharToWCharString( inPath, path );
-       
-       err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       
-       err = WSCInstallNameSpace( name, path, NS_DNS, 1, &guid );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       WSACleanup();
-       require_noerr( err, exit );
-       
-       if (!gToolQuietMode)
-       {
-               fprintf( stderr, "Installed NSP \"%s\" (%s) at %s\n", inName, inGUID, inPath );
-       }
-       
-exit:
-       if( err != kNoErr )
-       {
-               fprintf( stderr, "### FAILED (%d) to install \"%s\" (%s) Name Space Provider at %s\n", err, inName, inGUID, inPath );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     RemoveNSP
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   RemoveNSP( const char *inGUID )
-{
-       OSStatus                err;
-       WSADATA                 wsd;
-       GUID                    guid;
-       
-       require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
-       
-       err = StringToGUID( inGUID, &guid );
-       require_noerr( err, exit );
-       
-       err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       
-       err = WSCUnInstallNameSpace( &guid );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       WSACleanup();
-       require_noerr( err, exit );
-       
-       if (!gToolQuietMode)
-       {
-               fprintf( stderr, "Removed NSP %s\n", inGUID );
-       }
-               
-exit:
-       if( err != kNoErr )
-       {
-               fprintf( stderr, "### FAILED (%d) to remove %s Name Space Provider\n", err, inGUID );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     EnableNSP
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   EnableNSP( const char *inGUID, BOOL inEnable )
-{
-       OSStatus                err;
-       WSADATA                 wsd;
-       GUID                    guid;
-       
-       require_action( inGUID && ( *inGUID != '\0' ), exit, err = kParamErr );
-       
-       err = StringToGUID( inGUID, &guid );
-       require_noerr( err, exit );
-       
-       err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       
-       err = WSCEnableNSProvider( &guid, inEnable );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       WSACleanup();
-       require_noerr( err, exit );
-       
-       if (!gToolQuietMode)
-       {
-               fprintf( stderr, "Removed NSP %s\n", inGUID );
-       }
-               
-exit:
-       if( err != kNoErr )
-       {
-               fprintf( stderr, "### FAILED (%d) to remove %s Name Space Provider\n", err, inGUID );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     ListNameSpaces
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   ListNameSpaces( void )
-{
-       OSStatus                                err;
-       WSADATA                                 wsd;
-       bool                                    started;
-       int                                             n;
-       int                                             i;
-       DWORD                                   size;
-       WSANAMESPACE_INFO *             array;
-       char                                    s[ 256 ];
-       
-       array   = NULL;
-       started = false;
-       
-       err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       started = true;
-       
-       // Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
-       
-       size = 0;
-       n = WSAEnumNameSpaceProviders( &size, NULL );
-       err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
-       require_action( err == WSAEFAULT, exit, err = kUnknownErr );
-       
-       array = (WSANAMESPACE_INFO *) malloc( size );
-       require_action( array, exit, err = kNoMemoryErr );
-       
-       n = WSAEnumNameSpaceProviders( &size, array );
-       err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       fprintf( stdout, "\n" );
-       for( i = 0; i < n; ++i )
-       {
-               fprintf( stdout, "Name Space %d\n", i + 1 );
-               fprintf( stdout, "    NSProviderId:   %s\n", GUIDtoString( &array[ i ].NSProviderId, sizeof( s ), s ) );
-               fprintf( stdout, "    dwNameSpace:    %d\n", array[ i ].dwNameSpace );
-               fprintf( stdout, "    fActive:        %s\n", array[ i ].fActive ? "YES" : "NO" );
-               fprintf( stdout, "    dwVersion:      %d\n", array[ i ].dwVersion );
-               fprintf( stdout, "    lpszIdentifier: \"%s\"\n", array[ i ].lpszIdentifier );
-               fprintf( stdout, "\n" );
-       }
-       err = kNoErr;
-       
-exit:
-       if( array )
-       {
-               free( array );
-       }
-       if( started )
-       {
-               WSACleanup();
-       }
-       if( err != kNoErr )
-       {
-               fprintf( stderr, "### FAILED (%d) to list Name Space Providers\n", err );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     ReorderNameSpaces
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   ReorderNameSpaces( void )
-{
-       OSStatus                                err;
-       WSADATA                                 wsd;
-       bool                                    started;
-       int                                             n;
-       int                                             i;
-       DWORD                                   size;
-       WSANAMESPACE_INFO *             array;
-       WCHAR                                   name[ 256 ];
-       WCHAR                                   path[ MAX_PATH ];
-       
-       array   = NULL;
-       started = false;
-               
-       err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       started = true;
-       
-       // Build an array of all the NSPs. Call it first with NULL to get the size, allocate a buffer, then get them into it.
-       
-       size = 0;
-       n = WSAEnumNameSpaceProviders( &size, NULL );
-       err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
-       require_action( err == WSAEFAULT, exit, err = kUnknownErr );
-       
-       array = (WSANAMESPACE_INFO *) malloc( size );
-       require_action( array, exit, err = kNoMemoryErr );
-       
-       n = WSAEnumNameSpaceProviders( &size, array );
-       err = translate_errno( n != SOCKET_ERROR, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       // Find the "Tcpip" NSP.
-       
-       for( i = 0; i < n; ++i )
-       {
-               if( strcmp( array[ i ].lpszIdentifier, "Tcpip" ) == 0 )
-               {
-                       break;
-               }
-       }
-       require_action( i < n, exit, err = kNotFoundErr );
-       
-       // Uninstall it then re-install it to move it to the end.
-       
-       size = (DWORD) strlen( array[ i ].lpszIdentifier );
-       require_action( size < sizeof_array( name ), exit, err = kSizeErr );
-       CharToWCharString( array[ i ].lpszIdentifier, name );
-       
-       size = (DWORD) strlen( "%SystemRoot%\\System32\\mswsock.dll" );
-       require_action( size < sizeof_array( path ), exit, err = kSizeErr );
-       CharToWCharString( "%SystemRoot%\\System32\\mswsock.dll", path );
-       
-       err = WSCUnInstallNameSpace( &array[ i ].NSProviderId );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       
-       err = WSCInstallNameSpace( name, path, NS_DNS, array[ i ].dwVersion, &array[ i ].NSProviderId );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-               
-       // Success!
-       
-       fprintf( stderr, "Reordered \"Tcpip\" NSP to to the bottom of the NSP chain\n" );       
-       err = kNoErr;
-       
-exit:
-       if( array )
-       {
-               free( array );
-       }
-       if( started )
-       {
-               WSACleanup();
-       }
-       if( err != kNoErr )
-       {
-               fprintf( stderr, "### FAILED (%d) to reorder Name Space Providers\n", err );
-       }
-       return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     CharToWCharString
-//===========================================================================================================================
-
-DEBUG_LOCAL WCHAR *    CharToWCharString( const char *inCharString, WCHAR *outWCharString )
-{
-       const char *            src;
-       WCHAR *                         dst;
-       char                            c;
-       
-       check( inCharString );
-       check( outWCharString );
-       
-       src = inCharString;
-       dst = outWCharString;
-       do
-       {
-               c = *src++;
-               *dst++ = (WCHAR) c;
-       
-       }       while( c != '\0' );
-       
-       return( outWCharString );
-}
-
-//===========================================================================================================================
-//     GUIDtoString
-//===========================================================================================================================
-
-DEBUG_LOCAL char *     GUIDtoString( const GUID *inGUID, size_t inLen, char *outString )
-{
-       check( inGUID );
-       check( outString );
-       
-       _snprintf( outString, inLen, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-               inGUID->Data1, inGUID->Data2, inGUID->Data3, 
-               inGUID->Data4[ 0 ], inGUID->Data4[ 1 ], inGUID->Data4[ 2 ], inGUID->Data4[ 3 ], 
-               inGUID->Data4[ 4 ], inGUID->Data4[ 5 ], inGUID->Data4[ 6 ], inGUID->Data4[ 7 ] );
-       return( outString );
-}
-
-//===========================================================================================================================
-//     StringToGUID
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   StringToGUID( const char *inCharString, GUID *outGUID )
-{
-       OSStatus                        err;
-       int                                     n;
-       unsigned int            v[ 8 ];
-       
-       check( inCharString );
-       check( outGUID );
-       
-       n = sscanf( inCharString, "%lX-%hX-%hX-%02X%02X-%02X%02X%02X%02X%02X%02X", 
-               &outGUID->Data1, &outGUID->Data2, &outGUID->Data3, 
-               &v[ 0 ], &v[ 1 ], &v[ 2 ], &v[ 3 ], &v[ 4 ], &v[ 5 ], &v[ 6 ], &v[ 7 ] );
-       require_action( n == 11, exit, err = kFormatErr );
-       
-       outGUID->Data4[ 0 ] = (unsigned char) v[ 0 ];
-       outGUID->Data4[ 1 ] = (unsigned char) v[ 1 ];
-       outGUID->Data4[ 2 ] = (unsigned char) v[ 2 ];
-       outGUID->Data4[ 3 ] = (unsigned char) v[ 3 ];
-       outGUID->Data4[ 4 ] = (unsigned char) v[ 4 ];
-       outGUID->Data4[ 5 ] = (unsigned char) v[ 5 ];
-       outGUID->Data4[ 6 ] = (unsigned char) v[ 6 ];
-       outGUID->Data4[ 7 ] = (unsigned char) v[ 7 ];
-       err = kNoErr;
-
-exit:
-       return( err );
-}
diff --git a/mDNSWindows/NSPTool/NSPTool.rc b/mDNSWindows/NSPTool/NSPTool.rc
deleted file mode 100644 (file)
index 72a6b36..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-// Microsoft Visual C++ generated resource script.\r
-//\r
-#include "resource.h"\r
-\r
-#define APSTUDIO_READONLY_SYMBOLS\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 2 resource.\r
-//\r
-#include "afxres.h"\r
-#include "WinVersRes.h"\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#undef APSTUDIO_READONLY_SYMBOLS\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-// English (U.S.) resources\r
-\r
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r
-#ifdef _WIN32\r
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
-#pragma code_page(1252)\r
-#endif //_WIN32\r
-\r
-#ifdef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// TEXTINCLUDE\r
-//\r
-\r
-1 TEXTINCLUDE \r
-BEGIN\r
-    "resource.h\0"\r
-END\r
-\r
-2 TEXTINCLUDE \r
-BEGIN\r
-    "#include ""afxres.h""\r\n"\r
-    "\0"\r
-END\r
-\r
-3 TEXTINCLUDE \r
-BEGIN\r
-    "\r\n"\r
-    "\0"\r
-END\r
-\r
-#endif    // APSTUDIO_INVOKED\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Version\r
-//\r
-\r
-VS_VERSION_INFO VERSIONINFO\r
- FILEVERSION MASTER_PROD_VERS\r
- PRODUCTVERSION MASTER_PROD_VERS\r
- FILEFLAGSMASK 0x17L\r
-#ifdef _DEBUG\r
- FILEFLAGS 0x1L\r
-#else\r
- FILEFLAGS 0x0L\r
-#endif\r
- FILEOS 0x4L\r
- FILETYPE 0x1L\r
- FILESUBTYPE 0x0L\r
-BEGIN\r
-    BLOCK "StringFileInfo"\r
-    BEGIN\r
-        BLOCK "040904b0"\r
-        BEGIN\r
-            VALUE "CompanyName", MASTER_COMPANY_NAME\r
-            VALUE "FileDescription", "NSPTool Application"\r
-            VALUE "FileVersion", MASTER_PROD_VERS_STR\r
-            VALUE "InternalName", "NSPTool"\r
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT\r
-            VALUE "OriginalFilename", "NSPTool.exe"\r
-            VALUE "ProductName", MASTER_PROD_NAME\r
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR\r
-        END\r
-    END\r
-    BLOCK "VarFileInfo"\r
-    BEGIN\r
-        VALUE "Translation", 0x409, 1200\r
-    END\r
-END\r
-\r
-#endif    // English (U.S.) resources\r
-/////////////////////////////////////////////////////////////////////////////\r
-\r
-\r
-\r
-#ifndef APSTUDIO_INVOKED\r
-/////////////////////////////////////////////////////////////////////////////\r
-//\r
-// Generated from the TEXTINCLUDE 3 resource.\r
-//\r
-\r
-\r
-/////////////////////////////////////////////////////////////////////////////\r
-#endif    // not APSTUDIO_INVOKED\r
-\r
diff --git a/mDNSWindows/NSPTool/NSPTool.vcproj b/mDNSWindows/NSPTool/NSPTool.vcproj
deleted file mode 100644 (file)
index bed3203..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="NSPTool"\r
-       ProjectGUID="{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}"\r
-       Keyword="Win32Proj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               EnableFunctionLevelLinking="false"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="4"\r
-                               CallingConvention="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="..\"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/NSPTool.exe"\r
-                               LinkIncremental="2"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/NSPTool.pdb"\r
-                               SubSystem="1"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               EnableFunctionLevelLinking="false"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="0"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="..\"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/NSPTool.exe"\r
-                               LinkIncremental="2"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/NSPTool.pdb"\r
-                               SubSystem="1"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="..\"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/NSPTool.exe"\r
-                               LinkIncremental="1"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
-                               SubSystem="1"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories=".;..;../../mDNSShared"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="..\"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib"\r
-                               OutputFile="$(OutDir)/NSPTool.exe"\r
-                               LinkIncremental="1"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
-                               SubSystem="1"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\NSPTool.c"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\CommonServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\resource.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\NSPTool.rc"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/NSPTool/NSPTool.vcxproj b/mDNSWindows/NSPTool/NSPTool.vcxproj
deleted file mode 100755 (executable)
index 7c86852..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{208B3A9F-1CA0-4D1D-9D6C-C61616F94705}</ProjectGuid>\r
-    <Keyword>Win32Proj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <FunctionLevelLinking>false</FunctionLevelLinking>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>\r
-      <CallingConvention>Cdecl</CallingConvention>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)NSPTool.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <FunctionLevelLinking>false</FunctionLevelLinking>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>Cdecl</CallingConvention>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)NSPTool.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>.;..;../../mDNSShared;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)NSPTool.exe</OutputFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
-    <ClCompile Include="NSPTool.c" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
-    <ClInclude Include="resource.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="NSPTool.rc" />\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/NSPTool/NSPTool.vcxproj.filters b/mDNSWindows/NSPTool/NSPTool.vcxproj.filters
deleted file mode 100755 (executable)
index e52b917..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="NSPTool.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="resource.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="NSPTool.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/NSPTool/Prefix.h b/mDNSWindows/NSPTool/Prefix.h
deleted file mode 100644 (file)
index 3aa1cee..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __PREFIX__
-#define __PREFIX__
-
-#if( defined( _DEBUG ) )
-       #define DEBUG                           1
-       #define MDNS_DEBUGMSGS          1
-#else
-       #define DEBUG                           0
-#endif
-
-#endif // __PREFIX__
diff --git a/mDNSWindows/NSPTool/resource.h b/mDNSWindows/NSPTool/resource.h
deleted file mode 100644 (file)
index 78c1d91..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by NSPTool.rc
-//
-#define IDS_PROJNAME                    100
-#define IDR_WMDMLOGGER                  101
-#define IDS_LOG_SEV_INFO                201
-#define IDS_LOG_SEV_WARN                202
-#define IDS_LOG_SEV_ERROR               203
-#define IDS_LOG_DATETIME                204
-#define IDS_LOG_SRCNAME                 205
-#define IDS_DEF_LOGFILE                 301
-#define IDS_DEF_MAXSIZE                 302
-#define IDS_DEF_SHRINKTOSIZE            303
-#define IDS_DEF_LOGENABLED              304
-#define IDS_MUTEX_TIMEOUT               401
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        201
-#define _APS_NEXT_COMMAND_VALUE         32768
-#define _APS_NEXT_CONTROL_VALUE         201
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/mDNSWindows/Poll.c b/mDNSWindows/Poll.c
deleted file mode 100755 (executable)
index 9adc632..0000000
+++ /dev/null
@@ -1,728 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Poll.h"
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-#include <process.h>
-#include "GenLinkedList.h"
-#include "DebugServices.h"
-
-
-typedef struct PollSource_struct
-{
-       SOCKET socket;
-       HANDLE handle;
-       void   *context;
-
-       union
-       {
-               mDNSPollSocketCallback socket;
-               mDNSPollEventCallback event;
-       } callback;
-
-       struct Worker_struct            *worker;
-       struct PollSource_struct        *next;
-
-} PollSource;
-
-
-typedef struct Worker_struct
-{
-       HANDLE                                  thread;         // NULL for main worker
-       unsigned                                id;                     // 0 for main worker
-
-       HANDLE                                  start;          // NULL for main worker
-       HANDLE                                  stop;           // NULL for main worker
-       BOOL                                    done;           // Not used for main worker
-
-       DWORD                                   numSources;
-       PollSource                              *sources[ MAXIMUM_WAIT_OBJECTS ];
-       HANDLE                                  handles[ MAXIMUM_WAIT_OBJECTS ];
-       DWORD                                   result;
-       struct Worker_struct    *next;
-} Worker;
-
-
-typedef struct Poll_struct
-{
-       mDNSBool                setup;
-       HANDLE                  wakeup;
-       GenLinkedList   sources;
-       DWORD                   numSources;
-       Worker                  main;
-       GenLinkedList   workers;
-       HANDLE                  workerHandles[ MAXIMUM_WAIT_OBJECTS ];
-       DWORD                   numWorkers;
-
-} Poll;
-
-
-/*
- * Poll Methods
- */
-
-mDNSlocal mStatus                      PollSetup();
-mDNSlocal mStatus                      PollRegisterSource( PollSource *source ); 
-mDNSlocal void                         PollUnregisterSource( PollSource *source );
-mDNSlocal mStatus                      PollStartWorkers();
-mDNSlocal mStatus                      PollStopWorkers();
-mDNSlocal void                         PollRemoveWorker( Worker *worker );
-
-
-/*
- * Worker Methods
- */
-
-mDNSlocal mStatus                      WorkerInit( Worker *worker );
-mDNSlocal void                         WorkerFree( Worker *worker );
-mDNSlocal void                         WorkerRegisterSource( Worker *worker, PollSource *source );
-mDNSlocal int                          WorkerSourceToIndex( Worker *worker, PollSource *source );
-mDNSlocal void                         WorkerUnregisterSource( Worker *worker, PollSource *source );
-mDNSlocal void                         WorkerDispatch( Worker *worker);
-mDNSlocal void CALLBACK                WorkerWakeupNotification( HANDLE event, void *context );
-mDNSlocal unsigned WINAPI      WorkerMain( LPVOID inParam );
-
-
-static void
-ShiftDown( void * arr, size_t arraySize, size_t itemSize, int index )
-{
-    memmove( ( ( unsigned char* ) arr ) + ( ( index - 1 ) * itemSize ), ( ( unsigned char* ) arr ) + ( index * itemSize ), ( arraySize - index ) * itemSize );
-}
-
-
-#define        DEBUG_NAME      "[mDNSWin32] "
-#define gMDNSRecord mDNSStorage
-mDNSlocal Poll gPoll = { mDNSfalse, NULL };
-
-#define LogErr( err, FUNC ) LogMsg( "%s:%d - %s failed: %d\n", __FUNCTION__, __LINE__, FUNC, err );
-
-
-mStatus
-mDNSPollRegisterSocket( SOCKET socket, int networkEvents, mDNSPollSocketCallback callback, void *context )
-{
-       PollSource      *source = NULL;
-       HANDLE          event = INVALID_HANDLE_VALUE;
-       mStatus         err = mStatus_NoError;
-
-       if ( !gPoll.setup )
-       {
-               err = PollSetup();
-               require_noerr( err, exit );
-       }
-
-       source = malloc( sizeof( PollSource ) );
-       require_action( source, exit, err = mStatus_NoMemoryErr );
-
-       event = WSACreateEvent();
-       require_action( event, exit, err = mStatus_NoMemoryErr );
-
-       err = WSAEventSelect( socket, event, networkEvents );
-       require_noerr( err, exit );
-
-       source->socket = socket;
-       source->handle = event;
-       source->callback.socket = callback;
-       source->context = context;
-
-       err = PollRegisterSource( source );
-       require_noerr( err, exit );
-       
-exit:
-
-       if ( err != mStatus_NoError )
-       {
-               if ( event != INVALID_HANDLE_VALUE )
-               {
-                       WSACloseEvent( event );
-               }
-
-               if ( source != NULL )
-               {
-                       free( source );
-               }
-       }
-
-       return err;
-}
-
-
-void
-mDNSPollUnregisterSocket( SOCKET socket )
-{
-       PollSource      *source;
-
-       for ( source = gPoll.sources.Head; source; source = source->next )
-       {
-               if ( source->socket == socket )
-               {
-                       break;
-               }
-       }
-
-       if ( source )
-       {
-               WSACloseEvent( source->handle );
-               PollUnregisterSource( source );
-               free( source );
-       }
-}
-
-
-mStatus
-mDNSPollRegisterEvent( HANDLE event, mDNSPollEventCallback callback, void *context )
-{
-       PollSource      *source = NULL;
-       mStatus         err = mStatus_NoError;
-
-       if ( !gPoll.setup )
-       {
-               err = PollSetup();
-               require_noerr( err, exit );
-       }
-
-       source = malloc( sizeof( PollSource ) );
-       require_action( source, exit, err = mStatus_NoMemoryErr );
-
-       source->socket = INVALID_SOCKET;
-       source->handle = event;
-       source->callback.event = callback;
-       source->context = context;
-
-       err = PollRegisterSource( source ); 
-       require_noerr( err, exit );
-       
-exit:
-
-       if ( err != mStatus_NoError )
-       {
-               if ( source != NULL )
-               {
-                       free( source );
-               }
-       }
-
-       return err;
-}
-
-
-void
-mDNSPollUnregisterEvent( HANDLE event )
-{
-       PollSource      *source;
-
-       for ( source = gPoll.sources.Head; source; source = source->next )
-       {
-               if ( source->handle == event )
-               {
-                       break;
-               }
-       }
-
-       if ( source )
-       {
-               PollUnregisterSource( source );
-               free( source );
-       }
-}
-
-
-mStatus
-mDNSPoll( DWORD msec )
-{
-       mStatus err = mStatus_NoError;
-
-       if ( gPoll.numWorkers > 0 )
-       {       
-               err = PollStartWorkers();
-               require_noerr( err, exit );
-       }
-
-       gPoll.main.result = WaitForMultipleObjects( gPoll.main.numSources, gPoll.main.handles, FALSE, msec );
-       err = translate_errno( ( gPoll.main.result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
-       if ( err ) LogErr( err, "WaitForMultipleObjects()" );
-       require_action( gPoll.main.result != WAIT_FAILED, exit, err = ( mStatus ) GetLastError() );
-
-       if ( gPoll.numWorkers > 0 )
-       {
-               err = PollStopWorkers();
-               require_noerr( err, exit );
-       }
-
-       WorkerDispatch( &gPoll.main );
-
-exit:
-
-       return ( err );
-}
-
-
-mDNSlocal mStatus
-PollSetup()
-{
-       mStatus err = mStatus_NoError;
-
-       if ( !gPoll.setup )
-       {
-               memset( &gPoll, 0, sizeof( gPoll ) );
-
-               InitLinkedList( &gPoll.sources, offsetof( PollSource, next ) );
-               InitLinkedList( &gPoll.workers, offsetof( Worker, next ) );
-
-               gPoll.wakeup = CreateEvent( NULL, TRUE, FALSE, NULL );
-               require_action( gPoll.wakeup, exit, err = mStatus_NoMemoryErr );
-
-               err = WorkerInit( &gPoll.main );
-               require_noerr( err, exit );
-               
-               gPoll.setup = mDNStrue;
-       }
-
-exit:
-
-       return err;
-}
-
-
-mDNSlocal mStatus
-PollRegisterSource( PollSource *source )
-{
-       Worker  *worker = NULL;
-       mStatus err = mStatus_NoError;
-
-       AddToTail( &gPoll.sources, source );
-       gPoll.numSources++;
-
-       // First check our main worker. In most cases, we won't have to worry about threads
-
-       if ( gPoll.main.numSources < MAXIMUM_WAIT_OBJECTS )
-       {
-               WorkerRegisterSource( &gPoll.main, source );
-       }
-       else
-       {
-               // Try to find a thread to use that we've already created
-
-               for ( worker = gPoll.workers.Head; worker; worker = worker->next )
-               {
-                       if ( worker->numSources < MAXIMUM_WAIT_OBJECTS )
-                       {
-                               WorkerRegisterSource( worker, source );
-                               break;
-                       }
-               }
-
-               // If not, then create a worker and make a thread to run it in
-               
-               if ( !worker )
-               {
-                       worker = ( Worker* ) malloc( sizeof( Worker ) );                        
-                       require_action( worker, exit, err = mStatus_NoMemoryErr );
-
-                       memset( worker, 0, sizeof( Worker ) );
-
-                       worker->start = CreateEvent( NULL, FALSE, FALSE, NULL );
-                       require_action( worker->start, exit, err = mStatus_NoMemoryErr );
-
-                       worker->stop = CreateEvent( NULL, FALSE, FALSE, NULL );
-                       require_action( worker->stop, exit, err = mStatus_NoMemoryErr );
-
-                       err = WorkerInit( worker );
-                       require_noerr( err, exit );
-
-                       // Create thread with _beginthreadex() instead of CreateThread() to avoid
-                       // memory leaks when using static run-time libraries.
-                       // See <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createthread.asp>.
-
-                       worker->thread = ( HANDLE ) _beginthreadex_compat( NULL, 0, WorkerMain, worker, 0, &worker->id );
-                       err = translate_errno( worker->thread, ( mStatus ) GetLastError(), kUnknownErr );
-                       require_noerr( err, exit );
-
-                       AddToTail( &gPoll.workers, worker );
-                       gPoll.workerHandles[ gPoll.numWorkers++ ] = worker->stop;
-                       
-                       WorkerRegisterSource( worker, source );
-               }
-       }
-
-exit:
-
-       if ( err && worker )
-       {
-               WorkerFree( worker );
-       }
-
-       return err;
-}
-
-
-mDNSlocal void
-PollUnregisterSource( PollSource *source )
-{
-       RemoveFromList( &gPoll.sources, source );
-       gPoll.numSources--;
-
-       WorkerUnregisterSource( source->worker, source );
-}
-
-
-mDNSlocal mStatus
-PollStartWorkers()
-{
-       Worker  *worker;
-       mStatus err = mStatus_NoError;
-       BOOL    ok;
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "starting workers\n" );
-       
-       worker = gPoll.workers.Head;
-
-       while ( worker )
-       {
-               Worker *next = worker->next;
-
-               if ( worker->numSources == 1 )
-               {
-                       PollRemoveWorker( worker );
-               }
-               else
-               {
-                       dlog( kDebugLevelChatty, DEBUG_NAME "waking up worker\n" );
-
-                       ok = SetEvent( worker->start );
-                       err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
-                       if ( err ) LogErr( err, "SetEvent()" );
-
-                       if ( err )
-                       {
-                               PollRemoveWorker( worker );
-                       }
-               }
-
-               worker = next;
-       }
-
-       err = mStatus_NoError;
-
-       return err;
-}
-
-
-mDNSlocal mStatus
-PollStopWorkers()
-{
-       DWORD   result;
-       Worker  *worker;
-       BOOL    ok;
-       mStatus err = mStatus_NoError;
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "stopping workers\n" );
-       
-       ok = SetEvent( gPoll.wakeup );
-       err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
-       if ( err ) LogErr( err, "SetEvent()" );
-
-       // Wait For 5 seconds for all the workers to wake up
-
-       result = WaitForMultipleObjects( gPoll.numWorkers, gPoll.workerHandles, TRUE, 5000 );
-       err = translate_errno( ( result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
-       if ( err ) LogErr( err, "WaitForMultipleObjects()" );
-
-       ok = ResetEvent( gPoll.wakeup );
-       err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
-       if ( err ) LogErr( err, "ResetEvent()" );
-
-       for ( worker = gPoll.workers.Head; worker; worker = worker->next )
-       {
-               WorkerDispatch( worker );
-       }
-
-       err = mStatus_NoError;
-
-       return err;
-}
-
-
-mDNSlocal void
-PollRemoveWorker( Worker *worker )
-{
-       DWORD   result;
-       mStatus err;
-       BOOL    ok;
-       DWORD   i;
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "removing worker %d\n", worker->id );
-       
-       RemoveFromList( &gPoll.workers, worker );
-
-       // Remove handle from gPoll.workerHandles
-
-       for ( i = 0; i < gPoll.numWorkers; i++ )
-       {
-               if ( gPoll.workerHandles[ i ] == worker->stop )
-               {
-                       ShiftDown( gPoll.workerHandles, gPoll.numWorkers, sizeof( gPoll.workerHandles[ 0 ] ), i + 1 );
-                       break;
-               }
-       }
-
-       worker->done = TRUE;
-       gPoll.numWorkers--;
-
-       // Cause the thread to exit.
-
-       ok = SetEvent( worker->start );
-       err = translate_errno( ok, ( OSStatus ) GetLastError(), kUnknownErr );
-       if ( err ) LogErr( err, "SetEvent()" );
-                       
-       result = WaitForSingleObject( worker->thread, 5000 );
-       err = translate_errno( result != WAIT_FAILED, ( OSStatus ) GetLastError(), kUnknownErr );
-       if ( err ) LogErr( err, "WaitForSingleObject()" );
-                       
-       if ( ( result == WAIT_FAILED ) || ( result == WAIT_TIMEOUT ) )
-       {
-               ok = TerminateThread( worker->thread, 0 );
-               err = translate_errno( ok, ( OSStatus ) GetLastError(), kUnknownErr );
-               if ( err ) LogErr( err, "TerminateThread()" );
-       }
-       
-       CloseHandle( worker->thread );
-       worker->thread = NULL;
-
-       WorkerFree( worker );
-}
-
-
-mDNSlocal void
-WorkerRegisterSource( Worker *worker, PollSource *source )
-{
-       source->worker = worker;
-       worker->sources[ worker->numSources ] = source;
-       worker->handles[ worker->numSources ] = source->handle;
-       worker->numSources++;
-}
-
-
-mDNSlocal int
-WorkerSourceToIndex( Worker *worker, PollSource *source )
-{
-       int index;
-
-       for ( index = 0; index < ( int ) worker->numSources; index++ )
-       {
-               if ( worker->sources[ index ] == source )
-               {
-                       break;
-               }
-       }
-
-       if ( index == ( int ) worker->numSources )
-       {
-               index = -1;
-       }
-
-       return index;
-}
-
-
-mDNSlocal void
-WorkerUnregisterSource( Worker *worker, PollSource *source )
-{
-       int sourceIndex = WorkerSourceToIndex( worker, source );
-       DWORD delta;
-
-       if ( sourceIndex == -1 )
-       {
-               LogMsg( "WorkerUnregisterSource: source not found in list" );
-               goto exit;
-       }
-
-       delta = ( worker->numSources - sourceIndex - 1 );
-
-       // If this source is not at the end of the list, then move memory
-
-       if ( delta > 0 )
-       {
-               ShiftDown( worker->sources, worker->numSources, sizeof( worker->sources[ 0 ] ), sourceIndex + 1 );
-               ShiftDown( worker->handles, worker->numSources, sizeof( worker->handles[ 0 ] ), sourceIndex + 1 );
-       }
-                        
-       worker->numSources--;
-
-exit:
-
-       return;
-}
-
-
-mDNSlocal void CALLBACK
-WorkerWakeupNotification( HANDLE event, void *context )
-{
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "Worker thread wakeup\n" );
-}
-
-
-mDNSlocal void
-WorkerDispatch( Worker *worker )
-{
-       if ( worker->result == WAIT_FAILED )
-       {
-               /* What should we do here? */
-       }
-       else if ( worker->result == WAIT_TIMEOUT )
-       {
-               dlog( kDebugLevelChatty, DEBUG_NAME "timeout\n" );
-       }
-       else
-       {
-               DWORD           waitItemIndex = ( DWORD )( ( ( int ) worker->result ) - WAIT_OBJECT_0 );
-               PollSource      *source = NULL;
-
-               // Sanity check
-
-               if ( waitItemIndex >= worker->numSources )
-               {
-                       LogMsg( "WorkerDispatch: waitItemIndex (%d) is >= numSources (%d)", waitItemIndex, worker->numSources );
-                       goto exit;
-               }
-
-               source = worker->sources[ waitItemIndex ];
-
-               if ( source->socket != INVALID_SOCKET )
-               {
-                       WSANETWORKEVENTS event;
-       
-                       if ( WSAEnumNetworkEvents( source->socket, source->handle, &event ) == 0 )
-                       {
-                               source->callback.socket( source->socket, &event, source->context );
-                       }
-                       else
-                       {
-                               source->callback.socket( source->socket, NULL, source->context );
-                       }
-               }
-               else
-               {
-                       source->callback.event( source->handle, source->context );
-               }
-       }
-
-exit:
-
-       return;
-}
-
-
-mDNSlocal mStatus
-WorkerInit( Worker *worker )
-{
-       PollSource *source = NULL;
-       mStatus err = mStatus_NoError;
-       
-       require_action( worker, exit, err = mStatus_BadParamErr );
-
-       source = malloc( sizeof( PollSource ) );
-       require_action( source, exit, err = mStatus_NoMemoryErr );
-
-       source->socket = INVALID_SOCKET;
-       source->handle = gPoll.wakeup;
-       source->callback.event = WorkerWakeupNotification;
-       source->context = NULL;
-       
-       WorkerRegisterSource( worker, source );
-
-exit:
-
-       return err;
-}
-       
-
-mDNSlocal void
-WorkerFree( Worker *worker )
-{
-       if ( worker->start )
-       {
-               CloseHandle( worker->start );
-               worker->start = NULL;
-       }
-
-       if ( worker->stop )
-       {
-               CloseHandle( worker->stop );
-               worker->stop = NULL;
-       }
-
-       free( worker );
-}
-
-
-mDNSlocal unsigned WINAPI
-WorkerMain( LPVOID inParam )
-{
-       Worker *worker = ( Worker* ) inParam;
-       mStatus err = mStatus_NoError;
-
-       require_action( worker, exit, err = mStatus_BadParamErr );
-
-       dlog( kDebugLevelVerbose, DEBUG_NAME, "entering WorkerMain()\n" );
-
-       while ( TRUE )
-       {
-               DWORD   result;
-               BOOL    ok;
-
-               dlog( kDebugLevelChatty, DEBUG_NAME, "worker thread %d will wait on main loop\n", worker->id );
-               
-               result = WaitForSingleObject( worker->start, INFINITE );        
-               err = translate_errno( ( result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
-               if ( err ) { LogErr( err, "WaitForSingleObject()" ); break; }
-               if ( worker->done ) break;
-
-               dlog( kDebugLevelChatty, DEBUG_NAME "worker thread %d will wait on sockets\n", worker->id );
-
-               worker->result = WaitForMultipleObjects( worker->numSources, worker->handles, FALSE, INFINITE );
-               err = translate_errno( ( worker->result != WAIT_FAILED ), ( mStatus ) GetLastError(), kUnknownErr );
-               if ( err ) { LogErr( err, "WaitForMultipleObjects()" ); break; }
-
-               dlog( kDebugLevelChatty, DEBUG_NAME "worker thread %d did wait on sockets: %d\n", worker->id, worker->result );
-
-               ok = SetEvent( gPoll.wakeup );
-               err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
-               if ( err ) { LogErr( err, "SetEvent()" ); break; }
-
-               dlog( kDebugLevelChatty, DEBUG_NAME, "worker thread %d preparing to sleep\n", worker->id );
-
-               ok = SetEvent( worker->stop );
-               err = translate_errno( ok, ( mStatus ) GetLastError(), kUnknownErr );
-               if ( err ) { LogErr( err, "SetEvent()" ); break; }
-       }
-
-       dlog( kDebugLevelVerbose, DEBUG_NAME "exiting WorkerMain()\n" );
-
-exit:
-
-       return 0;
-}
diff --git a/mDNSWindows/Poll.h b/mDNSWindows/Poll.h
deleted file mode 100755 (executable)
index bd1b10f..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _Poll_h
-#define _Poll_h
-
-#include       "CommonServices.h"
-#include       <mswsock.h>
-#include       "mDNSEmbeddedAPI.h"
-#include       "uDNS.h"
-
-
-#if defined(__cplusplus )
-extern "C" {
-#endif
-
-
-typedef void ( CALLBACK *mDNSPollSocketCallback )( SOCKET socket, LPWSANETWORKEVENTS event, void *context );
-typedef void ( CALLBACK *mDNSPollEventCallback )( HANDLE event, void *context );
-
-
-extern mStatus
-mDNSPollRegisterSocket( SOCKET socket, int networkEvents, mDNSPollSocketCallback callback, void *context );
-
-
-extern void
-mDNSPollUnregisterSocket( SOCKET socket );
-
-
-extern mStatus
-mDNSPollRegisterEvent( HANDLE event, mDNSPollEventCallback callback, void *context );
-
-
-extern void
-mDNSPollUnregisterEvent( HANDLE event );
-
-
-extern mStatus
-mDNSPoll( DWORD msec );
-
-
-#if defined(__cplusplus)
-}
-#endif
-
-
-#endif
diff --git a/mDNSWindows/PosixCompat.c b/mDNSWindows/PosixCompat.c
deleted file mode 100755 (executable)
index faabd07..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-/* -*- 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.
- */
-
-#include "PosixCompat.h"
-#include <DebugServices.h>
-
-
-typedef PCHAR (WINAPI * if_indextoname_funcptr_t)(ULONG index, PCHAR name);
-typedef ULONG (WINAPI * if_nametoindex_funcptr_t)(PCSTR name);
-
-
-unsigned
-if_nametoindex( const char * ifname )
-{
-       HMODULE library;
-       unsigned index = 0;
-
-       check( ifname );
-
-       // Try and load the IP helper library dll
-       if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
-       {
-               if_nametoindex_funcptr_t if_nametoindex_funcptr;
-
-               // On Vista and above there is a Posix like implementation of if_nametoindex
-               if ((if_nametoindex_funcptr = (if_nametoindex_funcptr_t) GetProcAddress(library, "if_nametoindex")) != NULL )
-               {
-                       index = if_nametoindex_funcptr(ifname);
-               }
-
-               FreeLibrary(library);
-       }
-
-       return index;
-}
-
-
-char*
-if_indextoname( unsigned ifindex, char * ifname )
-{
-       HMODULE library;
-       char * name = NULL;
-
-       check( ifname );
-       *ifname = '\0';
-
-       // Try and load the IP helper library dll
-       if ((library = LoadLibrary(TEXT("Iphlpapi")) ) != NULL )
-       {
-               if_indextoname_funcptr_t if_indextoname_funcptr;
-
-               // On Vista and above there is a Posix like implementation of if_indextoname
-               if ((if_indextoname_funcptr = (if_indextoname_funcptr_t) GetProcAddress(library, "if_indextoname")) != NULL )
-               {
-                       name = if_indextoname_funcptr(ifindex, ifname);
-               }
-
-               FreeLibrary(library);
-       }
-
-       return name;
-}
-
-
-int
-inet_pton( int family, const char * addr, void * dst )
-{
-       struct sockaddr_storage ss;
-       int sslen = sizeof( ss );
-
-       ZeroMemory( &ss, sizeof( ss ) );
-       ss.ss_family = family;
-
-       if ( WSAStringToAddressA( ( LPSTR ) addr, family, NULL, ( struct sockaddr* ) &ss, &sslen ) == 0 )
-       {
-               if ( family == AF_INET ) { memcpy( dst, &( ( struct sockaddr_in* ) &ss)->sin_addr, sizeof( IN_ADDR ) ); return 1; }
-               else if ( family == AF_INET6 ) { memcpy( dst, &( ( struct sockaddr_in6* ) &ss)->sin6_addr, sizeof( IN6_ADDR ) ); return 1; }
-               else return 0;
-       }
-    else return 0;
-}
-
-
-int
-gettimeofday( struct timeval * tv, struct timezone * tz )
-{
-#define EPOCHFILETIME (116444736000000000i64)
-
-       if ( tv != NULL )
-       {
-               FILETIME        ft;
-               LARGE_INTEGER   li;
-               __int64         t;
-
-               GetSystemTimeAsFileTime(&ft);
-               li.LowPart  = ft.dwLowDateTime;
-               li.HighPart = ft.dwHighDateTime;
-               t  = li.QuadPart;       /* In 100-nanosecond intervals */
-               t -= EPOCHFILETIME;     /* Offset to the Epoch time */
-               t /= 10;                        /* In microseconds */
-               tv->tv_sec  = ( long )( t / 1000000 );
-               tv->tv_usec = ( long )( t % 1000000 );
-       }
-
-       return 0;
-}
-
-
-extern struct tm*
-localtime_r( const time_t * clock, struct tm * result )
-{
-       localtime_s( result, clock );
-       return result;
-}
diff --git a/mDNSWindows/PosixCompat.h b/mDNSWindows/PosixCompat.h
deleted file mode 100755 (executable)
index 9f9d005..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- 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.
- */
-
-#pragma once
-
-#include "CommonServices.h"
-#include <winsock2.h>
-#include <time.h>
-
-
-/* 
- * Posix process compatibility
- */
-typedef int pid_t;
-#if !defined( getpid )
-#      define getpid _getpid
-#endif
-
-
-/* 
- * Posix networking compatibility
- */
-extern unsigned
-if_nametoindex( const char * ifname );
-
-
-extern char*
-if_indextoname( unsigned ifindex, char * ifname );
-
-
-extern int
-inet_pton( int family, const char * addr, void * dst );
-
-
-/* 
- * Posix time compatibility
- */
-extern int
-gettimeofday( struct timeval * tv, struct timezone * tz );
-
-
-extern struct tm*
-localtime_r( const time_t * clock, struct tm * result );
-
-
-/* 
- * Posix string compatibility
- */
-#if !defined( strcasecmp )
-#      define strcasecmp       _stricmp
-#endif
-
-#if !defined( snprintf )
-#      define snprint          _snprintf
-#endif
-
diff --git a/mDNSWindows/README.txt b/mDNSWindows/README.txt
deleted file mode 100644 (file)
index 8d8ab4b..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-This directory contains support files for running mDNS on Microsoft Windows 
-and Windows CE/PocketPC. Building this code requires the Windows SDK 2003
-or later. The CodeWarrior builds require CodeWarrior 8 or later and if using
-CodeWarrior 8, the newer Windows headers from the Mac CodeWarrior 9 need to
-be used.
-
-mDNSWin32.c/.h
-       
-       Platform Support files that go below mDNS Core. These work on both Windows 
-       and Windows CE/PocketPC.
-
-DNSSD.c/.h
-
-       High-level implementation of the DNS-SD API. This supports both "direct"
-       (compiled-in mDNSCore) and "client" (IPC to service) usage. Conditionals
-       can exclude either "direct" or "client" to reduce code size.
-
-DNSSDDirect.c/.h
-
-       Portable implementation of the DNS-SD API. This interacts with mDNSCore
-       to perform all the real work of the DNS-SD API. This code does not rely
-       on any platform-specifics so it should run on any platform with an mDNS
-       platform plugin available. Software that cannot or does not want to use
-       the IPC mechanism (e.g. Windows CE, VxWorks, etc.) can use this code 
-       directly without any of the IPC pieces.
-
-RMxClient.c/.h
-       
-       Client-side implementation of the DNS-SD IPC API. This handles sending 
-       and receiving messages from the service to perform DNS-SD operations 
-       and get DNS-SD responses.
-
-RMxCommon.c/.h
-
-       Common code between the RMxClient and RMxServer. This handles establishing
-       and accepting connections, the underying message sending and receiving, 
-       portable data packing and unpacking, and shared utility routines.
-
-RMxServer.c/.h
-
-       Server-side implementation of the DNS-SD IPC API. This listens for 
-       and accepts connections from IPC clients, starts server sessions, and 
-       acts as a mediator between the "direct" (compiled-in mDNSCore) code
-       and the IPC client.
-
-DNSServices is an obsolete higher-level API for using mDNS. New code should 
-use the DNS-SD APIs.
-
-DNSServiceDiscovery is an obsolete emulation layer that sits on top of 
-DNSServices and provides the Mac OS X DNS Service Discovery API's on any 
-platform. New code should use the DNS-SD APIs.
-
-Tool.c is an example client that uses the services of mDNS Core.
-
-ToolWin32.mcp is a CodeWarrior project (CodeWarrior for Windows version 8). 
-ToolWin32.vcproj is a Visual Studio .NET 7 project. These projects build 
-Tool.c to make DNSServiceTest.exe, a small Windows command-line tool to do all 
-the standard DNS-SD stuff on Windows. It has the following features:
-
-- Browse for browsing and/or registration domains.
-- Browse for services.
-- Lookup Service Instances.
-- Register domains for browsing and/or registration.
-- Register services.
-
-For example, if you have a Windows machine running a Web server,
-then you can make it advertise that it is offering HTTP on port 80
-with the following command:
-
-DNSServiceTest -rs "Windows Web Server" "_http._tcp." "local." 80 ""
-
-To search for AFP servers, use this:
-
-DNSServiceTest -bs "_afpovertcp._tcp." "local."
-
-You can also do multiple things at once (e.g. register a service and
-browse for it so one instance of the app can be used for testing).
-Multiple instances can also be run on the same machine to discover each
-other. There is a -help command to show all the commands, their
-parameters, and some examples of using it.
-
-DNSServiceBrowser contains the source code for a graphical browser application 
-for Windows CE/PocketPC. The Windows CE/PocketPC version requires Microsoft 
-eMbedded C++ 4.0 with SP2 installed and the PocketPC 2003 SDK.
-
diff --git a/mDNSWindows/RegNames.h b/mDNSWindows/RegNames.h
deleted file mode 100644 (file)
index bc885d6..0000000
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//----------------------------------------------------------------------------------------
-//     Registry Constants
-//----------------------------------------------------------------------------------------
-
-#if defined(UNICODE)
-
-#      define kServiceParametersSoftware                       L"SOFTWARE"
-#      define kServiceParametersAppleComputer          L"Apple Computer, Inc."
-#      define kServiceParametersBonjour                        L"Bonjour"
-#      define kServiceParametersNode                           L"SOFTWARE\\Apple Inc.\\Bonjour"
-#      define kServiceName                                                     L"Bonjour Service"
-#      define kServiceDynDNSBrowseDomains                      L"BrowseDomains"
-#      define kServiceDynDNSHostNames                          L"HostNames"
-#      define kServiceDynDNSRegistrationDomains        L"RegistrationDomains"
-#      define kServiceDynDNSDomains                            L"Domains"      // value is comma separated list of domains
-#      define kServiceDynDNSEnabled                            L"Enabled"
-#      define kServiceDynDNSStatus                                     L"Status"
-#      define kServiceManageLLRouting                          L"ManageLLRouting"
-#      define kServiceCacheEntryCount                          L"CacheEntryCount"
-#      define kServiceManageFirewall                           L"ManageFirewall"
-#      define kServiceAdvertisedServices                       L"Services"
-
-# else
-
-#      define kServiceParametersSoftware                       "SOFTWARE"
-#      define kServiceParametersAppleComputer          "Apple Computer, Inc."
-#      define kServiceParametersBonjour                        "Bonjour"
-#      define kServiceParametersNode                           "SOFTWARE\\Apple Inc.\\Bonjour"
-#      define kServiceName                                                     "Bonjour Service"
-#      define kServiceDynDNSBrowseDomains                      "BrowseDomains"
-#      define kServiceDynDNSHostNames                          "HostNames"
-#      define kServiceDynDNSRegistrationDomains        "RegistrationDomains"
-#      define kServiceDynDNSDomains                            "Domains"       // value is comma separated list of domains
-#      define kServiceDynDNSEnabled                            "Enabled"
-#      define kServiceDynDNSStatus                                     "Status"
-#      define kServiceManageLLRouting                          "ManageLLRouting"
-#      define kServiceCacheEntryCount                          "CacheEntryCount"
-#      define kServiceManageFirewall                           "ManageFirewall"
-
-#endif
diff --git a/mDNSWindows/Secret.c b/mDNSWindows/Secret.c
deleted file mode 100644 (file)
index b5f254c..0000000
+++ /dev/null
@@ -1,338 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Secret.h"
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#include <windows.h>
-#include <process.h>
-#include <ntsecapi.h>
-#include <lm.h>
-#include "DebugServices.h"
-
-
-mDNSlocal OSStatus MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input );
-mDNSlocal OSStatus MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input );
-
-
-mDNSBool
-LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainSize, char * outKey, unsigned outKeySize, char * outSecret, unsigned outSecretSize )
-{
-       PLSA_UNICODE_STRING             domainLSA;
-       PLSA_UNICODE_STRING             keyLSA;
-       PLSA_UNICODE_STRING             secretLSA;
-       size_t                                  i;
-       size_t                                  dlen;
-       LSA_OBJECT_ATTRIBUTES   attrs;
-       LSA_HANDLE                              handle = NULL;
-       NTSTATUS                                res;
-       OSStatus                                err;
-
-       check( inDomain );
-       check( outDomain );
-       check( outKey );
-       check( outSecret );
-
-       // Initialize
-
-       domainLSA       = NULL;
-       keyLSA          = NULL;
-       secretLSA       = NULL;
-
-       // Make sure we have enough space to add trailing dot
-
-       dlen = strlen( inDomain );
-       err = strcpy_s( outDomain, outDomainSize - 2, inDomain );
-       require_noerr( err, exit );
-
-       // If there isn't a trailing dot, add one because the mDNSResponder
-       // presents names with the trailing dot.
-
-       if ( outDomain[ dlen - 1 ] != '.' )
-       {
-               outDomain[ dlen++ ] = '.';
-               outDomain[ dlen ] = '\0';
-       }
-
-       // Canonicalize name by converting to lower case (keychain and some name servers are case sensitive)
-
-       for ( i = 0; i < dlen; i++ )
-       {
-               outDomain[i] = (char) tolower( outDomain[i] );  // canonicalize -> lower case
-       }
-
-       // attrs are reserved, so initialize to zeroes.
-
-       ZeroMemory( &attrs, sizeof( attrs ) );
-
-       // Get a handle to the Policy object on the local system
-
-       res = LsaOpenPolicy( NULL, &attrs, POLICY_GET_PRIVATE_INFORMATION, &handle );
-       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-       require_noerr( err, exit );
-
-       // Get the encrypted data
-
-       domainLSA = ( PLSA_UNICODE_STRING ) malloc( sizeof( LSA_UNICODE_STRING ) );
-       require_action( domainLSA != NULL, exit, err = mStatus_NoMemoryErr );
-       err = MakeLsaStringFromUTF8String( domainLSA, outDomain );
-       require_noerr( err, exit );
-
-       // Retrieve the key
-
-       res = LsaRetrievePrivateData( handle, domainLSA, &keyLSA );
-       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-       require_noerr_quiet( err, exit );
-
-       // <rdar://problem/4192119> Lsa secrets use a flat naming space.  Therefore, we will prepend "$" to the keyname to
-       // make sure it doesn't conflict with a zone name.      
-       // Strip off the "$" prefix.
-
-       err = MakeUTF8StringFromLsaString( outKey, outKeySize, keyLSA );
-       require_noerr( err, exit );
-       require_action( outKey[0] == '$', exit, err = kUnknownErr );
-       memcpy( outKey, outKey + 1, strlen( outKey ) );
-
-       // Retrieve the secret
-
-       res = LsaRetrievePrivateData( handle, keyLSA, &secretLSA );
-       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-       require_noerr_quiet( err, exit );
-
-       // Convert the secret to UTF8 string
-
-       err = MakeUTF8StringFromLsaString( outSecret, outSecretSize, secretLSA );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( domainLSA != NULL )
-       {
-               if ( domainLSA->Buffer != NULL )
-               {
-                       free( domainLSA->Buffer );
-               }
-
-               free( domainLSA );
-       }
-
-       if ( keyLSA != NULL )
-       {
-               LsaFreeMemory( keyLSA );
-       }
-
-       if ( secretLSA != NULL )
-       {
-               LsaFreeMemory( secretLSA );
-       }
-
-       if ( handle )
-       {
-               LsaClose( handle );
-               handle = NULL;
-       }
-
-       return ( !err ) ? TRUE : FALSE;
-}
-
-
-mDNSBool
-LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret )
-{
-       size_t                                  inDomainLength;
-       size_t                                  inKeyLength;
-       char                                    domain[ 1024 ];
-       char                                    key[ 1024 ];
-       LSA_OBJECT_ATTRIBUTES   attrs;
-       LSA_HANDLE                              handle = NULL;
-       NTSTATUS                                res;
-       LSA_UNICODE_STRING              lucZoneName;
-       LSA_UNICODE_STRING              lucKeyName;
-       LSA_UNICODE_STRING              lucSecretName;
-       BOOL                                    ok = TRUE;
-       OSStatus                                err;
-
-       require_action( inDomain != NULL, exit, ok = FALSE );
-       require_action( inKey != NULL, exit, ok = FALSE );
-       require_action( inSecret != NULL, exit, ok = FALSE );
-
-       // If there isn't a trailing dot, add one because the mDNSResponder
-       // presents names with the trailing dot.
-
-       ZeroMemory( domain, sizeof( domain ) );
-       inDomainLength = strlen( inDomain );
-       require_action( inDomainLength > 0, exit, ok = FALSE );
-       err = strcpy_s( domain, sizeof( domain ) - 2, inDomain );
-       require_action( !err, exit, ok = FALSE );
-
-       if ( domain[ inDomainLength - 1 ] != '.' )
-       {
-               domain[ inDomainLength++ ] = '.';
-               domain[ inDomainLength ] = '\0';
-       }
-
-       // <rdar://problem/4192119>
-       //
-       // Prepend "$" to the key name, so that there will
-       // be no conflict between the zone name and the key
-       // name
-
-       ZeroMemory( key, sizeof( key ) );
-       inKeyLength = strlen( inKey );
-       require_action( inKeyLength > 0 , exit, ok = FALSE );
-       key[ 0 ] = '$';
-       err = strcpy_s( key + 1, sizeof( key ) - 3, inKey );
-       require_action( !err, exit, ok = FALSE );
-       inKeyLength++;
-
-       if ( key[ inKeyLength - 1 ] != '.' )
-       {
-               key[ inKeyLength++ ] = '.';
-               key[ inKeyLength ] = '\0';
-       }
-
-       // attrs are reserved, so initialize to zeroes.
-
-       ZeroMemory( &attrs, sizeof( attrs ) );
-
-       // Get a handle to the Policy object on the local system
-
-       res = LsaOpenPolicy( NULL, &attrs, POLICY_ALL_ACCESS, &handle );
-       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-       require_noerr( err, exit );
-
-       // Intializing PLSA_UNICODE_STRING structures
-
-       err = MakeLsaStringFromUTF8String( &lucZoneName, domain );
-       require_noerr( err, exit );
-
-       err = MakeLsaStringFromUTF8String( &lucKeyName, key );
-       require_noerr( err, exit );
-
-       err = MakeLsaStringFromUTF8String( &lucSecretName, inSecret );
-       require_noerr( err, exit );
-
-       // Store the private data.
-
-       res = LsaStorePrivateData( handle, &lucZoneName, &lucKeyName );
-       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-       require_noerr( err, exit );
-
-       res = LsaStorePrivateData( handle, &lucKeyName, &lucSecretName );
-       err = translate_errno( res == 0, LsaNtStatusToWinError( res ), kUnknownErr );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( handle )
-       {
-               LsaClose( handle );
-               handle = NULL;
-       }
-
-       return ok;
-}
-
-
-//===========================================================================================================================
-//     MakeLsaStringFromUTF8String
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-MakeLsaStringFromUTF8String( PLSA_UNICODE_STRING output, const char * input )
-{
-       int                     size;
-       OSStatus        err;
-       
-       check( input );
-       check( output );
-
-       output->Buffer = NULL;
-
-       size = MultiByteToWideChar( CP_UTF8, 0, input, -1, NULL, 0 );
-       err = translate_errno( size > 0, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       output->Length = (USHORT)( size * sizeof( wchar_t ) );
-       output->Buffer = (PWCHAR) malloc( output->Length );
-       require_action( output->Buffer, exit, err = mStatus_NoMemoryErr );
-       size = MultiByteToWideChar( CP_UTF8, 0, input, -1, output->Buffer, size );
-       err = translate_errno( size > 0, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       // We're going to subtrace one wchar_t from the size, because we didn't
-       // include it when we encoded the string
-
-       output->MaximumLength = output->Length;
-       output->Length          -= sizeof( wchar_t );
-       
-exit:
-
-       if ( err && output->Buffer )
-       {
-               free( output->Buffer );
-               output->Buffer = NULL;
-       }
-
-       return( err );
-}
-
-
-
-//===========================================================================================================================
-//     MakeUTF8StringFromLsaString
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-MakeUTF8StringFromLsaString( char * output, size_t len, PLSA_UNICODE_STRING input )
-{
-       size_t          size;
-       OSStatus        err = kNoErr;
-
-       // The Length field of this structure holds the number of bytes,
-       // but WideCharToMultiByte expects the number of wchar_t's. So
-       // we divide by sizeof(wchar_t) to get the correct number.
-
-       size = (size_t) WideCharToMultiByte(CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), NULL, 0, NULL, NULL);
-       err = translate_errno( size != 0, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       // Ensure that we have enough space (Add one for trailing '\0')
-
-       require_action( ( size + 1 ) <= len, exit, err = mStatus_NoMemoryErr );
-
-       // Convert the string
-
-       size = (size_t) WideCharToMultiByte( CP_UTF8, 0, input->Buffer, ( input->Length / sizeof( wchar_t ) ), output, (int) size, NULL, NULL); 
-       err = translate_errno( size != 0, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       // have to add the trailing 0 because WideCharToMultiByte doesn't do it,
-       // although it does return the correct size
-
-       output[size] = '\0';
-
-exit:
-
-       return err;
-}
-
diff --git a/mDNSWindows/Secret.h b/mDNSWindows/Secret.h
deleted file mode 100644 (file)
index f5434f0..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _Secret_h
-#define _Secret_h
-
-#include "mDNSEmbeddedAPI.h"
-
-
-#if defined(__cplusplus )
-extern "C" {
-#endif
-
-
-extern mDNSBool
-LsaGetSecret( const char * inDomain, char * outDomain, unsigned outDomainSize, char * outKey, unsigned outKeySize, char * outSecret, unsigned outSecretSize );
-
-
-extern mDNSBool
-LsaSetSecret( const char * inDomain, const char * inKey, const char * inSecret );
-
-
-#if defined(__cplusplus)
-}
-#endif
-
-
-#endif
diff --git a/mDNSWindows/SystemService/EventLog.mc b/mDNSWindows/SystemService/EventLog.mc
deleted file mode 100644 (file)
index 248e6c1..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-MessageIdTypedef=WORD
-LanguageNames=(English=0x409:MSG00409)
-
-MessageId=100
-SymbolicName=MDNSRESPONDER_LOG
-Severity=Success
-Facility=Application
-Language=English
-%1
-.
-
diff --git a/mDNSWindows/SystemService/EventLogMessages.bin b/mDNSWindows/SystemService/EventLogMessages.bin
deleted file mode 100644 (file)
index e74c67e..0000000
Binary files a/mDNSWindows/SystemService/EventLogMessages.bin and /dev/null differ
diff --git a/mDNSWindows/SystemService/Firewall.cpp b/mDNSWindows/SystemService/Firewall.cpp
deleted file mode 100755 (executable)
index c7c96d0..0000000
+++ /dev/null
@@ -1,484 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// <rdar://problem/4278931> Doesn't compile correctly with latest Platform SDK
-
-#if !defined(_WIN32_DCOM)
-#      define _WIN32_DCOM 
-#endif
-
-
-#include "Firewall.h"
-#include <windows.h>
-#include <crtdbg.h>
-#include <netfw.h>
-#include <objbase.h>
-#include <oleauto.h>
-
-
-static const int kMaxTries                     = 30;
-static const int kRetrySleepPeriod     = 1 * 1000; // 1 second
-
-
-static OSStatus
-mDNSFirewallInitialize(OUT INetFwProfile ** fwProfile)
-{
-       INetFwMgr               *       fwMgr           = NULL;
-       INetFwPolicy    *       fwPolicy        = NULL;
-       int                                     numRetries      = 0;
-       HRESULT                         err                     = kNoErr;
-    
-       _ASSERT(fwProfile != NULL);
-
-    *fwProfile = NULL;
-
-       // Use COM to get a reference to the firewall settings manager.  This
-       // call will fail on anything other than XP SP2
-
-       err = CoCreateInstance( __uuidof(NetFwMgr), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwMgr), (void**)&fwMgr );
-       require(SUCCEEDED(err) && ( fwMgr != NULL ), exit);
-
-       // Use the reference to get the local firewall policy
-
-       err = fwMgr->get_LocalPolicy(&fwPolicy);
-       require(SUCCEEDED(err) && ( fwPolicy != NULL ), exit);
-
-       // Use the reference to get the extant profile. Empirical evidence
-       // suggests that there is the potential for a race condition when a system
-       // service whose startup type is automatic calls this method.
-       // This is true even when the service declares itself to be dependent
-       // on the firewall service. Re-trying the method will succeed within
-       // a few seconds.
-
-       do
-       {
-       err = fwPolicy->get_CurrentProfile(fwProfile);
-
-               if (err)
-               {
-                       Sleep(kRetrySleepPeriod);
-               }
-       }
-       while (err && (numRetries++ < kMaxTries));
-
-       require(SUCCEEDED(err), exit);
-
-       err = kNoErr;
-
-exit:
-
-       // Release temporary COM objects
-
-    if (fwPolicy != NULL)
-    {
-        fwPolicy->Release();
-    }
-
-    if (fwMgr != NULL)
-    {
-        fwMgr->Release();
-    }
-
-    return err;
-}
-
-
-static void
-mDNSFirewallCleanup
-                       (
-                       IN INetFwProfile        *       fwProfile
-                       )
-{
-       // Call Release on the COM reference.
-
-    if (fwProfile != NULL)
-    {
-        fwProfile->Release();
-    }
-}
-
-
-static OSStatus
-mDNSFirewallAppIsEnabled
-                       (
-                       IN INetFwProfile        *       fwProfile,
-                       IN const wchar_t        *       fwProcessImageFileName,
-                       OUT BOOL                        *       fwAppEnabled    
-                       )
-{
-       BSTR                                                    fwBstrProcessImageFileName = NULL;
-       VARIANT_BOOL                                    fwEnabled;
-       INetFwAuthorizedApplication     *       fwApp   = NULL;
-       INetFwAuthorizedApplications*   fwApps  = NULL;
-       OSStatus                                                err             = kNoErr;
-    
-       _ASSERT(fwProfile != NULL);
-       _ASSERT(fwProcessImageFileName != NULL);
-       _ASSERT(fwAppEnabled != NULL);
-
-    *fwAppEnabled = FALSE;
-
-       // Get the list of authorized applications
-
-       err = fwProfile->get_AuthorizedApplications(&fwApps);
-       require(SUCCEEDED(err) && ( fwApps != NULL ), exit);
-
-    fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
-       require_action( ( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
-
-       // Look for us
-
-    err = fwApps->Item(fwBstrProcessImageFileName, &fwApp);
-       
-    if (SUCCEEDED(err) && ( fwApp != NULL ) )
-    {
-        // It's listed, but is it enabled?
-
-               err = fwApp->get_Enabled(&fwEnabled);
-               require(SUCCEEDED(err), exit);
-
-        if (fwEnabled != VARIANT_FALSE)
-        {
-                       // Yes, it's enabled
-
-            *fwAppEnabled = TRUE;
-               }
-       }
-
-       err = kNoErr;
-
-exit:
-
-       // Deallocate the BSTR
-
-       if ( fwBstrProcessImageFileName != NULL )
-       {
-               SysFreeString(fwBstrProcessImageFileName);
-       }
-
-       // Release the COM objects
-
-    if (fwApp != NULL)
-    {
-        fwApp->Release();
-    }
-
-    if (fwApps != NULL)
-    {
-        fwApps->Release();
-    }
-
-    return err;
-}
-
-
-static OSStatus
-mDNSFirewallAddApp
-                       (
-            IN INetFwProfile   *       fwProfile,
-            IN const wchar_t   *       fwProcessImageFileName,
-            IN const wchar_t   *       fwName
-            )
-{
-       BOOL                                                    fwAppEnabled;
-       BSTR                                                    fwBstrName = NULL;
-       BSTR                                                    fwBstrProcessImageFileName = NULL;
-       INetFwAuthorizedApplication     *       fwApp = NULL;
-       INetFwAuthorizedApplications*   fwApps = NULL;
-       OSStatus                                                err = S_OK;
-    
-       _ASSERT(fwProfile != NULL);
-    _ASSERT(fwProcessImageFileName != NULL);
-    _ASSERT(fwName != NULL);
-
-    // First check to see if the application is already authorized.
-       err = mDNSFirewallAppIsEnabled( fwProfile, fwProcessImageFileName, &fwAppEnabled );
-       require_noerr(err, exit);
-
-       // Only add the application if it isn't enabled
-
-       if (!fwAppEnabled)
-       {
-               // Get the list of authorized applications
-
-        err = fwProfile->get_AuthorizedApplications(&fwApps);
-               require(SUCCEEDED(err) && ( fwApps != NULL ), exit);
-
-        // Create an instance of an authorized application.
-
-               err = CoCreateInstance( __uuidof(NetFwAuthorizedApplication), NULL, CLSCTX_INPROC_SERVER, __uuidof(INetFwAuthorizedApplication), (void**)&fwApp );
-               require(SUCCEEDED(err) && ( fwApp != NULL ), exit);
-
-        fwBstrProcessImageFileName = SysAllocString(fwProcessImageFileName);
-               require_action(( fwProcessImageFileName != NULL ) && ( SysStringLen(fwBstrProcessImageFileName) > 0 ), exit, err = kNoMemoryErr);
-
-               // Set the executable file name
-
-               err = fwApp->put_ProcessImageFileName(fwBstrProcessImageFileName);
-               require(SUCCEEDED(err), exit);
-
-               fwBstrName = SysAllocString(fwName);
-               require_action( ( fwBstrName != NULL ) && ( SysStringLen(fwBstrName) > 0 ), exit, err = kNoMemoryErr);
-
-               // Set the friendly name
-
-        err = fwApp->put_Name(fwBstrName);
-               require(SUCCEEDED(err), exit);
-
-               // Now add the application
-
-        err = fwApps->Add(fwApp);
-               require(SUCCEEDED(err), exit);
-       }
-
-       err = kNoErr;
-
-exit:
-
-       // Deallocate the BSTR objects
-
-       if ( fwBstrName != NULL )
-       {
-               SysFreeString(fwBstrName);
-       }
-
-       if ( fwBstrProcessImageFileName != NULL )
-       {
-               SysFreeString(fwBstrProcessImageFileName);
-       }
-
-    // Release the COM objects
-
-    if (fwApp != NULL)
-    {
-        fwApp->Release();
-    }
-
-    if (fwApps != NULL)
-    {
-        fwApps->Release();
-    }
-
-    return err;
-}
-
-
-
-
-
-static OSStatus
-
-mDNSFirewallIsFileAndPrintSharingEnabled
-
-       (
-
-       IN INetFwProfile        * fwProfile,
-
-       OUT BOOL                        * fwServiceEnabled
-
-       )
-
-{
-
-    VARIANT_BOOL fwEnabled;
-
-    INetFwService* fwService = NULL;
-
-    INetFwServices* fwServices = NULL;
-
-       OSStatus err = S_OK;
-
-
-
-    _ASSERT(fwProfile != NULL);
-
-    _ASSERT(fwServiceEnabled != NULL);
-
-
-
-    *fwServiceEnabled = FALSE;
-
-
-
-    // Retrieve the globally open ports collection.
-
-    err = fwProfile->get_Services(&fwServices);
-
-       require( SUCCEEDED( err ), exit );
-
-
-
-    // Attempt to retrieve the globally open port.
-
-    err = fwServices->Item(NET_FW_SERVICE_FILE_AND_PRINT, &fwService);
-
-       require( SUCCEEDED( err ), exit );
-
-       
-
-       // Find out if the globally open port is enabled.
-
-    err = fwService->get_Enabled(&fwEnabled);
-
-       require( SUCCEEDED( err ), exit );
-
-       if (fwEnabled != VARIANT_FALSE)
-
-       {
-
-               *fwServiceEnabled = TRUE;
-
-       }
-
-
-
-exit:
-
-
-
-    // Release the globally open port.
-
-    if (fwService != NULL)
-
-    {
-
-        fwService->Release();
-
-    }
-
-
-
-    // Release the globally open ports collection.
-
-    if (fwServices != NULL)
-
-    {
-
-        fwServices->Release();
-
-    }
-
-
-
-    return err;
-
-}
-
-
-OSStatus
-mDNSAddToFirewall
-               (
-               LPWSTR  executable,
-               LPWSTR  name
-               )
-{
-       INetFwProfile   *       fwProfile       = NULL;
-       HRESULT                         comInit         = E_FAIL;
-       OSStatus                        err                     = kNoErr;
-
-       // Initialize COM.
-
-       comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
-
-       // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
-       // initialized with a different mode.
-
-       if (comInit != RPC_E_CHANGED_MODE)
-       {
-               err = comInit;
-               require(SUCCEEDED(err), exit);
-       }
-
-       // Connect to the firewall
-
-       err = mDNSFirewallInitialize(&fwProfile);
-       require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit);
-
-       // Add us to the list of exempt programs
-
-       err = mDNSFirewallAddApp( fwProfile, executable, name );
-       require_noerr(err, exit);
-
-exit:
-
-       // Disconnect from the firewall
-
-       if ( fwProfile != NULL )
-       {
-               mDNSFirewallCleanup(fwProfile);
-       }
-
-       // De-initialize COM
-
-       if (SUCCEEDED(comInit))
-    {
-        CoUninitialize();
-    }
-
-       return err;
-}
-
-
-BOOL
-mDNSIsFileAndPrintSharingEnabled( BOOL * retry )
-{
-       INetFwProfile   *       fwProfile                                       = NULL;
-       HRESULT                         comInit                                         = E_FAIL;
-       BOOL                            enabled                                         = FALSE;
-       OSStatus                        err                                                     = kNoErr;
-
-       // Initialize COM.
-
-       *retry = FALSE;
-       comInit = CoInitializeEx( 0, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE );
-
-       // Ignore this case. RPC_E_CHANGED_MODE means that COM has already been
-       // initialized with a different mode.
-
-       if (comInit != RPC_E_CHANGED_MODE)
-       {
-               *retry = TRUE;
-               err = comInit;
-               require(SUCCEEDED(err), exit);
-       }
-
-       // Connect to the firewall
-
-       err = mDNSFirewallInitialize(&fwProfile);
-       require( SUCCEEDED( err ) && ( fwProfile != NULL ), exit);
-
-       err = mDNSFirewallIsFileAndPrintSharingEnabled( fwProfile, &enabled );
-       require_noerr( err, exit );
-
-exit:
-
-       // Disconnect from the firewall
-
-       if ( fwProfile != NULL )
-       {
-               mDNSFirewallCleanup(fwProfile);
-       }
-
-       // De-initialize COM
-
-       if (SUCCEEDED(comInit))
-    {
-        CoUninitialize();
-    }
-
-       return enabled;
-}
diff --git a/mDNSWindows/SystemService/Firewall.h b/mDNSWindows/SystemService/Firewall.h
deleted file mode 100755 (executable)
index 3d7d532..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-
-#ifndef _Firewall_h
-
-#define _Firewall_h
-
-
-
-
-
-#include "CommonServices.h"
-
-#include "DebugServices.h"
-
-
-
-
-
-#if defined(__cplusplus)
-
-extern "C"
-
-{
-
-#endif
-
-
-
-
-
-OSStatus
-
-mDNSAddToFirewall
-
-               (
-
-               LPWSTR  executable,
-
-               LPWSTR  name
-
-               );
-
-
-BOOL
-mDNSIsFileAndPrintSharingEnabled( BOOL * retry );
-
-
-
-
-
-#if defined(__cplusplus)
-
-}
-
-#endif
-
-
-
-
-
-#endif
-
diff --git a/mDNSWindows/SystemService/Prefix.h b/mDNSWindows/SystemService/Prefix.h
deleted file mode 100644 (file)
index 61381d0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __PREFIX__
-#define __PREFIX__
-
-#if( defined( _DEBUG ) )
-       #define DEBUG                                   1
-       #define MDNS_DEBUGMSGS                  1
-#else
-       #define DEBUG                                   0
-#endif
-
-#define        DNS_SD_CLIENT_ENABLED           0
-
-#endif // __PREFIX__
diff --git a/mDNSWindows/SystemService/Service.aps b/mDNSWindows/SystemService/Service.aps
deleted file mode 100644 (file)
index 41f2556..0000000
Binary files a/mDNSWindows/SystemService/Service.aps and /dev/null differ
diff --git a/mDNSWindows/SystemService/Service.c b/mDNSWindows/SystemService/Service.c
deleted file mode 100644 (file)
index 1dea5c7..0000000
+++ /dev/null
@@ -1,2616 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include       <stdio.h>
-#include       <stdlib.h>
-#include       <crtdbg.h>
-#include       <stdarg.h>
-#include       <stddef.h>
-
-#include       "Poll.h"
-#include       "CommonServices.h"
-#include       "DebugServices.h"
-#include       "RegNames.h"
-
-#include       "uds_daemon.h"
-#include       "GenLinkedList.h"
-#include       "Service.h"
-#include       "EventLog.h"
-
-#include       "Resource.h"
-
-#include       "mDNSEmbeddedAPI.h"
-#include       "uDNS.h"
-#include       "mDNSWin32.h"
-#include       "mDNSDebug.h"
-
-#include       "Firewall.h"
-
-#if( !TARGET_OS_WINDOWS_CE )
-       #include        <mswsock.h>
-       #include        <process.h>
-       #include        <ipExport.h>
-       #include        <ws2def.h>
-       #include        <ws2ipdef.h>
-       #include        <iphlpapi.h>
-       #include        <netioapi.h>
-       #include        <iptypes.h>
-       #include        <powrprof.h>
-#endif
-
-#ifndef HeapEnableTerminationOnCorruption
-#      define HeapEnableTerminationOnCorruption (HEAP_INFORMATION_CLASS)1
-#endif
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#define        DEBUG_NAME                                                      "[mDNSWin32] "
-#define kServiceFirewallName                           L"Bonjour"
-#define        kServiceDependencies                            TEXT("Tcpip\0\0")
-#define        kDNSServiceCacheEntryCountDefault       512
-#define kRetryFirewallPeriod                           30 * 1000
-#define kDefValueSize                                          MAX_PATH + 1
-#define kZeroIndex                                                     0
-#define kDefaultRouteMetric                                    399
-#define kSecondsTo100NSUnits                           ( 10 * 1000 * 1000 )
-#define kSPSMaintenanceWakePeriod                      -30
-#define kWaitToRetry                                           (60 * 5)
-
-#define RR_CACHE_SIZE 500
-static CacheEntity gRRCache[RR_CACHE_SIZE];
-#if 0
-#pragma mark == Structures ==
-#endif
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-static void                            Usage( void );
-static BOOL WINAPI             ConsoleControlHandler( DWORD inControlEvent );
-static OSStatus                        InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath );
-static OSStatus                        RemoveService( LPCTSTR inName );
-static OSStatus                        SetServiceParameters();
-static OSStatus                        GetServiceParameters();
-static OSStatus                        CheckFirewall();
-static OSStatus                        SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription );
-static void                            ReportStatus( int inType, const char *inFormat, ... );
-
-static void WINAPI             ServiceMain( DWORD argc, LPTSTR argv[] );
-static OSStatus                        ServiceSetupEventLogging( void );
-static DWORD WINAPI            ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext );
-
-static OSStatus                        ServiceRun( int argc, LPTSTR argv[] );
-static void                            ServiceStop( void );
-
-static OSStatus                        ServiceSpecificInitialize( int argc, LPTSTR  argv[] );
-static OSStatus                        ServiceSpecificRun( int argc, LPTSTR argv[] );
-static OSStatus                        ServiceSpecificStop( void );
-static void                            ServiceSpecificFinalize( int argc, LPTSTR argv[] );
-static mStatus                 SetupServiceEvents();
-static mStatus                 TearDownServiceEvents();
-static mStatus                 SetupNotifications();
-static mStatus                 TearDownNotifications();
-static void CALLBACK   StopNotification( HANDLE event, void * context );
-static void CALLBACK   PowerSuspendNotification( HANDLE event, void * context );
-static void    CALLBACK        PowerResumeNotification( HANDLE event, void * context );
-static void CALLBACK   InterfaceListNotification( SOCKET socket, LPWSANETWORKEVENTS event, void *context );
-static void CALLBACK   ComputerDescriptionNotification( HANDLE event, void *context );
-static void CALLBACK   TCPChangedNotification( HANDLE event, void *context );
-static void CALLBACK   DDNSChangedNotification( HANDLE event, void *context );
-static void CALLBACK   FileSharingChangedNotification( HANDLE event, void *context );
-static void CALLBACK   FirewallChangedNotification( HANDLE event, void *context );
-static void CALLBACK   AdvertisedServicesChangedNotification( HANDLE event, void *context );
-static void CALLBACK   SPSWakeupNotification( HANDLE event, void *context );
-static void    CALLBACK        SPSSleepNotification( HANDLE event, void *context );
-static void CALLBACK   UDSAcceptNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-static void CALLBACK   UDSReadNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-static void                            CoreCallback(mDNS * const inMDNS, mStatus result);
-static mDNSu8                  SystemWakeForNetworkAccess( LARGE_INTEGER * timeout );
-static OSStatus                        GetRouteDestination(DWORD * ifIndex, DWORD * address);
-static OSStatus                        SetLLRoute( mDNS * const inMDNS );
-static bool                            HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric );
-static bool                            IsValidAddress( const char * addr );
-static bool                            IsNortelVPN( IP_ADAPTER_INFO * pAdapter );
-static bool                            IsJuniperVPN( IP_ADAPTER_INFO * pAdapter );
-static bool                            IsCiscoVPN( IP_ADAPTER_INFO * pAdapter );
-static const char *            strnistr( const char * string, const char * subString, size_t max );
-
-#if defined(UNICODE)
-#      define StrLen(X)        wcslen(X)
-#      define StrCmp(X,Y)      wcscmp(X,Y)
-#else
-#      define StrLen(X)        strlen(X)
-#      define StrCmp(X,Y)      strcmp(X,Y)
-#endif
-
-
-#define kLLNetworkAddr      "169.254.0.0"
-#define kLLNetworkAddrMask  "255.255.0.0"
-
-
-#include       "mDNSEmbeddedAPI.h"
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-#define gMDNSRecord mDNSStorage
-DEBUG_LOCAL    mDNS_PlatformSupport            gPlatformStorage;
-DEBUG_LOCAL BOOL                                               gServiceQuietMode               = FALSE;
-DEBUG_LOCAL SERVICE_TABLE_ENTRY                        gServiceDispatchTable[] = 
-{
-       { kServiceName, ServiceMain }, 
-       { NULL,                 NULL }
-};
-DEBUG_LOCAL HANDLE                                             gStopEvent                                      = NULL;
-DEBUG_LOCAL HANDLE                                             gPowerSuspendEvent                      = NULL;
-DEBUG_LOCAL HANDLE                                             gPowerSuspendAckEvent           = NULL;
-DEBUG_LOCAL HANDLE                                             gPowerResumeEvent                       = NULL;
-DEBUG_LOCAL SOCKET                                             gInterfaceListChangedSocket     = INVALID_SOCKET;
-DEBUG_LOCAL HKEY                                               gDescKey                                        = NULL;
-DEBUG_LOCAL HANDLE                                             gDescChangedEvent                       = NULL; // Computer description changed event
-DEBUG_LOCAL HKEY                                               gTcpipKey                                       = NULL;
-DEBUG_LOCAL HANDLE                                             gTcpipChangedEvent                      = NULL; // TCP/IP config changed
-DEBUG_LOCAL HKEY                                               gDdnsKey                                        = NULL;
-DEBUG_LOCAL HANDLE                                             gDdnsChangedEvent                       = NULL; // DynDNS config changed
-DEBUG_LOCAL HKEY                                               gFileSharingKey                         = NULL;
-DEBUG_LOCAL HANDLE                                             gFileSharingChangedEvent        = NULL; // File Sharing changed
-DEBUG_LOCAL HKEY                                               gFirewallKey                            = NULL;
-DEBUG_LOCAL HANDLE                                             gFirewallChangedEvent           = NULL; // Firewall changed
-DEBUG_LOCAL HKEY                                               gAdvertisedServicesKey          = NULL;
-DEBUG_LOCAL HANDLE                                             gAdvertisedServicesChangedEvent = NULL; // Advertised services changed
-DEBUG_LOCAL SERVICE_STATUS                             gServiceStatus;
-DEBUG_LOCAL SERVICE_STATUS_HANDLE              gServiceStatusHandle    = NULL;
-DEBUG_LOCAL HANDLE                                             gServiceEventSource             = NULL;
-DEBUG_LOCAL bool                                               gServiceAllowRemote             = false;
-DEBUG_LOCAL int                                                        gServiceCacheEntryCount = 0;    // 0 means to use the DNS-SD default.
-DEBUG_LOCAL bool                                               gServiceManageLLRouting = true;
-DEBUG_LOCAL HANDLE                                             gSPSWakeupEvent                 = NULL;
-DEBUG_LOCAL HANDLE                                             gSPSSleepEvent                  = NULL;
-DEBUG_LOCAL SocketRef                                  gUDSSocket                              = 0;
-DEBUG_LOCAL udsEventCallback                   gUDSCallback                    = NULL;
-DEBUG_LOCAL BOOL                                               gRetryFirewall                  = FALSE;
-
-typedef DWORD ( WINAPI * GetIpInterfaceEntryFunctionPtr )( PMIB_IPINTERFACE_ROW );
-mDNSlocal HMODULE                                                              gIPHelperLibraryInstance                = NULL;
-mDNSlocal GetIpInterfaceEntryFunctionPtr               gGetIpInterfaceEntryFunctionPtr = NULL;
-
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     Main
-//===========================================================================================================================
-int    Main( int argc, LPTSTR argv[] )
-{
-       OSStatus                err;
-       BOOL                    ok;
-       BOOL                    start;
-       int                             i;
-
-       HeapSetInformation( NULL, HeapEnableTerminationOnCorruption, NULL, 0 );
-
-       debug_initialize( kDebugOutputTypeMetaConsole );
-       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelVerbose );
-
-       // Default to automatically starting the service dispatcher if no extra arguments are specified.
-       
-       start = ( argc <= 1 );
-       
-       // Parse arguments.
-       
-       for( i = 1; i < argc; ++i )
-       {
-               if( StrCmp( argv[ i ], TEXT("-install") ) == 0 )                        // Install
-               {
-                       TCHAR desc[ 256 ];
-                       
-                       desc[ 0 ] = 0;
-                       LoadString( GetModuleHandle( NULL ), IDS_SERVICE_DESCRIPTION, desc, sizeof( desc ) );
-                       err = InstallService( kServiceName, kServiceName, desc, argv[0] );
-                       if( err )
-                       {
-                               ReportStatus( EVENTLOG_ERROR_TYPE, "install service failed (%d)\n", err );
-                               goto exit;
-                       }
-               }
-               else if( StrCmp( argv[ i ], TEXT("-remove") ) == 0 )            // Remove
-               {
-                       err = RemoveService( kServiceName );
-                       if( err )
-                       {
-                               ReportStatus( EVENTLOG_ERROR_TYPE, "remove service failed (%d)\n", err );
-                               goto exit;
-                       }
-               }
-               else if( StrCmp( argv[ i ], TEXT("-start") ) == 0 )             // Start
-               {
-                       start = TRUE;
-               }
-               else if( StrCmp( argv[ i ], TEXT("-server") ) == 0 )            // Server
-               {
-                       err = RunDirect( argc, argv );
-                       if( err )
-                       {
-                               ReportStatus( EVENTLOG_ERROR_TYPE, "run service directly failed (%d)\n", err );
-                       }
-                       goto exit;
-               }
-               else if( StrCmp( argv[ i ], TEXT("-q") ) == 0 )                 // Quiet Mode (toggle)
-               {
-                       gServiceQuietMode = !gServiceQuietMode;
-               }
-               else if( ( StrCmp( argv[ i ], TEXT("-help") ) == 0 ) ||         // Help
-                                ( StrCmp( argv[ i ], TEXT("-h") ) == 0 ) )
-               {
-                       Usage();
-                       err = 0;
-                       break;
-               }
-               else
-               {
-                       Usage();
-                       err = kParamErr;
-                       break;
-               }
-       }
-       
-       // Start the service dispatcher if requested. This does not return until all services have terminated. If any 
-       // global initialization is needed, it should be done before starting the service dispatcher, but only if it 
-       // will take less than 30 seconds. Otherwise, use a separate thread for it and start the dispatcher immediately.
-       
-       if( start )
-       {
-               ok = StartServiceCtrlDispatcher( gServiceDispatchTable );
-               err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
-               if( err != kNoErr )
-               {
-                       ReportStatus( EVENTLOG_ERROR_TYPE, "start service dispatcher failed (%d)\n", err );
-                       goto exit;
-               }
-       }
-       err = 0;
-       
-exit:
-       dlog( kDebugLevelTrace, DEBUG_NAME "exited (%d %m)\n", err, err );
-       _CrtDumpMemoryLeaks();
-       return( (int) err );
-}
-
-//===========================================================================================================================
-//     Usage
-//===========================================================================================================================
-
-static void    Usage( void )
-{
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "mDNSResponder 1.0d1\n" );
-       fprintf( stderr, "\n" );
-       fprintf( stderr, "    <no args>    Runs the service normally\n" );
-       fprintf( stderr, "    -install     Creates the service and starts it\n" );
-       fprintf( stderr, "    -remove      Stops the service and deletes it\n" );
-       fprintf( stderr, "    -start       Starts the service dispatcher after processing all other arguments\n" );
-       fprintf( stderr, "    -server      Runs the service directly as a server (for debugging)\n" );
-       fprintf( stderr, "    -q           Toggles Quiet Mode (no events or output)\n" );
-       fprintf( stderr, "    -remote      Allow remote connections\n" );
-       fprintf( stderr, "    -cache n     Number of mDNS cache entries (defaults to %d)\n", kDNSServiceCacheEntryCountDefault );
-       fprintf( stderr, "    -h[elp]      Display Help/Usage\n" );
-       fprintf( stderr, "\n" );
-}
-
-//===========================================================================================================================
-//     ConsoleControlHandler
-//===========================================================================================================================
-
-static BOOL WINAPI     ConsoleControlHandler( DWORD inControlEvent )
-{
-       BOOL                    handled;
-       OSStatus                err;
-       
-       handled = FALSE;
-       switch( inControlEvent )
-       {
-               case CTRL_C_EVENT:
-               case CTRL_BREAK_EVENT:
-               case CTRL_CLOSE_EVENT:
-               case CTRL_LOGOFF_EVENT:
-               case CTRL_SHUTDOWN_EVENT:
-                       err = ServiceSpecificStop();
-                       require_noerr( err, exit );
-                       
-                       handled = TRUE;
-                       break;
-               
-               default:
-                       break;
-       }
-       
-exit:
-       return( handled );
-}
-
-//===========================================================================================================================
-//     InstallService
-//===========================================================================================================================
-
-static OSStatus        InstallService( LPCTSTR inName, LPCTSTR inDisplayName, LPCTSTR inDescription, LPCTSTR inPath )
-{
-       OSStatus                err;
-       SC_HANDLE               scm;
-       SC_HANDLE               service;
-       BOOL                    ok;
-       TCHAR                   fullPath[ MAX_PATH ];
-       TCHAR *                 namePtr;
-       DWORD                   size;
-       
-       scm             = NULL;
-       service = NULL;
-       
-       // Get a full path to the executable since a relative path may have been specified.
-       
-       size = GetFullPathName( inPath, MAX_PATH, fullPath, &namePtr );
-       err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
-       require_noerr( err, exit );
-       
-       // Create the service and start it.
-       
-       scm = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
-       err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
-       require_noerr( err, exit );
-       
-       service = CreateService( scm, inName, inDisplayName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS, 
-                                                        SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, NULL, NULL, kServiceDependencies, 
-                                                        NULL, NULL );
-       err = translate_errno( service, (OSStatus) GetLastError(), kDuplicateErr );
-       require_noerr( err, exit );
-
-       err = SetServiceParameters();
-       check_noerr( err );
-       
-       if( inDescription )
-       {
-               err = SetServiceInfo( scm, inName, inDescription );
-               check_noerr( err );
-       }
-
-       ok = StartService( service, 0, NULL );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kInUseErr );
-       require_noerr( err, exit );
-       
-       ReportStatus( EVENTLOG_SUCCESS, "installed service\n" );
-       err = kNoErr;
-       
-exit:
-       if( service )
-       {
-               CloseServiceHandle( service );
-       }
-       if( scm )
-       {
-               CloseServiceHandle( scm );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     RemoveService
-//===========================================================================================================================
-
-static OSStatus        RemoveService( LPCTSTR inName )
-{
-       OSStatus                        err;
-       SC_HANDLE                       scm;
-       SC_HANDLE                       service;
-       BOOL                            ok;
-       SERVICE_STATUS          status;
-       
-       scm             = NULL;
-       service = NULL;
-       
-       // Open a connection to the service.
-       
-       scm = OpenSCManager( 0, 0, SC_MANAGER_ALL_ACCESS );
-       err = translate_errno( scm, (OSStatus) GetLastError(), kOpenErr );
-       require_noerr( err, exit );
-       
-       service = OpenService( scm, inName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE );
-       err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
-       require_noerr( err, exit );
-       
-       // Stop the service, if it is not already stopped, then delete it.
-       
-       ok = QueryServiceStatus( service, &status );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
-       require_noerr( err, exit );
-       
-       if( status.dwCurrentState != SERVICE_STOPPED )
-       {
-               ok = ControlService( service, SERVICE_CONTROL_STOP, &status );
-               check_translated_errno( ok, (OSStatus) GetLastError(), kAuthenticationErr );
-       }
-       
-       ok = DeleteService( service );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kDeletedErr );
-       require_noerr( err, exit );
-               
-       ReportStatus( EVENTLOG_SUCCESS, "Removed service\n" );
-       err = ERROR_SUCCESS;
-       
-exit:
-       if( service )
-       {
-               CloseServiceHandle( service );
-       }
-       if( scm )
-       {
-               CloseServiceHandle( scm );
-       }
-       return( err );
-}
-
-
-
-//===========================================================================================================================
-//     SetServiceParameters
-//===========================================================================================================================
-
-static OSStatus SetServiceParameters()
-{
-       DWORD                   value;
-       DWORD                   valueLen = sizeof(DWORD);
-       DWORD                   type;
-       OSStatus                err;
-       HKEY                    key;
-
-       key = NULL;
-
-       //
-       // Add/Open Parameters section under service entry in registry
-       //
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
-       require_noerr( err, exit );
-       
-       //
-       // If the value isn't already there, then we create it
-       //
-       err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
-
-       if (err != ERROR_SUCCESS)
-       {
-               value = 1;
-
-               err = RegSetValueEx( key, kServiceManageLLRouting, 0, REG_DWORD, (const LPBYTE) &value, sizeof(DWORD) );
-               require_noerr( err, exit );
-       }
-
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       return( err );
-}
-
-
-
-//===========================================================================================================================
-//     GetServiceParameters
-//===========================================================================================================================
-
-static OSStatus GetServiceParameters()
-{
-       DWORD                   value;
-       DWORD                   valueLen;
-       DWORD                   type;
-       OSStatus                err;
-       HKEY                    key;
-
-       key = NULL;
-
-       //
-       // Add/Open Parameters section under service entry in registry
-       //
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
-       require_noerr( err, exit );
-       
-       valueLen = sizeof(DWORD);
-       err = RegQueryValueEx(key, kServiceManageLLRouting, 0, &type, (LPBYTE) &value, &valueLen);
-       if (err == ERROR_SUCCESS)
-       {
-               gServiceManageLLRouting = (value) ? true : false;
-       }
-
-       valueLen = sizeof(DWORD);
-       err = RegQueryValueEx(key, kServiceCacheEntryCount, 0, &type, (LPBYTE) &value, &valueLen);
-       if (err == ERROR_SUCCESS)
-       {
-               gServiceCacheEntryCount = value;
-       }
-
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       return( err );
-}
-
-
-//===========================================================================================================================
-//     CheckFirewall
-//===========================================================================================================================
-
-static OSStatus CheckFirewall()
-{
-       DWORD                                   value;
-       DWORD                                   valueLen;
-       DWORD                                   type;
-       ENUM_SERVICE_STATUS     *       lpService = NULL;
-       SC_HANDLE                               sc = NULL;
-       HKEY                                    key = NULL;
-       BOOL                                    ok;
-       DWORD                                   bytesNeeded = 0;
-       DWORD                                   srvCount;
-       DWORD                                   resumeHandle = 0;
-       DWORD                                   srvType;
-       DWORD                                   srvState;
-       DWORD                                   dwBytes = 0;
-       DWORD                                   i;
-       BOOL                                    isRunning = FALSE;
-       OSStatus                                err = kUnknownErr;
-       
-       // Check to see if the firewall service is running.  If it isn't, then
-       // we want to return immediately
-
-       sc = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
-       err = translate_errno( sc, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       srvType         =       SERVICE_WIN32;
-       srvState        =       SERVICE_STATE_ALL;
-
-       for ( ;; )
-       {
-               // Call EnumServicesStatus using the handle returned by OpenSCManager
-
-               ok = EnumServicesStatus ( sc, srvType, srvState, lpService, dwBytes, &bytesNeeded, &srvCount, &resumeHandle );
-
-               if ( ok || ( GetLastError() != ERROR_MORE_DATA ) )
-               {
-                       break;
-               }
-
-               if ( lpService )
-               {
-                       free( lpService );
-               }
-
-               dwBytes = bytesNeeded;
-
-               lpService = ( ENUM_SERVICE_STATUS* ) malloc( dwBytes );
-               require_action( lpService, exit, err = mStatus_NoMemoryErr );
-       }
-
-       err = translate_errno( ok, GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       for ( i = 0; i < srvCount; i++ )
-       {
-               if ( wcscmp( lpService[i].lpServiceName, L"SharedAccess" ) == 0 )
-               {
-                       if ( lpService[i].ServiceStatus.dwCurrentState == SERVICE_RUNNING )
-                       {
-                               isRunning = TRUE;
-                       }
-
-                       break;
-               }
-       }
-
-       require_action( isRunning, exit, err = kUnknownErr );
-
-       // Check to see if we've managed the firewall.
-       // This package might have been installed, then
-       // the OS was upgraded to SP2 or above.  If that's
-       // the case, then we need to manipulate the firewall
-       // so networking works correctly.
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode, &key );
-       require_noerr( err, exit );
-
-       valueLen = sizeof(DWORD);
-       err = RegQueryValueEx(key, kServiceManageFirewall, 0, &type, (LPBYTE) &value, &valueLen);
-       
-       if ((err != ERROR_SUCCESS) || (value == 0))
-       {
-               wchar_t fullPath[ MAX_PATH ];
-               DWORD   size;
-
-               // Get a full path to the executable
-
-               size = GetModuleFileNameW( NULL, fullPath, MAX_PATH );
-               err = translate_errno( size > 0, (OSStatus) GetLastError(), kPathErr );
-               require_noerr( err, exit );
-
-               err = mDNSAddToFirewall(fullPath, kServiceFirewallName);
-               require_noerr( err, exit );
-
-               value = 1;
-               err = RegSetValueEx( key, kServiceManageFirewall, 0, REG_DWORD, (const LPBYTE) &value, sizeof( DWORD ) );
-               require_noerr( err, exit );
-       }
-       
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-       
-       if ( lpService )
-       {
-               free( lpService );
-       }
-
-       if ( sc )
-       {
-               CloseServiceHandle ( sc );
-       }
-
-       return( err );
-}
-
-
-
-//===========================================================================================================================
-//     SetServiceInfo
-//===========================================================================================================================
-
-static OSStatus        SetServiceInfo( SC_HANDLE inSCM, LPCTSTR inServiceName, LPCTSTR inDescription )
-{
-       OSStatus                                err;
-       SC_LOCK                                 lock;
-       SC_HANDLE                               service;
-       SERVICE_DESCRIPTION             description;
-       SERVICE_FAILURE_ACTIONS actions;
-       SC_ACTION                               action;
-       BOOL                                    ok;
-       
-       check( inServiceName );
-       check( inDescription );
-       
-       lock    = NULL;
-       service = NULL;
-       
-       // Open the database (if not provided) and lock it to prevent other access while re-configuring.
-       
-       if( !inSCM )
-       {
-               inSCM = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS );
-               err = translate_errno( inSCM, (OSStatus) GetLastError(), kOpenErr );
-               require_noerr( err, exit );
-       }
-       
-       lock = LockServiceDatabase( inSCM );
-       err = translate_errno( lock, (OSStatus) GetLastError(), kInUseErr );
-       require_noerr( err, exit );
-       
-       // Open a handle to the service. 
-
-       service = OpenService( inSCM, inServiceName, SERVICE_CHANGE_CONFIG|SERVICE_START );
-       err = translate_errno( service, (OSStatus) GetLastError(), kNotFoundErr );
-       require_noerr( err, exit );
-       
-       // Change the description.
-       
-       description.lpDescription = (LPTSTR) inDescription;
-       ok = ChangeServiceConfig2( service, SERVICE_CONFIG_DESCRIPTION, &description );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
-       require_noerr( err, exit );
-       
-       actions.dwResetPeriod   =       INFINITE;
-       actions.lpRebootMsg             =       NULL;
-       actions.lpCommand               =       NULL;
-       actions.cActions                =       1;
-       actions.lpsaActions             =       &action;
-       action.Delay                    =       500;
-       action.Type                             =       SC_ACTION_RESTART;
-
-       ok = ChangeServiceConfig2( service, SERVICE_CONFIG_FAILURE_ACTIONS, &actions );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kParamErr );
-       require_noerr( err, exit );
-       
-       err = ERROR_SUCCESS;
-       
-exit:
-       // Close the service and release the lock.
-       
-       if( service )
-       {
-               CloseServiceHandle( service );
-       }
-       if( lock )
-       {
-               UnlockServiceDatabase( lock ); 
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     ReportStatus
-//===========================================================================================================================
-
-static void    ReportStatus( int inType, const char *inFormat, ... )
-{
-       if( !gServiceQuietMode )
-       {
-               va_list         args;
-               
-               va_start( args, inFormat );
-               if( gServiceEventSource )
-               {
-                       char                            s[ 1024 ];
-                       BOOL                            ok;
-                       const char *            array[ 1 ];
-                       
-                       vsnprintf( s, sizeof( s ), inFormat, args );
-                       array[ 0 ] = s;
-                       ok = ReportEventA( gServiceEventSource, (WORD) inType, 0, MDNSRESPONDER_LOG, NULL, 1, 0, array, NULL );
-                       check_translated_errno( ok, GetLastError(), kUnknownErr );
-               }
-               else
-               {
-                       int             n;
-                       
-                       n = vfprintf( stderr, inFormat, args );
-                       check( n >= 0 );
-               }
-               va_end( args );
-       }
-}
-
-//===========================================================================================================================
-//     RunDirect
-//===========================================================================================================================
-
-int    RunDirect( int argc, LPTSTR argv[] )
-{
-       OSStatus                err;
-       BOOL                    initialized;
-   BOOL        ok;
-       
-       initialized = FALSE;
-
-       err = SetupServiceEvents();
-       require_noerr( err, exit );
-
-       // Install a Console Control Handler to handle things like control-c signals.
-       
-       ok = SetConsoleCtrlHandler( ConsoleControlHandler, TRUE );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       err = ServiceSpecificInitialize( argc, argv );
-       require_noerr( err, exit );
-       initialized = TRUE;
-       
-       // Run the service. This does not return until the service quits or is stopped.
-       
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Running service directly\n" );
-       
-       err = ServiceSpecificRun( argc, argv );
-       require_noerr( err, exit );
-       
-       // Clean up.
-       
-exit:
-       if( initialized )
-       {
-               ServiceSpecificFinalize( argc, argv );
-       }
-
-       TearDownServiceEvents();
-
-       return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     ServiceMain
-//===========================================================================================================================
-
-static void WINAPI ServiceMain( DWORD argc, LPTSTR argv[] )
-{
-       OSStatus                err;
-       BOOL                    ok;
-
-       err = SetupServiceEvents();
-       require_noerr( err, exit );
-       
-       err = ServiceSetupEventLogging();
-       check_noerr( err );
-
-       err = GetServiceParameters();
-       check_noerr( err );
-       
-       // Initialize the service status and register the service control handler with the name of the service.
-       
-       gServiceStatus.dwServiceType                            = SERVICE_WIN32_SHARE_PROCESS;
-       gServiceStatus.dwCurrentState                           = 0;
-       gServiceStatus.dwControlsAccepted                       = SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN|SERVICE_ACCEPT_POWEREVENT;
-       gServiceStatus.dwWin32ExitCode                          = NO_ERROR;
-       gServiceStatus.dwServiceSpecificExitCode        = NO_ERROR;
-       gServiceStatus.dwCheckPoint                             = 0;
-       gServiceStatus.dwWaitHint                                       = 0;
-       
-       gServiceStatusHandle = RegisterServiceCtrlHandlerEx( argv[ 0 ], ServiceControlHandler, NULL );
-       err = translate_errno( gServiceStatusHandle, (OSStatus) GetLastError(), kInUseErr );
-       require_noerr( err, exit );
-       
-       // Mark the service as starting.
-
-       gServiceStatus.dwCurrentState   = SERVICE_START_PENDING;
-       gServiceStatus.dwCheckPoint             = 0;
-       gServiceStatus.dwWaitHint               = 5000; // 5 seconds
-       ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
-       check_translated_errno( ok, GetLastError(), kParamErr );
-       
-       // Run the service. This does not return until the service quits or is stopped.
-       
-       err = ServiceRun( (int) argc, argv );
-       if( err != kNoErr )
-       {
-               gServiceStatus.dwWin32ExitCode                          = ERROR_SERVICE_SPECIFIC_ERROR;
-               gServiceStatus.dwServiceSpecificExitCode        = (DWORD) err;
-       }
-       
-       // Service-specific work is done so mark the service as stopped.
-       
-       gServiceStatus.dwCurrentState = SERVICE_STOPPED;
-       ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
-       check_translated_errno( ok, GetLastError(), kParamErr );
-       
-       // Note: The service status handle should not be closed according to Microsoft documentation.
-       
-exit:
-
-       if( gServiceEventSource )
-       {
-               ok = DeregisterEventSource( gServiceEventSource );
-               check_translated_errno( ok, GetLastError(), kUnknownErr );
-               gServiceEventSource = NULL;
-       }
-
-       TearDownServiceEvents();
-}
-
-//===========================================================================================================================
-//     ServiceSetupEventLogging
-//===========================================================================================================================
-
-static OSStatus        ServiceSetupEventLogging( void )
-{
-       OSStatus                        err;
-       HKEY                            key;
-       LPCTSTR                         s;
-       DWORD                           typesSupported;
-       TCHAR                           path[ MAX_PATH ];
-       DWORD                           n;
-       
-       key = NULL;
-       
-       // Add/Open source name as a sub-key under the Application key in the EventLog registry key.
-
-       s = TEXT("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\") kServiceName;
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, s, &key );
-       require_noerr( err, exit );
-       
-       // Add the name to the EventMessageFile subkey.
-
-       path[ 0 ] = '\0';
-       GetModuleFileName( NULL, path, MAX_PATH );
-       n = (DWORD) ( ( StrLen( path ) + 1 ) * sizeof( TCHAR ) );
-       err = RegSetValueEx( key, TEXT("EventMessageFile"), 0, REG_EXPAND_SZ, (const LPBYTE) path, n );
-       require_noerr( err, exit );
-       
-       // Set the supported event types in the TypesSupported subkey.
-       
-       typesSupported = 0 
-                                        | 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( err, exit );
-       
-       // Set up the event source.
-       
-       gServiceEventSource = RegisterEventSource( NULL, kServiceName );
-       err = translate_errno( gServiceEventSource, (OSStatus) GetLastError(), kParamErr );
-       require_noerr( err, exit );
-               
-exit:
-       if( key )
-       {
-               RegCloseKey( key );
-       }
-       return( err );
-}
-
-
-//===========================================================================================================================
-//     ServiceControlHandler
-//===========================================================================================================================
-
-static DWORD WINAPI    ServiceControlHandler( DWORD inControl, DWORD inEventType, LPVOID inEventData, LPVOID inContext )
-{
-       BOOL            setStatus;
-       OSStatus        err;
-       BOOL            ok;
-
-       DEBUG_UNUSED( inEventData );
-       DEBUG_UNUSED( inContext );
-       
-       setStatus = TRUE;
-       switch( inControl )
-       {
-               case SERVICE_CONTROL_STOP:
-               case SERVICE_CONTROL_SHUTDOWN:
-                       
-                       dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: SERVICE_CONTROL_STOP|SERVICE_CONTROL_SHUTDOWN\n" );
-                       
-                       ServiceStop();
-                       setStatus = FALSE;
-                       break;
-               
-               case SERVICE_CONTROL_POWEREVENT:
-
-                       if (inEventType == PBT_APMSUSPEND)
-                       {
-                               dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMSUSPEND\n" );
-
-                               if ( gPowerSuspendEvent )
-                               {
-                                       ok = SetEvent( gPowerSuspendEvent );
-                                       err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-                                       check_noerr( err );
-
-                                       switch ( WaitForSingleObject( gPowerSuspendAckEvent, 5 * 1000 ) )
-                                       {
-                                               case WAIT_OBJECT_0:
-                                               {
-                                                       // No error
-                                               }
-                                               break;
-
-                                               case WAIT_TIMEOUT:
-                                               {
-                                                       dlog( kDebugLevelError, DEBUG_NAME "Timed out waiting for acknowledgement of machine sleep\n" );
-                                                       ReportStatus( EVENTLOG_ERROR_TYPE, "Timed out waiting for acknowledgement of machine sleep" );
-                                               }
-                                               break;
-
-                                               default:
-                                               {
-                                                       dlog( kDebugLevelError, DEBUG_NAME "Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
-                                                       ReportStatus( EVENTLOG_ERROR_TYPE, "Error waiting for acknowledgement of machine sleep: %d", GetLastError() );
-                                               }
-                                               break;
-                                       }
-                               }
-                       }
-                       else if (inEventType == PBT_APMRESUMESUSPEND)
-                       {
-                               dlog( kDebugLevelInfo, DEBUG_NAME "ServiceControlHandler: PBT_APMRESUMESUSPEND\n" );
-
-                               if ( gPowerResumeEvent )
-                               {
-                                       ok = SetEvent( gPowerResumeEvent );
-                                       err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-                                       check_noerr( err );
-                               }
-                       }
-               
-                       break;
-
-               default:
-                       dlog( kDebugLevelNotice, DEBUG_NAME "ServiceControlHandler: event (0x%08X)\n", inControl );
-                       break;
-       }
-       
-       if( setStatus && gServiceStatusHandle )
-       {
-               ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
-               check_translated_errno( ok, GetLastError(), kUnknownErr );
-       }
-
-       return NO_ERROR;
-}
-
-//===========================================================================================================================
-//     ServiceRun
-//===========================================================================================================================
-
-static OSStatus        ServiceRun( int argc, LPTSTR argv[] )
-{
-       OSStatus                err;
-       BOOL                    initialized;
-       BOOL                    ok;
-       
-       DEBUG_UNUSED( argc );
-       DEBUG_UNUSED( argv );
-       
-       initialized = FALSE;
-       
-       // <rdar://problem/5727548> Make the service as running before we call ServiceSpecificInitialize. We've
-       // had reports that some machines with McAfee firewall installed cause a problem with iTunes installation.
-       // We think that the firewall product is interferring with code in ServiceSpecificInitialize. So as a
-       // simple workaround, we'll mark us as running *before* we call ServiceSpecificInitialize. This will unblock
-       // any installers that are waiting for our state to change.
-
-       gServiceStatus.dwCurrentState = SERVICE_RUNNING;
-       ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
-       check_translated_errno( ok, GetLastError(), kParamErr );
-
-       // Initialize the service-specific stuff
-       
-       while ( 1 )
-       {
-               DWORD ret;
-
-               ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initializing" );
-
-               err = ServiceSpecificInitialize( argc, argv );
-
-               if ( !err )
-               {
-                       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initialized" );
-                       break;
-               }
-
-               ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service initialization failed with err %d. Waiting %d seconds to retry...", err, kWaitToRetry );
-
-               ret = WaitForSingleObject( gStopEvent, 1000 * kWaitToRetry );
-
-               if ( ret == WAIT_OBJECT_0 )
-               {
-                       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a stop event" );
-                       goto exit;
-               }
-               else if ( ret == WAIT_OBJECT_0 + 1 )
-               {
-                       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a power suspend event" );
-               }
-               else if ( ret == WAIT_OBJECT_0 + 2 )
-               {
-                       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received a power resume event" );
-               }
-               else if ( ret != WAIT_TIMEOUT )
-               {
-                       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service received an error in WaitForSingleObject() : %d, %d", ret, GetLastError() );
-                       goto exit;
-               }
-       }
-
-       initialized = TRUE;
-       
-       err = CheckFirewall();
-       check_noerr( err );
-
-       if ( err )
-       {
-               gRetryFirewall = TRUE;
-       }
-       
-       // Run the service-specific stuff. This does not return until the service quits or is stopped.
-
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service started\n" );
-
-       err = ServiceSpecificRun( argc, argv );
-       require_noerr( err, exit );
-
-exit:
-
-       // Service stopped. Clean up and we're done.
-       
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Service stopped (%d)\n", err );
-       
-       if( initialized )
-       {
-               ServiceSpecificFinalize( argc, argv );
-       }
-       
-       return( err );
-}
-
-//===========================================================================================================================
-//     ServiceStop
-//===========================================================================================================================
-
-static void    ServiceStop( void )
-{
-       BOOL                    ok;
-       OSStatus                err;
-       
-       // Signal the event to cause the service to exit.
-       
-       if( gServiceStatusHandle )
-       {
-               gServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
-               ok = SetServiceStatus( gServiceStatusHandle, &gServiceStatus );
-               check_translated_errno( ok, GetLastError(), kParamErr );
-       }
-               
-       err = ServiceSpecificStop();
-       check_noerr( err );
-}
-
-
-#if 0
-#pragma mark -
-#pragma mark == Service Specific ==
-#endif
-
-//===========================================================================================================================
-//     ServiceSpecificInitialize
-//===========================================================================================================================
-
-static OSStatus        ServiceSpecificInitialize( int argc, LPTSTR argv[] )
-{
-       OSStatus err;
-       
-       DEBUG_UNUSED( argc );
-       DEBUG_UNUSED( argv );
-       
-       mDNSPlatformMemZero( &gMDNSRecord, sizeof gMDNSRecord);
-       mDNSPlatformMemZero( &gPlatformStorage, sizeof gPlatformStorage);
-
-       gPlatformStorage.reportStatusFunc = ReportStatus;
-
-       err = mDNS_Init( &gMDNSRecord, &gPlatformStorage, gRRCache, RR_CACHE_SIZE, mDNS_Init_AdvertiseLocalAddresses, CoreCallback, mDNS_Init_NoInitCallbackContext); 
-       require_noerr( err, exit);
-
-       err = SetupNotifications();
-       check_noerr( err );
-
-       err = udsserver_init(mDNSNULL, 0);
-       require_noerr( err, exit);
-
-       SetLLRoute( &gMDNSRecord );
-
-exit:
-       if( err != kNoErr )
-       {
-               ServiceSpecificFinalize( argc, argv );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     ServiceSpecificRun
-//===========================================================================================================================
-
-static OSStatus        ServiceSpecificRun( int argc, LPTSTR argv[] )
-{
-       mDNSBool done = mDNSfalse;
-       mStatus err = mStatus_NoError;
-       
-       DEBUG_UNUSED( argc );
-       DEBUG_UNUSED( argv );
-
-       err = SetupInterfaceList( &gMDNSRecord );
-       check( !err );
-
-       err = uDNS_SetupDNSConfig( &gMDNSRecord );
-       check( !err );
-
-       while( !done )
-       {
-               static mDNSs32 RepeatedBusy = 0;        
-               mDNSs32 nextTimerEvent;
-               mStatus err;
-
-               // Give the mDNS core a chance to do its work and determine next event time.
-
-               nextTimerEvent = udsserver_idle( mDNS_Execute( &gMDNSRecord ) - mDNS_TimeNow( &gMDNSRecord ) );
-
-               if      ( nextTimerEvent < 0)                                   nextTimerEvent = 0;
-               else if ( nextTimerEvent > (0x7FFFFFFF / 1000)) nextTimerEvent = 0x7FFFFFFF / mDNSPlatformOneSecond;
-               else                                                                                    nextTimerEvent = ( nextTimerEvent * 1000) / mDNSPlatformOneSecond;
-
-               // Debugging sanity check, to guard against CPU spins
-                       
-               if ( nextTimerEvent > 0 )
-               {
-                       RepeatedBusy = 0;
-               }
-               else
-               {
-                       nextTimerEvent = 1;
-
-                       if ( ++RepeatedBusy >= mDNSPlatformOneSecond )
-                       {
-                               ShowTaskSchedulingError( &gMDNSRecord );
-                               RepeatedBusy = 0;
-                       }
-               }
-
-               if ( gMDNSRecord.ShutdownTime )
-               {
-                       mDNSs32 now = mDNS_TimeNow( &gMDNSRecord );
-
-                       if ( mDNS_ExitNow( &gMDNSRecord, now ) )
-                       {
-                               mDNS_FinalExit( &gMDNSRecord );
-                               done = TRUE;
-                               break;
-                       }
-
-                       if ( nextTimerEvent - gMDNSRecord.ShutdownTime >= 0 )
-                       {
-                               nextTimerEvent = gMDNSRecord.ShutdownTime;
-                       }
-               }
-
-               err = mDNSPoll( nextTimerEvent );
-
-               if ( err )
-               {
-                       Sleep( 3 * 1000 );
-                               
-                       err = SetupInterfaceList( &gMDNSRecord );
-                       check( !err );
-
-                       err = uDNS_SetupDNSConfig( &gMDNSRecord );
-                       check( !err );
-                               
-                       break;
-               }
-       }
-
-       return ( err );
-}
-
-
-//===========================================================================================================================
-//     ServiceSpecificStop
-//===========================================================================================================================
-
-static OSStatus        ServiceSpecificStop( void )
-{
-       OSStatus    err;
-       BOOL        ok;
-
-       ok = SetEvent(gStopEvent);
-       err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-exit:
-
-       return( err );
-}
-
-//===========================================================================================================================
-//     ServiceSpecificFinalize
-//===========================================================================================================================
-
-static void    ServiceSpecificFinalize( int argc, LPTSTR argv[] )
-{
-       DEBUG_UNUSED( argc );
-       DEBUG_UNUSED( argv );
-       
-       //
-       // clean up the notifications
-       //
-       TearDownNotifications();
-
-       //
-       // clean up loaded library
-       //
-
-       if( gIPHelperLibraryInstance )
-       {
-               gGetIpInterfaceEntryFunctionPtr = NULL;
-               
-               FreeLibrary( gIPHelperLibraryInstance );
-               gIPHelperLibraryInstance = NULL;
-       }
-}
-
-
-//===========================================================================================================================
-//     SetupServiceEvents
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupServiceEvents()
-{
-       mStatus err;
-       
-       // Stop Event
-
-       gStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( gStopEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( err )
-       {
-               TearDownServiceEvents();
-       }
-
-       return err;
-}
-
-
-//===========================================================================================================================
-//     TearDownServiceNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus      TearDownServiceEvents()
-{
-       if ( gStopEvent )
-       {
-               CloseHandle( gStopEvent );
-               gStopEvent = NULL;
-       }
-
-       return mStatus_NoError;
-}
-
-
-//===========================================================================================================================
-//     SetupNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupNotifications()
-{
-       mStatus                         err;
-       SocketRef                       sock;
-       unsigned long           param;
-       int                                     inBuffer;
-       int                                     outBuffer;
-       DWORD                           outSize;
-
-       require_action( gStopEvent, exit, err = kUnknownErr );
-       err = mDNSPollRegisterEvent( gStopEvent, StopNotification, NULL );
-       require_noerr( err, exit );
-
-       // Power Suspend
-
-       gPowerSuspendEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( gPowerSuspendEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = mDNSPollRegisterEvent( gPowerSuspendEvent, PowerSuspendNotification, NULL );
-       require_noerr( err, exit );
-
-       // Power Suspend Ack
-
-       gPowerSuspendAckEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( gPowerSuspendAckEvent, ( mStatus ) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       // Power Resume
-
-       gPowerResumeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( gPowerResumeEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = mDNSPollRegisterEvent( gPowerResumeEvent, PowerResumeNotification, NULL );
-       require_noerr( err, exit );
-
-       // Register to listen for address list changes.
-       
-       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-       gInterfaceListChangedSocket = sock;
-       
-       // Make the socket non-blocking so the WSAIoctl returns immediately with WSAEWOULDBLOCK. It will set the event 
-       // when a change to the interface list is detected.
-       
-       param = 1;
-       err = ioctlsocket( sock, FIONBIO, &param );
-       err = translate_errno( err == 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       inBuffer        = 0;
-       outBuffer       = 0;
-       err = WSAIoctl( sock, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
-       if( err < 0 )
-       {
-               check( errno_compat() == WSAEWOULDBLOCK );
-       }
-
-       err = mDNSPollRegisterSocket( sock, FD_ADDRESS_LIST_CHANGE, InterfaceListNotification, NULL );
-       require_noerr( err, exit );
-       
-       gDescChangedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-       err = translate_errno( gDescChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters"), 0, KEY_READ, &gDescKey);
-       check_translated_errno( err == 0, errno_compat(), kNameErr );
-
-       if ( gDescKey != NULL )
-       {
-               err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
-               require_noerr( err, exit );
-       }
-
-       err = mDNSPollRegisterEvent( gDescChangedEvent, ComputerDescriptionNotification, NULL );
-       require_noerr( err, exit );
-
-       // This will catch all changes to tcp/ip networking, including changes to the domain search list
-
-       gTcpipChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( gTcpipChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &gTcpipKey );
-       require_noerr( err, exit );
-       err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE);
-       require_noerr( err, exit );
-       err = mDNSPollRegisterEvent( gTcpipChangedEvent, TCPChangedNotification, NULL );
-       require_noerr( err, exit );
-
-       // This will catch all changes to ddns configuration
-
-       gDdnsChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( gDdnsChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup"), &gDdnsKey );
-       require_noerr( err, exit );
-       err = RegNotifyChangeKeyValue( gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
-       require_noerr( err, exit );
-       err = mDNSPollRegisterEvent( gDdnsChangedEvent, DDNSChangedNotification, NULL );
-       require_noerr( err, exit );
-
-       // This will catch all changes to file sharing
-
-       gFileSharingChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( gFileSharingChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\Shares"), &gFileSharingKey );
-       
-       // Just to make sure that initialization doesn't fail on some old OS
-       // that doesn't have this key, we'll only add the notification if
-       // the key exists.
-
-       if ( !err )
-       {
-               err = RegNotifyChangeKeyValue( gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
-               require_noerr( err, exit );
-               err = mDNSPollRegisterEvent( gFileSharingChangedEvent, FileSharingChangedNotification, NULL );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = mStatus_NoError;
-       }
-
-       // This will catch changes to the Windows firewall
-
-       gFirewallChangedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-       err = translate_errno( gFirewallChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-
-       // Just to make sure that initialization doesn't fail on some old OS
-       // that doesn't have this key, we'll only add the notification if
-       // the key exists.
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\SharedAccess\\Parameters\\FirewallPolicy\\FirewallRules"), &gFirewallKey );
-       
-       if ( !err )
-       {
-               err = RegNotifyChangeKeyValue( gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
-               require_noerr( err, exit );
-               err = mDNSPollRegisterEvent( gFirewallChangedEvent, FirewallChangedNotification, NULL );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               err = mStatus_NoError;
-       }
-
-       // This will catch all changes to advertised services configuration
-
-       gAdvertisedServicesChangedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
-       err = translate_errno( gAdvertisedServicesChangedEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\Services"), &gAdvertisedServicesKey );
-       require_noerr( err, exit );
-       err = RegNotifyChangeKeyValue( gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
-       require_noerr( err, exit );
-       err = mDNSPollRegisterEvent( gAdvertisedServicesChangedEvent, AdvertisedServicesChangedNotification, NULL );
-       require_noerr( err, exit );
-
-       // SPSWakeup timer
-
-       gSPSWakeupEvent = CreateWaitableTimer( NULL, FALSE, NULL );
-       err = translate_errno( gSPSWakeupEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = mDNSPollRegisterEvent( gSPSWakeupEvent, SPSWakeupNotification, NULL );
-       require_noerr( err, exit );
-
-       // SPSSleep timer
-
-       gSPSSleepEvent = CreateWaitableTimer( NULL, FALSE, NULL );
-       err = translate_errno( gSPSSleepEvent, (mStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       err = mDNSPollRegisterEvent( gSPSSleepEvent, SPSSleepNotification, NULL );
-       require_noerr( err, exit );
-
-exit:
-       if( err )
-       {
-               TearDownNotifications();
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     TearDownNotifications
-//===========================================================================================================================
-
-mDNSlocal mStatus      TearDownNotifications()
-{
-       if( IsValidSocket( gInterfaceListChangedSocket ) )
-       {
-               mDNSPollUnregisterSocket( gInterfaceListChangedSocket );
-
-               close_compat( gInterfaceListChangedSocket );
-               gInterfaceListChangedSocket = kInvalidSocketRef;
-       }
-
-       if ( gDescChangedEvent != NULL )
-       {
-               mDNSPollUnregisterEvent( gDescChangedEvent );
-               CloseHandle( gDescChangedEvent );
-               gDescChangedEvent = NULL;
-       }
-
-       if ( gDescKey != NULL )
-       {
-               RegCloseKey( gDescKey );
-               gDescKey = NULL;
-       }
-
-       if ( gTcpipChangedEvent != NULL )
-       {
-               mDNSPollUnregisterEvent( gTcpipChangedEvent );
-               CloseHandle( gTcpipChangedEvent );
-               gTcpipChangedEvent = NULL;
-       }
-
-       if ( gDdnsChangedEvent != NULL )
-       {
-               mDNSPollUnregisterEvent( gDdnsChangedEvent );
-               CloseHandle( gDdnsChangedEvent );
-               gDdnsChangedEvent = NULL;
-       }
-
-       if ( gDdnsKey != NULL )
-       {
-               RegCloseKey( gDdnsKey );
-               gDdnsKey = NULL;
-       }
-
-       if ( gFileSharingChangedEvent != NULL )
-       {
-               mDNSPollUnregisterEvent( gFileSharingChangedEvent );
-               CloseHandle( gFileSharingChangedEvent );
-               gFileSharingChangedEvent = NULL;
-       }
-
-       if ( gFileSharingKey != NULL )
-       {
-               RegCloseKey( gFileSharingKey );
-               gFileSharingKey = NULL;
-       }
-
-       if ( gFirewallChangedEvent != NULL )
-       {
-               mDNSPollUnregisterEvent( gFirewallChangedEvent );
-               CloseHandle( gFirewallChangedEvent );
-               gFirewallChangedEvent = NULL;
-       }
-
-       if ( gFirewallKey != NULL )
-       {
-               RegCloseKey( gFirewallKey );
-               gFirewallKey = NULL;
-       }
-
-       if ( gAdvertisedServicesChangedEvent != NULL )
-       {
-               mDNSPollUnregisterEvent( gAdvertisedServicesChangedEvent );
-               CloseHandle( gAdvertisedServicesChangedEvent );
-               gAdvertisedServicesChangedEvent = NULL;
-       }
-
-       if ( gAdvertisedServicesKey != NULL )
-       {
-               RegCloseKey( gAdvertisedServicesKey );
-               gAdvertisedServicesKey = NULL;
-       }
-
-       if ( gSPSWakeupEvent )
-       {
-               mDNSPollUnregisterEvent( gSPSWakeupEvent );
-               CloseHandle( gSPSWakeupEvent );
-               gSPSWakeupEvent = NULL;
-       }
-
-       if ( gSPSSleepEvent )
-       {
-               mDNSPollUnregisterEvent( gSPSSleepEvent );
-               CloseHandle( gSPSSleepEvent );
-               gSPSSleepEvent = NULL;
-       }
-
-       if ( gPowerResumeEvent )
-       {
-               mDNSPollUnregisterEvent( gPowerResumeEvent );
-               CloseHandle( gPowerResumeEvent );
-               gPowerResumeEvent = NULL;
-       }
-
-       if ( gPowerSuspendAckEvent )
-       {
-               CloseHandle( gPowerSuspendAckEvent );
-               gPowerSuspendAckEvent = NULL;
-       }
-
-       if ( gPowerSuspendEvent )
-       {
-               mDNSPollUnregisterEvent( gPowerSuspendEvent );
-               CloseHandle( gPowerSuspendEvent );
-               gPowerSuspendEvent = NULL;
-       }
-
-       if ( gStopEvent )
-       {
-               mDNSPollUnregisterEvent( gStopEvent );
-       }
-
-       return( mStatus_NoError );
-}
-
-
-mDNSlocal void CALLBACK
-StopNotification( HANDLE event, void *context )
-{
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       dlog( kDebugLevelVerbose, DEBUG_NAME "stopping...\n" );
-       udsserver_exit();
-       mDNS_StartExit( &gMDNSRecord );
-}
-
-
-mDNSlocal void CALLBACK
-PowerSuspendNotification( HANDLE event, void * context )
-{
-       LARGE_INTEGER   timeout;
-       BOOL                    ok;
-
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       dlog( kDebugLevelInfo, DEBUG_NAME "PowerSuspendNotification\n" );
-
-       gMDNSRecord.SystemWakeOnLANEnabled = SystemWakeForNetworkAccess( &timeout );
-                               
-       if ( gMDNSRecord.SystemWakeOnLANEnabled )
-       {
-               ok = SetWaitableTimer( gSPSWakeupEvent, &timeout, 0, NULL, NULL, TRUE );
-               check( ok );
-       }
-
-       mDNSCoreMachineSleep(&gMDNSRecord, TRUE);
-
-       ok = SetEvent( gPowerSuspendAckEvent );
-
-       if ( !ok )
-       {
-               dlog( kDebugLevelError, DEBUG_NAME "PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
-               ReportStatus( EVENTLOG_ERROR_TYPE, "PowerSuspendNotification: error while setting acknowledgement: %d", GetLastError() );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-PowerResumeNotification( HANDLE event, void * context )
-{
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       dlog( kDebugLevelInfo, DEBUG_NAME "PowerResumeNotification\n" );
-
-       if ( gSPSWakeupEvent )
-       {
-               CancelWaitableTimer( gSPSWakeupEvent );
-       }
-
-       if ( gSPSSleepEvent )
-       {
-               CancelWaitableTimer( gSPSSleepEvent );
-       }
-
-       mDNSCoreMachineSleep(&gMDNSRecord, FALSE);
-}
-
-
-
-mDNSlocal void CALLBACK
-InterfaceListNotification( SOCKET socket, LPWSANETWORKEVENTS event, void *context )
-{
-       int             inBuffer;
-       int             outBuffer;
-       DWORD   outSize;
-       int             err;
-
-       DEBUG_UNUSED( socket );
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       // It would be nice to come up with a more elegant solution to this, but it seems that
-       // GetAdaptersAddresses doesn't always stay in sync after network changed events.  So as
-       // as a simple workaround, we'll pause for a couple of seconds before processing the change.
-
-       // We arrived at 2 secs by trial and error. We could reproduce the problem after sleeping
-       // for 500 msec and 750 msec, but couldn't after sleeping for 1 sec.  We added another
-       // second on top of that to account for machine load or some other exigency.
-
-       Sleep( 2000 );
-
-       // Interface list changed event. Break out of the inner loop to re-setup the wait list.
-                                       
-       InterfaceListDidChange( &gMDNSRecord );
-
-       // reset the event handler
-       inBuffer        = 0;
-       outBuffer       = 0;
-       err = WSAIoctl( gInterfaceListChangedSocket, SIO_ADDRESS_LIST_CHANGE, &inBuffer, 0, &outBuffer, 0, &outSize, NULL, NULL );
-       if( err < 0 )
-       {
-               check( errno_compat() == WSAEWOULDBLOCK );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-ComputerDescriptionNotification( HANDLE event, void *context )
-{
-       // The computer description might have changed
-                                       
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       ComputerDescriptionDidChange( &gMDNSRecord );
-       udsserver_handle_configchange( &gMDNSRecord );
-
-       // and reset the event handler
-       if ( ( gDescKey != NULL ) && ( gDescChangedEvent != NULL ) )
-       {
-               int err = RegNotifyChangeKeyValue( gDescKey, TRUE, REG_NOTIFY_CHANGE_LAST_SET, gDescChangedEvent, TRUE);
-               check_noerr( err );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-TCPChangedNotification( HANDLE event, void *context )
-{
-       // The TCP/IP might have changed
-
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       TCPIPConfigDidChange( &gMDNSRecord );
-       udsserver_handle_configchange( &gMDNSRecord );
-
-       // and reset the event handler
-
-       if ( ( gTcpipKey != NULL ) && ( gTcpipChangedEvent ) )
-       {
-               int err = RegNotifyChangeKeyValue( gTcpipKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gTcpipChangedEvent, TRUE );
-               check_noerr( err );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-DDNSChangedNotification( HANDLE event, void *context )
-{
-       // The DynDNS config might have changed
-
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       DynDNSConfigDidChange( &gMDNSRecord );
-       udsserver_handle_configchange( &gMDNSRecord );
-
-       // and reset the event handler
-
-       if ((gDdnsKey != NULL) && (gDdnsChangedEvent))
-       {
-               int err = RegNotifyChangeKeyValue(gDdnsKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gDdnsChangedEvent, TRUE);
-               check_noerr( err );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-FileSharingChangedNotification( HANDLE event, void *context )
-{
-       // File sharing changed
-
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       FileSharingDidChange( &gMDNSRecord );
-
-       // and reset the event handler
-
-       if ((gFileSharingKey != NULL) && (gFileSharingChangedEvent))
-       {
-               int err = RegNotifyChangeKeyValue(gFileSharingKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFileSharingChangedEvent, TRUE);
-               check_noerr( err );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-FirewallChangedNotification( HANDLE event, void *context )
-{
-       // Firewall configuration changed
-
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       FirewallDidChange( &gMDNSRecord );
-
-       // and reset the event handler
-
-       if ((gFirewallKey != NULL) && (gFirewallChangedEvent))
-       {
-               int err = RegNotifyChangeKeyValue(gFirewallKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gFirewallChangedEvent, TRUE);
-               check_noerr( err );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-AdvertisedServicesChangedNotification( HANDLE event, void *context )
-{
-       // Ultimately we'll want to manage multiple services, but right now the only service
-       // we'll be managing is SMB.
-
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       FileSharingDidChange( &gMDNSRecord );
-
-       // and reset the event handler
-
-       if ( ( gAdvertisedServicesKey != NULL ) && ( gAdvertisedServicesChangedEvent ) )
-       {
-               int err = RegNotifyChangeKeyValue(gAdvertisedServicesKey, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_LAST_SET, gAdvertisedServicesChangedEvent, TRUE);
-               check_noerr( err );
-       }
-}
-
-
-mDNSlocal void CALLBACK
-SPSWakeupNotification( HANDLE event, void *context )
-{
-       LARGE_INTEGER timeout;
-
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Maintenance wake" );
-
-       timeout.QuadPart  = kSPSMaintenanceWakePeriod;
-       timeout.QuadPart *= kSecondsTo100NSUnits;
-
-       SetWaitableTimer( gSPSSleepEvent, &timeout, 0, NULL, NULL, TRUE );
-}
-
-
-mDNSlocal void CALLBACK
-SPSSleepNotification( HANDLE event, void *context )
-{
-       DEBUG_UNUSED( event );
-       DEBUG_UNUSED( context );
-
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "Returning to sleep after maintenance wake" );
-
-       // Calling SetSuspendState() doesn't invoke our sleep handlers, so we'll
-       // call HandlePowerSuspend() explicity.  This will reset the 
-       // maintenance wake timers.
-
-       PowerSuspendNotification( gPowerSuspendEvent, NULL );
-       SetSuspendState( FALSE, FALSE, FALSE );
-}
-
-
-//===========================================================================================================================
-//     CoreCallback
-//===========================================================================================================================
-
-static void
-CoreCallback(mDNS * const inMDNS, mStatus status)
-{
-       if (status == mStatus_ConfigChanged)
-       {
-               SetLLRoute( inMDNS );
-       }
-}
-
-
-//===========================================================================================================================
-//     UDSAcceptNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-UDSAcceptNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
-       ( void ) sock;
-       ( void ) event;
-       ( void ) context;
-       
-       if ( gUDSCallback )
-       {
-               gUDSCallback( ( int ) gUDSSocket, 0, context );
-       }
-}
-
-
-//===========================================================================================================================
-//     UDSReadNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-UDSReadNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
-       TCPSocket *tcpSock = ( TCPSocket* ) context;
-
-       ( void ) sock;
-       ( void ) event;
-
-       if ( tcpSock )
-       {
-               tcpSock->userCallback( ( int ) tcpSock->fd, 0, tcpSock->userContext );
-       }
-}
-
-
-//===========================================================================================================================
-//     udsSupportAddFDToEventLoop
-//===========================================================================================================================
-
-mStatus
-udsSupportAddFDToEventLoop( SocketRef fd, udsEventCallback callback, void *context, void **platform_data)
-{
-       mStatus err = mStatus_NoError;
-
-       // We are using some knowledge of what is being passed to us here.  If the fd is a listen socket,
-       // then the "context" parameter is NULL.  If it is an actual read/write socket, then the "context"
-       // parameter is not null.
-
-       if ( context )
-       {
-               TCPSocket * sock;
-
-               sock = malloc( sizeof( TCPSocket ) );
-               require_action( sock, exit, err = mStatus_NoMemoryErr );
-               mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
-
-               sock->fd                                = (SOCKET) fd;
-               sock->userCallback              = callback;
-               sock->userContext               = context;
-               sock->m                                 = &gMDNSRecord;
-
-               *platform_data = sock;
-
-               err = mDNSPollRegisterSocket( sock->fd, FD_READ | FD_CLOSE, UDSReadNotification, sock );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               gUDSSocket              = fd;
-               gUDSCallback    = callback;
-
-               err = mDNSPollRegisterSocket( gUDSSocket, FD_ACCEPT | FD_CLOSE, UDSAcceptNotification, NULL );
-               require_noerr( err, exit );
-       }
-
-exit:
-
-       return err;
-}
-
-
-int
-udsSupportReadFD( SocketRef fd, char *buf, int len, int flags, void *platform_data )
-{
-       TCPSocket       *       sock;
-       mDNSBool                closed;
-       int                             ret;
-
-       ( void ) flags;
-
-       sock = ( TCPSocket* ) platform_data;
-       require_action( sock, exit, ret = -1 );
-       require_action( sock->fd == fd, exit, ret = -1 );
-
-       ret = mDNSPlatformReadTCP( sock, buf, len, &closed );
-
-       if ( closed )
-       {
-               ret = 0;
-       }
-       else if ( !ret && ( WSAGetLastError() == WSAEWOULDBLOCK ) )
-       {
-               // mDNSPlatformReadTCP will return 0 if it gets WSAEWOULDBLOCK, but
-               // that caller of this routine interprets that as close connection.
-               // We'll fix that by returning -1 in that case.
-
-               ret = -1;
-       }
-
-exit:
-
-       return ret;
-}
-
-
-mStatus
-udsSupportRemoveFDFromEventLoop( SocketRef fd, void *platform_data)            // Note: This also CLOSES the socket
-{
-       mStatus err = kNoErr;
-
-       mDNSPollUnregisterSocket( fd );
-
-       if ( platform_data != NULL )
-       {
-               TCPSocket * sock;
-
-               dlog( kDebugLevelInfo, DEBUG_NAME "session closed\n" );
-               sock = ( TCPSocket* ) platform_data;
-               check( sock->fd == fd );
-               mDNSPlatformTCPCloseConnection( sock );
-       }
-
-       return err;
-}
-
-
-mDNSexport void RecordUpdatedNiceLabel(mDNS *const m, mDNSs32 delay)
-       {
-       (void)m;
-       (void)delay;
-       // No-op, for now
-       }
-
-
-//===========================================================================================================================
-//     SystemWakeForNetworkAccess
-//===========================================================================================================================
-
-mDNSu8
-SystemWakeForNetworkAccess( LARGE_INTEGER * timeout )
-{
-       HKEY                                    key = NULL;
-       DWORD                                   dwSize;
-       DWORD                                   enabled;
-       mDNSu8                                  ok;
-       SYSTEM_POWER_STATUS             powerStatus;
-       time_t                                  startTime;
-       time_t                                  nextWakeupTime;
-       int                                             delta;
-       DWORD                                   err;
-
-       dlog( kDebugLevelInfo, DEBUG_NAME "SystemWakeForNetworkAccess\n" );
-
-       // Make sure we have a timer
-
-       require_action( gSPSWakeupEvent != NULL, exit, ok = FALSE );
-       require_action( gSPSSleepEvent != NULL, exit, ok = FALSE );
-
-       // Make sure the user enabled bonjour sleep proxy client 
-       
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Power Management", &key );
-       require_action( !err, exit, ok = FALSE );
-       dwSize = sizeof( DWORD );
-       err = RegQueryValueEx( key, L"Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-       require_action( !err, exit, ok = FALSE );
-       require_action( enabled, exit, ok = FALSE );
-       
-       // Make sure machine is on AC power
-       
-       ok = ( mDNSu8 ) GetSystemPowerStatus( &powerStatus );
-       require_action( ok, exit, ok = FALSE );
-       require_action( powerStatus.ACLineStatus == AC_LINE_ONLINE, exit, ok = FALSE );
-
-       // Now make sure we have a network interface that does wake-on-lan
-
-       ok = ( mDNSu8 ) IsWOMPEnabled( &gMDNSRecord );
-       require_action( ok, exit, ok = FALSE );
-
-       // Now make sure we have advertised services. Doesn't make sense to
-       // enable sleep proxy if we have no multicast services that could
-       // potentially wake us up.
-
-       ok = ( mDNSu8 ) mDNSCoreHaveAdvertisedMulticastServices( &gMDNSRecord );
-       require_action( ok, exit, ok = FALSE );
-
-       // Calculate next wake up time
-
-       startTime               = time( NULL );                                 // Seconds since midnight January 1, 1970
-       nextWakeupTime  = startTime + ( 120 * 60 );             // 2 hours later
-       
-       if ( gMDNSRecord.p->nextDHCPLeaseExpires < nextWakeupTime )
-       {
-               nextWakeupTime = gMDNSRecord.p->nextDHCPLeaseExpires;
-       }
-
-       // Finally calculate the next relative wakeup time
-
-       delta = ( int )( ( ( double )( nextWakeupTime - startTime ) ) * 0.9 );
-       ReportStatus( EVENTLOG_INFORMATION_TYPE, "enabling sleep proxy client with next maintenance wake in %d seconds", delta );
-
-       // Convert seconds to 100 nanosecond units expected by SetWaitableTimer
-
-       timeout->QuadPart  = -delta;
-       timeout->QuadPart *= kSecondsTo100NSUnits;
-
-       ok = TRUE;
-
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       return ok;
-}
-
-
-//===========================================================================================================================
-//     HaveRoute
-//===========================================================================================================================
-
-static bool
-HaveRoute( PMIB_IPFORWARDROW rowExtant, unsigned long addr, unsigned long metric )
-{
-       PMIB_IPFORWARDTABLE     pIpForwardTable = NULL;
-       DWORD                           dwSize                  = 0;
-       BOOL                            bOrder                  = FALSE;
-       OSStatus                        err;
-       bool                            found                   = false;
-       unsigned long int       i;
-
-       //
-       // Find out how big our buffer needs to be.
-       //
-       err = GetIpForwardTable(NULL, &dwSize, bOrder);
-       require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
-
-       //
-       // Allocate the memory for the table
-       //
-       pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
-       require_action( pIpForwardTable, exit, err = kNoMemoryErr );
-  
-       //
-       // Now get the table.
-       //
-       err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
-       require_noerr( err, exit );
-
-       //
-       // Search for the row in the table we want.
-       //
-       for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
-       {
-               if ( ( pIpForwardTable->table[i].dwForwardDest == addr ) && ( !metric || ( pIpForwardTable->table[i].dwForwardMetric1 == metric ) ) )
-               {
-                       memcpy( rowExtant, &(pIpForwardTable->table[i]), sizeof(*rowExtant) );
-                       found = true;
-                       break;
-               }
-       }
-
-exit:
-
-       if ( pIpForwardTable != NULL ) 
-       {
-               free(pIpForwardTable);
-       }
-    
-       return found;
-}
-
-
-//===========================================================================================================================
-//     IsValidAddress
-//===========================================================================================================================
-
-static bool
-IsValidAddress( const char * addr )
-{
-       return ( addr && ( strcmp( addr, "0.0.0.0" ) != 0 ) ) ? true : false;
-}      
-
-
-//===========================================================================================================================
-//     GetAdditionalMetric
-//===========================================================================================================================
-
-static ULONG
-GetAdditionalMetric( DWORD ifIndex )
-{
-       ULONG metric = 0;
-
-       if( !gIPHelperLibraryInstance )
-       {
-               gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
-
-               gGetIpInterfaceEntryFunctionPtr = 
-                               (GetIpInterfaceEntryFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetIpInterfaceEntry" );
-
-               if( !gGetIpInterfaceEntryFunctionPtr )
-               {               
-                       BOOL ok;
-                               
-                       ok = FreeLibrary( gIPHelperLibraryInstance );
-                       check_translated_errno( ok, GetLastError(), kUnknownErr );
-                       gIPHelperLibraryInstance = NULL;
-               }
-       }
-
-       if ( gGetIpInterfaceEntryFunctionPtr )
-       {
-               MIB_IPINTERFACE_ROW row;
-               DWORD err;
-
-               ZeroMemory( &row, sizeof( MIB_IPINTERFACE_ROW ) );
-               row.Family = AF_INET;
-               row.InterfaceIndex = ifIndex;
-               err = gGetIpInterfaceEntryFunctionPtr( &row );
-               require_noerr( err, exit );
-               metric = row.Metric + 256;
-       }
-
-exit:
-
-       return metric;
-}
-
-
-//===========================================================================================================================
-//     SetLLRoute
-//===========================================================================================================================
-
-static OSStatus
-SetLLRoute( mDNS * const inMDNS )
-{
-       OSStatus err = kNoErr;
-
-       DEBUG_UNUSED( inMDNS );
-
-       //
-       // <rdar://problem/4096464> Don't call SetLLRoute on loopback
-       // <rdar://problem/6885843> Default route on Windows 7 breaks network connectivity
-       // 
-       // Don't mess w/ the routing table on Vista and later OSes, as 
-       // they have a permanent route to link-local addresses. Otherwise,
-       // set a route to link local addresses (169.254.0.0)
-       //
-       if ( ( inMDNS->p->osMajorVersion < 6 ) && gServiceManageLLRouting && !gPlatformStorage.registeredLoopback4 )
-       {
-               DWORD                           ifIndex;
-               MIB_IPFORWARDROW        rowExtant;
-               bool                            addRoute;
-               MIB_IPFORWARDROW        row;
-
-               ZeroMemory(&row, sizeof(row));
-
-               err = GetRouteDestination(&ifIndex, &row.dwForwardNextHop);
-               require_noerr( err, exit );
-               row.dwForwardDest               = inet_addr(kLLNetworkAddr);
-               row.dwForwardIfIndex    = ifIndex;
-               row.dwForwardMask               = inet_addr(kLLNetworkAddrMask);
-               row.dwForwardType               = 3;
-               row.dwForwardProto              = MIB_IPPROTO_NETMGMT;
-               row.dwForwardAge                = 0;
-               row.dwForwardPolicy             = 0;
-               row.dwForwardMetric1    = 20 + GetAdditionalMetric( ifIndex );
-               row.dwForwardMetric2    = (DWORD) - 1;
-               row.dwForwardMetric3    = (DWORD) - 1;
-               row.dwForwardMetric4    = (DWORD) - 1;
-               row.dwForwardMetric5    = (DWORD) - 1;
-
-               addRoute = true;
-
-               //
-               // check to make sure we don't already have a route
-               //
-               if ( HaveRoute( &rowExtant, inet_addr( kLLNetworkAddr ), 0 ) )
-               {
-                       //
-                       // set the age to 0 so that we can do a memcmp.
-                       //
-                       rowExtant.dwForwardAge = 0;
-
-                       //
-                       // check to see if this route is the same as our route
-                       //
-                       if (memcmp(&row, &rowExtant, sizeof(row)) != 0)
-                       {
-                               //
-                               // if it isn't then delete this entry
-                               //
-                               DeleteIpForwardEntry(&rowExtant);
-                       }
-                       else
-                       {
-                               //
-                               // else it is, so we don't want to create another route
-                               //
-                               addRoute = false;
-                       }
-               }
-
-               if (addRoute && row.dwForwardNextHop)
-               {
-                       err = CreateIpForwardEntry(&row);
-                       check_noerr( err );
-               }
-       }
-
-exit:
-
-       return ( err );
-}
-
-
-//===========================================================================================================================
-//     GetRouteDestination
-//===========================================================================================================================
-
-static OSStatus
-GetRouteDestination(DWORD * ifIndex, DWORD * address)
-{
-       struct in_addr          ia;
-       IP_ADAPTER_INFO *       pAdapterInfo    =       NULL;
-       IP_ADAPTER_INFO *       pAdapter                =       NULL;
-       ULONG                           bufLen;
-       mDNSBool                        done                    =       mDNSfalse;
-       OSStatus                        err;
-
-       //
-       // GetBestInterface will fail if there is no default gateway
-       // configured.  If that happens, we will just take the first
-       // interface in the list. MSDN support says there is no surefire
-       // way to manually determine what the best interface might
-       // be for a particular network address.
-       //
-       ia.s_addr       =       inet_addr(kLLNetworkAddr);
-       err                     =       GetBestInterface(*(IPAddr*) &ia, ifIndex);
-
-       if (err)
-       {
-               *ifIndex = 0;
-       }
-
-       //
-       // Make an initial call to GetAdaptersInfo to get
-       // the necessary size into the bufLen variable
-       //
-       err = GetAdaptersInfo( NULL, &bufLen);
-       require_action( err == ERROR_BUFFER_OVERFLOW, exit, err = kUnknownErr );
-
-       pAdapterInfo = (IP_ADAPTER_INFO*) malloc( bufLen );
-       require_action( pAdapterInfo, exit, err = kNoMemoryErr );
-       
-       err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-       require_noerr( err, exit );
-       
-       pAdapter        =       pAdapterInfo;
-       err                     =       kUnknownErr;
-                       
-       // <rdar://problem/3718122>
-       // <rdar://problem/5652098>
-       //
-       // Look for the Nortel VPN virtual interface, along with Juniper virtual interface.
-       //
-       // If these interfaces are active (i.e., has a non-zero IP Address),
-       // then we want to disable routing table modifications.
-
-       while (pAdapter)
-       {
-               if ( ( IsNortelVPN( pAdapter ) || IsJuniperVPN( pAdapter ) || IsCiscoVPN( pAdapter ) ) &&
-                        ( inet_addr( pAdapter->IpAddressList.IpAddress.String ) != 0 ) )
-               {
-                       dlog( kDebugLevelTrace, DEBUG_NAME "disabling routing table management due to VPN incompatibility" );
-                       goto exit;
-               }
-
-               pAdapter = pAdapter->Next;
-       }
-
-       while ( !done )
-       {
-               pAdapter        =       pAdapterInfo;
-               err                     =       kUnknownErr;
-
-               while (pAdapter)
-               {
-                       // If we don't have an interface selected, choose the first one that is of type ethernet and
-                       // has a valid IP Address
-
-                       if ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) && ( IsValidAddress( pAdapter->IpAddressList.IpAddress.String ) ) && (!(*ifIndex) || (pAdapter->Index == (*ifIndex))))
-                       {
-                               *address =      inet_addr( pAdapter->IpAddressList.IpAddress.String );
-                               *ifIndex =  pAdapter->Index;
-                               err              =      kNoErr;
-                               break;
-                       }
-               
-                       pAdapter = pAdapter->Next;
-               }
-
-               // If we found the right interface, or we weren't trying to find a specific interface then we're done
-
-               if ( !err || !( *ifIndex) )
-               {
-                       done = mDNStrue;
-               }
-
-               // Otherwise, try again by wildcarding the interface
-
-               else
-               {
-                       *ifIndex = 0;
-               }
-       } 
-
-exit:
-
-       if ( pAdapterInfo != NULL )
-       {
-               free( pAdapterInfo );
-       }
-
-       return( err );
-}
-
-
-static bool
-IsNortelVPN( IP_ADAPTER_INFO * pAdapter )
-{
-       return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
-                   (pAdapter->AddressLength == 6) &&
-                   (pAdapter->Address[0] == 0x44) &&
-                   (pAdapter->Address[1] == 0x45) &&
-                   (pAdapter->Address[2] == 0x53) &&
-                   (pAdapter->Address[3] == 0x54) &&
-                   (pAdapter->Address[4] == 0x42) &&
-                       (pAdapter->Address[5] == 0x00)) ? true : false;
-}
-
-
-static bool
-IsJuniperVPN( IP_ADAPTER_INFO * pAdapter )
-{      
-       return ( strnistr( pAdapter->Description, "Juniper", sizeof( pAdapter->Description  ) ) != NULL ) ? true : false;
-}
-
-
-static bool
-IsCiscoVPN( IP_ADAPTER_INFO * pAdapter )
-{
-       return ((pAdapter->Type == MIB_IF_TYPE_ETHERNET) &&
-                   (pAdapter->AddressLength == 6) &&
-                   (pAdapter->Address[0] == 0x00) &&
-                   (pAdapter->Address[1] == 0x05) &&
-                   (pAdapter->Address[2] == 0x9a) &&
-                   (pAdapter->Address[3] == 0x3c) &&
-                   (pAdapter->Address[4] == 0x7a) &&
-                       (pAdapter->Address[5] == 0x00)) ? true : false;
-}
-
-
-static const char *
-strnistr( const char * string, const char * subString, size_t max )
-{
-       size_t       subStringLen;
-       size_t       offset;
-       size_t       maxOffset;
-       size_t       stringLen;
-       const char * pPos;
-
-       if ( ( string == NULL ) || ( subString == NULL ) )
-       {
-               return string;
-       }
-
-       stringLen = ( max > strlen( string ) ) ? strlen( string ) : max;
-
-       if ( stringLen == 0 )
-       {
-               return NULL;
-       }
-       
-       subStringLen = strlen( subString );
-
-       if ( subStringLen == 0 )
-       {
-               return string;
-       }
-
-       if ( subStringLen > stringLen )
-       {
-               return NULL;
-       }
-
-       maxOffset = stringLen - subStringLen;
-       pPos      = string;
-
-       for ( offset = 0; offset <= maxOffset; offset++ )
-       {
-               if ( _strnicmp( pPos, subString, subStringLen ) == 0 )
-               {
-                       return pPos;
-               }
-
-               pPos++;
-       }
-
-       return NULL;
-}
-
diff --git a/mDNSWindows/SystemService/Service.h b/mDNSWindows/SystemService/Service.h
deleted file mode 100755 (executable)
index 0b806f0..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef        __MDNS_SERVICE_H__
-#define        __MDNS_SERVICE_H__
-
-
-#include <windows.h>
-
-
-extern int     RunDirect( int argc, LPTSTR argv[] );
-extern int     Main( int argc, LPTSTR argv[] );
-
-
-#endif
-
diff --git a/mDNSWindows/SystemService/Service.mcp b/mDNSWindows/SystemService/Service.mcp
deleted file mode 100644 (file)
index ca15566..0000000
Binary files a/mDNSWindows/SystemService/Service.mcp and /dev/null differ
diff --git a/mDNSWindows/SystemService/Service.rc b/mDNSWindows/SystemService/Service.rc
deleted file mode 100644 (file)
index 60ad484..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "winres.h"
-#include "WinVersRes.h"
-#include "EventLog.rc"
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x3fL
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x1L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", MASTER_COMPANY_NAME
-            VALUE "FileDescription", "Bonjour Service"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "mDNSResponder.exe"
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
-            VALUE "OriginalFilename", "mDNSResponder.exe"
-            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
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""winres.h""\r\n"
-    "#include ""WinVersRes.h""\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// String Table
-//
-
-STRINGTABLE 
-BEGIN
-    IDS_SERVICE_DESCRIPTION "Enables hardware devices and software services to automatically configure themselves on the network and advertise their presence, so that users can discover and use those services without any unnecessary manual setup or administration."
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/mDNSWindows/SystemService/Service.vcproj b/mDNSWindows/SystemService/Service.vcproj
deleted file mode 100644 (file)
index 7db6bc1..0000000
+++ /dev/null
@@ -1,570 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="mDNSResponder"\r
-       ProjectGUID="{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}"\r
-       RootNamespace="mDNSResponder"\r
-       Keyword="Win32Proj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;$(VCInstallDir)include&quot;;&quot;$(VCInstallDir)atlmfc\include&quot;;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               DisableSpecificWarnings="4127;4201"\r
-                               ShowIncludes="false"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
-                               OutputFile="$(OutDir)/mDNSResponder.exe"\r
-                               LinkIncremental="2"\r
-                               IgnoreAllDefaultLibraries="false"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"\r
-                               SubSystem="1"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\mDNSResponder.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;$(VCInstallDir)include&quot;;&quot;$(VCInstallDir)atlmfc\include&quot;;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               DisableSpecificWarnings="4127;4201"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
-                               OutputFile="$(OutDir)/mDNSResponder.exe"\r
-                               LinkIncremental="2"\r
-                               IgnoreAllDefaultLibraries="false"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/mDNSResponder.pdb"\r
-                               SubSystem="1"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\mDNSResponder64.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;$(VCInstallDir)include&quot;;&quot;$(VCInstallDir)atlmfc\include&quot;;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                               DisableSpecificWarnings="4127;4201"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib crypt32.lib netapi32.lib powrprof.lib"\r
-                               OutputFile="$(OutDir)/mDNSResponder.exe"\r
-                               LinkIncremental="1"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
-                               SubSystem="1"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\mDNSResponder.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal&quot;                                                   mkdir &quot;$(DSTROOT)\AppleInternal&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin&quot;                                            mkdir &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                           &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetDir)$(TargetName).pdb&quot;                                          &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="1"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSCore;../../mDNSShared;&quot;$(VCInstallDir)include&quot;;&quot;$(VCInstallDir)atlmfc\include&quot;;&quot;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include&quot;"\r
-                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE=&quot;&quot;&quot;&quot;;UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               DisableSpecificWarnings="4127;4201"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="ws2_32.lib iphlpapi.lib netapi32.lib powrprof.lib"\r
-                               OutputFile="$(OutDir)/mDNSResponder.exe"\r
-                               LinkIncremental="1"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
-                               SubSystem="1"\r
-                               OptimizeReferences="2"\r
-                               EnableCOMDATFolding="2"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                               AdditionalManifestFiles="res\mDNSResponder64.manifest"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal&quot;                                                   mkdir &quot;$(DSTROOT)\AppleInternal&quot;&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\AppleInternal\bin&quot;                                            mkdir &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                           &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetDir)$(TargetName).pdb&quot;                                          &quot;$(DSTROOT)\AppleInternal\bin&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\DNSCommon.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\DNSDigest.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\EventLog.mc"\r
-                               >\r
-                               <FileConfiguration\r
-                                       Name="Debug|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCustomBuildTool"\r
-                                               Description="Compiling Message Resource"\r
-                                               CommandLine="mc.exe EventLog.mc"\r
-                                               Outputs="EventLog.rc EventLog.h"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Debug|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCustomBuildTool"\r
-                                               Description="Compiling Message Resource"\r
-                                               CommandLine="mc.exe EventLog.mc"\r
-                                               Outputs="EventLog.rc EventLog.h"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|Win32"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCustomBuildTool"\r
-                                               Description="Compiling Message Resource"\r
-                                               CommandLine="mc.exe EventLog.mc"\r
-                                               Outputs="EventLog.rc EventLog.h"\r
-                                       />\r
-                               </FileConfiguration>\r
-                               <FileConfiguration\r
-                                       Name="Release|x64"\r
-                                       >\r
-                                       <Tool\r
-                                               Name="VCCustomBuildTool"\r
-                                               Description="Compiling Message Resource"\r
-                                               CommandLine="mc.exe EventLog.mc"\r
-                                               Outputs="EventLog.rc EventLog.h"\r
-                                       />\r
-                               </FileConfiguration>\r
-                       </File>\r
-                       <File\r
-                               RelativePath="Firewall.cpp"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\GenLinkedList.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSMacOSX\LegacyNATTraversal.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\main.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\mDNS.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\mDNSDebug.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\mDNSWin32.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Poll.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Secret.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\Service.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\uDNS.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\uds_daemon.c"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\CommonServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\DNSCommon.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\dnssd_ipc.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\GenLinkedList.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\mDNSDebug.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\mDNSEmbeddedAPI.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\mDNSWin32.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Poll.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\Resource.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\Secret.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\Service.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSCore\uDNS.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\uds_daemon.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\Service.rc"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/SystemService/Service.vcxproj b/mDNSWindows/SystemService/Service.vcxproj
deleted file mode 100755 (executable)
index c0eb7a0..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectName>mDNSResponder</ProjectName>\r
-    <ProjectGuid>{C1D98254-BA27-4427-A3BE-A68CA2CC5F69}</ProjectGuid>\r
-    <RootNamespace>mDNSResponder</RootNamespace>\r
-    <Keyword>Win32Proj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>Application</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-      <ShowIncludes>false</ShowIncludes>\r
-      <PrecompiledHeaderFile>\r
-      </PrecompiledHeaderFile>\r
-      <PrecompiledHeaderOutputFile>\r
-      </PrecompiledHeaderOutputFile>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;crypt32.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
-      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)mDNSResponder.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\mDNSResponder.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_WIN32_WINNT=0x0501;DEBUG=1;MDNS_DEBUGMSGS=0;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;crypt32.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
-      <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)mDNSResponder.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\mDNSResponder64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;_USE_32BIT_TIME_T;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-      <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;crypt32.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\mDNSResponder.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)"   mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-if not exist "$(DSTROOT)\AppleInternal"                                                   mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin"                                            mkdir "$(DSTROOT)\AppleInternal\bin"\r
-xcopy /I/Y "$(TargetPath)"                                                                           "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetDir)$(TargetName).pdb"                                          "$(DSTROOT)\AppleInternal\bin"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSCore;../../mDNSShared;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;C:/Program Files/Microsoft SDKs/Windows/v6.1/Include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_WIN32_WINNT=0x0501;TARGET_OS_WIN32;WIN32_LEAN_AND_MEAN;USE_TCP_LOOPBACK;PLATFORM_NO_STRSEP;PLATFORM_NO_EPIPE;PLATFORM_NO_RLIMIT;PID_FILE="";UNICODE;_UNICODE;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;_LEGACY_NAT_TRAVERSAL_;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <DisableSpecificWarnings>4127;4201;%(DisableSpecificWarnings)</DisableSpecificWarnings>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>ws2_32.lib;iphlpapi.lib;netapi32.lib;powrprof.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mDNSResponder.exe</OutputFile>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Console</SubSystem>\r
-      <OptimizeReferences>true</OptimizeReferences>\r
-      <EnableCOMDATFolding>true</EnableCOMDATFolding>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-      <UACExecutionLevel>RequireAdministrator</UACExecutionLevel>\r
-    </Link>\r
-    <Manifest>\r
-      <AdditionalManifestFiles>res\mDNSResponder64.manifest;%(AdditionalManifestFiles)</AdditionalManifestFiles>\r
-    </Manifest>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)"   mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-if not exist "$(DSTROOT)\AppleInternal"                                                   mkdir "$(DSTROOT)\AppleInternal"\r
-if not exist "$(DSTROOT)\AppleInternal\bin"                                            mkdir "$(DSTROOT)\AppleInternal\bin"\r
-xcopy /I/Y "$(TargetPath)"                                                                           "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetDir)$(TargetName).pdb"                                          "$(DSTROOT)\AppleInternal\bin"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\mDNSCore\anonymous.c" />\r
-    <ClCompile Include="..\..\mDNSCore\CryptoAlg.c" />\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
-    <ClCompile Include="..\..\mDNSCore\DNSCommon.c" />\r
-    <ClCompile Include="..\..\mDNSCore\DNSDigest.c" />\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c" />\r
-    <ClCompile Include="Firewall.cpp" />\r
-    <ClCompile Include="..\..\mDNSShared\GenLinkedList.c" />\r
-    <ClCompile Include="..\..\mDNSMacOSX\LegacyNATTraversal.c" />\r
-    <ClCompile Include="main.c" />\r
-    <ClCompile Include="..\..\mDNSCore\mDNS.c" />\r
-    <ClCompile Include="..\..\mDNSShared\mDNSDebug.c" />\r
-    <ClCompile Include="..\mDNSWin32.c" />\r
-    <ClCompile Include="..\Poll.c" />\r
-    <ClCompile Include="..\Secret.c" />\r
-    <ClCompile Include="Service.c" />\r
-    <ClCompile Include="..\..\mDNSCore\uDNS.c" />\r
-    <ClCompile Include="..\..\mDNSShared\uds_daemon.c" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <CustomBuild Include="EventLog.mc">\r
-      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Compiling Message Resource</Message>\r
-      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">mc.exe EventLog.mc</Command>\r
-      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
-      <Message Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Compiling Message Resource</Message>\r
-      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">mc.exe EventLog.mc</Command>\r
-      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
-      <Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Compiling Message Resource</Message>\r
-      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">mc.exe EventLog.mc</Command>\r
-      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
-      <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Compiling Message Resource</Message>\r
-      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">mc.exe EventLog.mc</Command>\r
-      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">EventLog.rc EventLog.h;%(Outputs)</Outputs>\r
-    </CustomBuild>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\mDNSCore\anonymous.h" />\r
-    <ClInclude Include="..\..\mDNSCore\CryptoAlg.h" />\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
-    <ClInclude Include="..\..\mDNSCore\DNSCommon.h" />\r
-    <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h" />\r
-    <ClInclude Include="..\..\mDNSShared\GenLinkedList.h" />\r
-    <ClInclude Include="..\..\mDNSCore\mDNSDebug.h" />\r
-    <ClInclude Include="..\..\mDNSCore\mDNSEmbeddedAPI.h" />\r
-    <ClInclude Include="..\mDNSWin32.h" />\r
-    <ClInclude Include="..\Poll.h" />\r
-    <ClInclude Include="Resource.h" />\r
-    <ClInclude Include="..\Secret.h" />\r
-    <ClInclude Include="Service.h" />\r
-    <ClInclude Include="..\..\mDNSCore\uDNS.h" />\r
-    <ClInclude Include="..\..\mDNSShared\uds_daemon.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="Service.rc" />\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/SystemService/Service.vcxproj.filters b/mDNSWindows/SystemService/Service.vcxproj.filters
deleted file mode 100755 (executable)
index ba41b93..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSCore\DNSCommon.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSCore\DNSDigest.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\dnssd_ipc.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="Firewall.cpp">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\GenLinkedList.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSMacOSX\LegacyNATTraversal.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="main.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSCore\mDNS.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\mDNSDebug.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\mDNSWin32.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\Poll.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\Secret.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="Service.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSCore\uDNS.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\uds_daemon.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSCore\anonymous.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSCore\CryptoAlg.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSCore\DNSCommon.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\dnssd_ipc.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\GenLinkedList.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSCore\mDNSDebug.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSCore\mDNSEmbeddedAPI.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\mDNSWin32.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\Poll.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="Resource.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\Secret.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="Service.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSCore\uDNS.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\uds_daemon.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSCore\anonymous.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSCore\CryptoAlg.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="Service.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <CustomBuild Include="EventLog.mc">\r
-      <Filter>Source Files</Filter>\r
-    </CustomBuild>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/SystemService/main.c b/mDNSWindows/SystemService/main.c
deleted file mode 100755 (executable)
index 33cce9e..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "Service.h"
-
-
-//===========================================================================================================================
-//     main
-//===========================================================================================================================
-#if defined(UNICODE)
-int __cdecl wmain( int argc, wchar_t * argv[] )
-#else
-int    __cdecl main( int argc, char *argv[] )
-#endif
-{
-       return Main( argc, argv );
-}
-
diff --git a/mDNSWindows/SystemService/res/mDNSResponder.manifest b/mDNSWindows/SystemService/res/mDNSResponder.manifest
deleted file mode 100644 (file)
index 7275854..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-       <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.mDNSResponder" type="win32"/>
-       <description>Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network.</description>
-       <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
-               <security>
-                       <requestedPrivileges>
-                               <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
-                       </requestedPrivileges>
-               </security>
-       </trustInfo>
-</assembly>
diff --git a/mDNSWindows/SystemService/res/mDNSResponder64.manifest b/mDNSWindows/SystemService/res/mDNSResponder64.manifest
deleted file mode 100644 (file)
index 13b3998..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-       <assemblyIdentity version="1.0.0.0" processorArchitecture="X86" name="Apple.Bonjour.ControlPanel" type="win32"/>
-       <description>Enables hardware devices and software services to automatically configure themselves and advertise their presence on the network.</description>
-       <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
-               <security>
-                       <requestedPrivileges>
-                               <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
-                       </requestedPrivileges>
-               </security>
-       </trustInfo>
-</assembly>
diff --git a/mDNSWindows/SystemService/resource.h b/mDNSWindows/SystemService/resource.h
deleted file mode 100644 (file)
index d968af9..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Service.rc
-//
-
-#define IDS_SERVICE_DESCRIPTION        100
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        101
-#define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1000
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/mDNSWindows/SystemService/resrc1.h b/mDNSWindows/SystemService/resrc1.h
deleted file mode 100644 (file)
index 54a6524..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by Service.rc
-//
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        101
-#define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1000
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/mDNSWindows/VPCDetect.cpp b/mDNSWindows/VPCDetect.cpp
deleted file mode 100755 (executable)
index 3df7c14..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define _WIN32_DCOM
-#include "VPCDetect.h"
-#include "DebugServices.h"
-#include <comdef.h>
-#include <Wbemidl.h>
-
-# pragma comment(lib, "wbemuuid.lib")
-
-static BOOL g_doneCheck = FALSE;
-static BOOL g_isVPC            = FALSE;
-
-
-mStatus
-IsVPCRunning( BOOL * inVirtualPC )
-{
-       IWbemLocator                    *       pLoc            = 0;
-       IWbemServices                   *       pSvc            = 0;
-    IEnumWbemClassObject       *       pEnumerator = NULL;
-       bool                                            coInit          = false;
-       HRESULT                                         hres;
-       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, 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, 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, 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, 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, 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, err = kUnknownErr );
-
-       do
-       {
-               IWbemClassObject* pInstance = NULL;
-               ULONG dwCount = NULL;
-
-               hres = pEnumerator->Next( WBEM_INFINITE, 1, &pInstance, &dwCount);
-
-               if ( pInstance )
-               {
-                       VARIANT v;
-                       BSTR strClassProp = SysAllocString(L"Manufacturer");
-                       HRESULT hr;
-
-                       hr = pInstance->Get(strClassProp, 0, &v, 0, 0);
-                       SysFreeString(strClassProp);
-
-                       // check the HRESULT to see if the action succeeded.
-
-                       if (SUCCEEDED(hr) && (V_VT(&v) == VT_BSTR))
-                       {
-                               wchar_t * wstring = wcslwr( V_BSTR( &v ) );
-
-                               if (wcscmp( wstring, L"microsoft corporation" ) == 0 )
-                               {
-                                       *inVirtualPC = TRUE;
-                               }
-                       }
-               
-                       VariantClear(&v);
-               }
-       } while (hres == WBEM_S_NO_ERROR);
-         
-exit:
-       if ( pSvc != NULL )
-       {
-       pSvc->Release();
-       }
-
-       if ( pLoc != NULL )
-       {
-       pLoc->Release();     
-       }
-
-       if ( coInit )
-       {
-       CoUninitialize();
-       }
-
-       if ( service )
-       {
-               CloseServiceHandle( service );
-       }
-
-       if ( scm )
-       {
-               CloseServiceHandle( scm );
-       }
-
-       if ( *inVirtualPC )
-       {
-               dlog( kDebugLevelTrace, "Virtual PC detected" );
-       }
-
-       return err;
-}
diff --git a/mDNSWindows/VPCDetect.h b/mDNSWindows/VPCDetect.h
deleted file mode 100644 (file)
index 9f34bee..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <windows.h>
-#include <mDNSEmbeddedAPI.h>
-
-
-#if defined(__cplusplus)
-extern "C"
-{
-#endif
-
-
-extern mStatus
-IsVPCRunning( BOOL * inVirtualPC );
-
-
-#if defined(__cplusplus)
-}
-#endif
diff --git a/mDNSWindows/WinServices.cpp b/mDNSWindows/WinServices.cpp
deleted file mode 100644 (file)
index e47c468..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-/* -*- 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.
- */
-
-#include "WinServices.h"
-#include <DebugServices.h>
-
-
-//===========================================================================================================================
-//     UTF8StringToStringObject
-//===========================================================================================================================
-
-OSStatus       UTF8StringToStringObject( const char *inUTF8, CString &inObject )
-{
-       OSStatus                err;
-       int                             n;
-       BSTR                    unicode;
-       
-       unicode = NULL;
-       
-       n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, NULL, 0 );
-       if( n > 0 )
-       {
-               unicode = (BSTR) malloc( (size_t)( n * sizeof( wchar_t ) ) );
-               if( !unicode )
-               {
-                       err = ERROR_INSUFFICIENT_BUFFER;
-                       goto exit;
-               }
-
-               n = MultiByteToWideChar( CP_UTF8, 0, inUTF8, -1, unicode, n );
-               try
-               {
-                       inObject = unicode;
-               }
-               catch( ... )
-               {
-                       err = ERROR_NO_UNICODE_TRANSLATION;
-                       goto exit;
-               }
-       }
-       else
-       {
-               inObject = "";
-       }
-       err = ERROR_SUCCESS;
-       
-exit:
-       if( unicode )
-       {
-               free( unicode );
-       }
-       return( err );
-}
-
-
-//===========================================================================================================================
-//     UTF8StringToStringObject
-//===========================================================================================================================
-
-OSStatus
-StringObjectToUTF8String( CString &inObject, char* outUTF8, size_t outUTF8Len )
-{
-    OSStatus err = kNoErr;
-
-       memset( outUTF8, 0, outUTF8Len );
-
-       if ( inObject.GetLength() > 0 )
-    {
-               size_t size;
-
-               size = (size_t) WideCharToMultiByte( CP_UTF8, 0, inObject.GetBuffer(), inObject.GetLength(), outUTF8, (int) outUTF8Len, NULL, NULL);
-        err = translate_errno( size != 0, GetLastError(), kUnknownErr );
-        require_noerr( err, exit );
-    }
-
-exit:
-
-       return err;
-}
diff --git a/mDNSWindows/WinServices.h b/mDNSWindows/WinServices.h
deleted file mode 100644 (file)
index f650d1d..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* -*- 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.
- */
-
-
-#pragma once
-
-#include <afxwin.h>         // MFC core and standard components
-#include <afxext.h>         // MFC extensions
-#include <afxdtctl.h>          // MFC support for Internet Explorer 4 Common Controls
-#ifndef _AFX_NO_AFXCMN_SUPPORT
-#      include <afxcmn.h>              // MFC support for Windows Common Controls
-#endif
-
-#include <winsock2.h>
-#include <afxsock.h>           // MFC socket extensions
-#include "CommonServices.h"
-
-
-OSStatus       UTF8StringToStringObject( const char *inUTF8, CString &outObject );
-OSStatus       StringObjectToUTF8String( CString &inObject, char* outUTF8, size_t outUTF8Len );
diff --git a/mDNSWindows/WinVersRes.h b/mDNSWindows/WinVersRes.h
deleted file mode 100644 (file)
index 382bba4..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- Mode: C; 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.
- */
-
-#ifndef WINRESVERS_H
-#define WINRESVERS_H
-
-#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               3,1,0,2
-#define MASTER_PROD_VERS_STR   "3,1,0,2"
-#define MASTER_PROD_VERS_STR2  "3.1.0.2"
-#define MASTER_PROD_VERS_STR3 "Explorer Plugin 3.1.0.2"
-
-// Define the legal copyright
-#define MASTER_LEGAL_COPYRIGHT "Copyright (C) 2003-2011 Apple Inc."
-
-#endif // WINRESVERS_H
diff --git a/mDNSWindows/isocode.h b/mDNSWindows/isocode.h
deleted file mode 100755 (executable)
index fe04f31..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* isocode.h                                                             */
-/* ----------------------------------------------------------------------*/
-/* THIS FILE HAS BEEN AUTO-GENERATED.  DO NOT EDIT DIRECTLY              */
-/* If a language needs to be added, edit isocode.txt, and run isocode.pl */
-/* to generate a new version of this file                                */
-/* ----------------------------------------------------------------------*/
-/* ----------------------------------------------------------------------*/
-
-
-unsigned char ISOCODES[] = {
-12, 9, 'e','n', 0 , 0 , 0 , 0 ,
-40, 9, 'e','n', 0 , 0 , 0 , 0 ,
-16, 9, 'e','n', 0 , 0 , 0 , 0 ,
-36, 9, 'e','n', 0 , 0 , 0 , 0 ,
-24, 9, 'e','n', 0 , 0 , 0 , 0 ,
-32, 9, 'e','n', 0 , 0 , 0 , 0 ,
-20, 9, 'e','n', 0 , 0 , 0 , 0 ,
-52, 9, 'e','n', 0 , 0 , 0 , 0 ,
-28, 9, 'e','n', 0 , 0 , 0 , 0 ,
-44, 9, 'e','n', 0 , 0 , 0 , 0 ,
-8, 9, 'e','n', 0 , 0 , 0 , 0 ,
-4, 9, 'e','n', 0 , 0 , 0 , 0 ,
-48, 9, 'e','n', 0 , 0 , 0 , 0 ,
-8, 12, 'f','r', 0 , 0 , 0 , 0 ,
-44, 12, 'f','r', 0 , 0 , 0 , 0 ,
-12, 12, 'f','r', 0 , 0 , 0 , 0 ,
-36, 12, 'f','r', 0 , 0 , 0 , 0 ,
-48, 12, 'f','r', 0 , 0 , 0 , 0 ,
-4, 12, 'f','r', 0 , 0 , 0 , 0 ,
-20, 12, 'f','r', 0 , 0 , 0 , 0 ,
-52, 12, 'f','r', 0 , 0 , 0 , 0 ,
-24, 12, 'f','r', 0 , 0 , 0 , 0 ,
-40, 12, 'f','r', 0 , 0 , 0 , 0 ,
-16, 12, 'f','r', 0 , 0 , 0 , 0 ,
-28, 12, 'f','r', 0 , 0 , 0 , 0 ,
-4, 98, 'f','r', 0 , 0 , 0 , 0 ,
-12, 7, 'd','e', 0 , 0 , 0 , 0 ,
-4, 7, 'd','e', 0 , 0 , 0 , 0 ,
-20, 7, 'd','e', 0 , 0 , 0 , 0 ,
-16, 7, 'd','e', 0 , 0 , 0 , 0 ,
-8, 7, 'd','e', 0 , 0 , 0 , 0 ,
-4, 17, 'j','a', 0 , 0 , 0 , 0 ,
-8, 19, 'n','l', 0 , 0 , 0 , 0 ,
-4, 19, 'n','l', 0 , 0 , 0 , 0 ,
-4, 16, 'i','t', 0 , 0 , 0 , 0 ,
-8, 16, 'i','t', 0 , 0 , 0 , 0 ,
-44, 10, 'e','s', 0 , 0 , 0 , 0 ,
-64, 10, 'e','s', 0 , 0 , 0 , 0 ,
-52, 10, 'e','s', 0 , 0 , 0 , 0 ,
-36, 10, 'e','s', 0 , 0 , 0 , 0 ,
-20, 10, 'e','s', 0 , 0 , 0 , 0 ,
-28, 10, 'e','s', 0 , 0 , 0 , 0 ,
-48, 10, 'e','s', 0 , 0 , 0 , 0 ,
-68, 10, 'e','s', 0 , 0 , 0 , 0 ,
-16, 10, 'e','s', 0 , 0 , 0 , 0 ,
-72, 10, 'e','s', 0 , 0 , 0 , 0 ,
-12, 10, 'e','s', 0 , 0 , 0 , 0 ,
-8, 10, 'e','s', 0 , 0 , 0 , 0 ,
-76, 10, 'e','s', 0 , 0 , 0 , 0 ,
-24, 10, 'e','s', 0 , 0 , 0 , 0 ,
-60, 10, 'e','s', 0 , 0 , 0 , 0 ,
-40, 10, 'e','s', 0 , 0 , 0 , 0 ,
-80, 10, 'e','s', 0 , 0 , 0 , 0 ,
-4, 10, 'e','s', 0 , 0 , 0 , 0 ,
-56, 10, 'e','s', 0 , 0 , 0 , 0 ,
-32, 10, 'e','s', 0 , 0 , 0 , 0 ,
-8, 4, 'z','h','_','C','N', 0 ,
-16, 4, 'z','h','_','C','N', 0 ,
-12, 4, 'z','h','_','T','W', 0 ,
-20, 4, 'z','h','_','T','W', 0 ,
-4, 4, 'z','h','_','T','W', 0 ,
-4, 6, 'd','a', 0 , 0 , 0 , 0 ,
-4, 11, 'f','i', 0 , 0 , 0 , 0 ,
-4, 18, 'k','o', 0 , 0 , 0 , 0 ,
-4, 20, 'n','b', 0 , 0 , 0 , 0 ,
-8, 20, 'n','b', 0 , 0 , 0 , 0 ,
-4, 22, 'p','t', 0 , 0 , 0 , 0 ,
-4, 29, 's','v', 0 , 0 , 0 , 0 ,
-8, 29, 's','v', 0 , 0 , 0 , 0 ,
-20, 1, 'a','r', 0 , 0 , 0 , 0 ,
-60, 1, 'a','r', 0 , 0 , 0 , 0 ,
-12, 1, 'a','r', 0 , 0 , 0 , 0 ,
-8, 1, 'a','r', 0 , 0 , 0 , 0 ,
-44, 1, 'a','r', 0 , 0 , 0 , 0 ,
-52, 1, 'a','r', 0 , 0 , 0 , 0 ,
-48, 1, 'a','r', 0 , 0 , 0 , 0 ,
-16, 1, 'a','r', 0 , 0 , 0 , 0 ,
-24, 1, 'a','r', 0 , 0 , 0 , 0 ,
-32, 1, 'a','r', 0 , 0 , 0 , 0 ,
-64, 1, 'a','r', 0 , 0 , 0 , 0 ,
-4, 1, 'a','r', 0 , 0 , 0 , 0 ,
-40, 1, 'a','r', 0 , 0 , 0 , 0 ,
-28, 1, 'a','r', 0 , 0 , 0 , 0 ,
-56, 1, 'a','r', 0 , 0 , 0 , 0 ,
-36, 1, 'a','r', 0 , 0 , 0 , 0 ,
-4, 2, 'b','g', 0 , 0 , 0 , 0 ,
-4, 26, 'h','r', 0 , 0 , 0 , 0 ,
-4, 5, 'c','s', 0 , 0 , 0 , 0 ,
-4, 8, 'e','l', 0 , 0 , 0 , 0 ,
-4, 13, 'i','w', 0 , 0 , 0 , 0 ,
-4, 14, 'h','u', 0 , 0 , 0 , 0 ,
-4, 15, 'i','s', 0 , 0 , 0 , 0 ,
-4, 21, 'p','l', 0 , 0 , 0 , 0 ,
-8, 22, 'p','t','_','P','T', 0 ,
-4, 24, 'r','o', 0 , 0 , 0 , 0 ,
-8, 24, 'r','o', 0 , 0 , 0 , 0 ,
-4, 25, 'r','u', 0 , 0 , 0 , 0 ,
-8, 25, 'r','u', 0 , 0 , 0 , 0 ,
-4, 30, 't','h', 0 , 0 , 0 , 0 ,
-4, 31, 't','r', 0 , 0 , 0 , 0 ,
-4, 34, 'u','k', 0 , 0 , 0 , 0 ,
-};
-
-#define NUM_ISOCODES      101
-#define LANG_CODE_LEN     5
-#define MODULO_ISOCODES   8
-
-
diff --git a/mDNSWindows/loclibrary.c b/mDNSWindows/loclibrary.c
deleted file mode 100755 (executable)
index 9744120..0000000
+++ /dev/null
@@ -1,268 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-    
-/* loclibrary.c                                                          
- * ----------------------------------------------------------------------
- * Source for localization library                                       
- * Originally created by jsantamaria: 3 may 2004                         
- * ----------------------------------------------------------------------
- */
-#include "DebugServices.h"
-#include <windows.h>
-#include <stdio.h>
-#include "isocode.h"
-#include "loclibrary.h"
-#include "Shlwapi.h"
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <wchar.h>
-
-
-#ifdef __cplusplus
-extern "c" {
-#endif
-
-#ifdef _MSC_VER
-#define swprintf _snwprintf
-#define snprintf _snprintf
-#endif
-
-
-
-#define DEFAULT_LANG_CODE "en"
-
-// gets the user language
-static LANGID _getUserLanguage( void ) {
-       
-       return GetUserDefaultUILanguage();
-
-}
-
-
-// gets the ISO mapping
-static int _getISOCode(LANGID wLangID, char *isoLangCode, int codeLen) {
-       int i;
-       unsigned short langCode;
-
-       for (i = 0; i < NUM_ISOCODES; i++) {
-               int startIndex = i * MODULO_ISOCODES;
-               
-               langCode = (ISOCODES[startIndex] << 8);
-               langCode = langCode + ( (unsigned short) (ISOCODES[startIndex + 1]) );
-
-               if (langCode == wLangID) {
-                       char *langStr = (char *)&(ISOCODES[startIndex+2]);
-                       strncpy(isoLangCode, langStr, codeLen);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-static char isoLangCode[LANG_CODE_LEN + 1] = "";
-static LANGID wLangID = (LANGID) -1;
-
-static void _setLanguageIfNeeded(void) {
-       
-       // get the language code if we don't have it cached
-       if (!strncmp(isoLangCode,"",LANG_CODE_LEN + 1)) {
-               
-               // if we haven't cached the language id, do the lookup
-               if (wLangID == (LANGID) -1) {
-                       wLangID = _getUserLanguage();
-               }
-               
-               // if no ISOCode, set it to DEFAULT_LANG_CODE
-               if (_getISOCode(wLangID, isoLangCode, LANG_CODE_LEN + 1)) {
-                       strncpy(isoLangCode, DEFAULT_LANG_CODE, LANG_CODE_LEN+1);
-               }
-       }
-
-}
-
-//// PathForResource
-
-// Gets the PathForResource for handle 0 for the current process
-
-
-static char appPathNameA[MAX_PATH] = "";
-
-int PathForResourceA ( HMODULE module, const char *name, char *locFile, int locFileLen)
-{
-       int ret = 0;
-
-       if ( !strcmp( appPathNameA, "" ) )
-       {
-               char   folder[MAX_PATH];
-               char * ext;
-               char * app;
-
-               GetModuleFileNameA( module, folder, MAX_PATH );
-
-               // Get folder string
-               
-               app = strrchr( folder, '\\' );
-               require_action( app, exit, ret = 0 );
-               *app++ = '\0';
-
-               // Strip the extension
-
-               if ( ( ( ext = strstr( app, ".exe" ) ) != NULL ) || ( ( ext = strstr( app, ".dll" ) ) != NULL ) )
-               {
-                       *ext = '\0';
-               }
-
-               snprintf( appPathNameA, MAX_PATH, "%s\\%s", folder, app );
-       }
-
-       ret = PathForResourceWithPathA (appPathNameA, name, locFile, locFileLen);
-
-exit:
-
-       return ret;
-}
-
-static wchar_t appPathNameW[MAX_PATH] = L"";
-
-int PathForResourceW ( HMODULE module, const wchar_t *name, wchar_t *locFile, int locFileLen)
-{
-       int ret = 0;
-
-       if ( !wcscmp( appPathNameW, L"" ) )
-       {
-               wchar_t   folder[MAX_PATH];
-               wchar_t * app;
-               wchar_t * ext;
-
-               GetModuleFileNameW( module, folder, MAX_PATH);
-
-               // Get folder string
-               
-               app = wcsrchr( folder, '\\' );
-               require_action( app, exit, ret = 0 );
-               *app++ = '\0';
-
-               // Strip the extension
-
-               if ( ( ( ext = wcsstr( app, L".exe" ) ) != NULL ) || ( ( ext = wcsstr( app, L".dll" ) ) != NULL ) )
-               {
-                       *ext = '\0';
-               }
-
-               swprintf( appPathNameW, MAX_PATH, L"%ls\\%ls", folder, app );
-       }
-
-       ret = PathForResourceWithPathW (appPathNameW, name, locFile, locFileLen);
-
-exit:
-
-       return ret;
-}
-
-
-//// PathForResourceWithPath
-
-#define TMP_BUF_SIZE MAX_PATH
-
-int PathForResourceWithPathA (const char *path, const char *nm, 
-                                                                       char *locFile, int locFileLen) {
-       char tmpBuffer[TMP_BUF_SIZE];
-
-       // build the path to the executable in the generic 
-       // resources folder, check there first
-       snprintf(tmpBuffer, MAX_PATH, "%s.Resources\\%s", path, nm);
-
-       if (!PathFileExistsA(tmpBuffer)) {
-
-               // didn't hit generic resource folder, so need to get language codes
-               _setLanguageIfNeeded();
-
-               // test to see if localized directory exists, 
-               // if so, we don't fall back if we don't find the file.
-               snprintf(tmpBuffer, TMP_BUF_SIZE, 
-                                "%s.Resources\\%s.lproj", path, isoLangCode);
-
-               if (PathFileExistsA(tmpBuffer)) {
-                       snprintf(tmpBuffer, TMP_BUF_SIZE, "%s\\%s", tmpBuffer, nm);
-
-                       if (!PathFileExistsA(tmpBuffer)) return 0;
-
-                       strncpy(locFile, tmpBuffer, locFileLen);
-                       return (int) strlen(locFile);
-               }
-
-               // fall back on DEFAULT_LANG_CODE if still no good
-               snprintf(tmpBuffer, TMP_BUF_SIZE, "%s.Resources\\%s.lproj\\%s", 
-                               path, DEFAULT_LANG_CODE, nm);
-                               
-               // we can't find the resource, so return 0
-               if (!PathFileExistsA(tmpBuffer)) return 0;
-       }
-       
-       strncpy(locFile, tmpBuffer, locFileLen);
-       return (int) strlen(locFile);
-
-}
-
-
-int PathForResourceWithPathW (const wchar_t *path, const wchar_t *nm, 
-                                                               wchar_t *locFile, int locFileLen) {
-
-       wchar_t tmpBuffer[TMP_BUF_SIZE];
-
-       // build the path to the executable in the generic
-       // resources folder, check there first
-       swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls.Resources\\%ls", path, nm);
-
-       if (!PathFileExistsW(tmpBuffer)) {
-               // didn't hit generic resource folder, so need to get language codes
-               _setLanguageIfNeeded();
-
-               // test to see if localized directory exists, 
-               // if so, we don't fall back if we don't find the file.
-               swprintf(tmpBuffer, TMP_BUF_SIZE, 
-                                 L"%ls.Resources\\%S.lproj", path, isoLangCode);
-
-               if (PathFileExistsW(tmpBuffer)) {
-                       swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls\\%ls", tmpBuffer, nm);
-
-                       if (!PathFileExistsW(tmpBuffer)) return 0;
-
-                       wcsncpy(locFile, tmpBuffer, locFileLen);
-                       return (int) wcslen(locFile);
-               }
-
-               // fall back on DEFAULT_LANG_CODE if still no good
-               swprintf(tmpBuffer, TMP_BUF_SIZE, L"%ls.Resources\\%S.lproj\\%ls", 
-                       path, DEFAULT_LANG_CODE, nm);
-
-               // we can't find the resource, so return 0
-               if (!PathFileExistsW(tmpBuffer)) return 0;
-       }
-       
-       wcsncpy(locFile, tmpBuffer, locFileLen);
-       return (int) wcslen(locFile);
-
-
-}
-
-
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/mDNSWindows/loclibrary.h b/mDNSWindows/loclibrary.h
deleted file mode 100755 (executable)
index 0a9b7ce..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-    
-/* loclibrary.h                                                      
- * ----------------------------------------------------------------------
- * Header file for localization library                                       
- * Originally created by jsantamaria: 3 may 2004                         
- * ----------------------------------------------------------------------
- */
-#ifndef _loclibrary_h_
-#define _loclibrary_h_
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif // __cplusplus
-
-int PathForResourceW ( HMODULE module, const wchar_t *name, wchar_t *locFile, int locFileLen);
-int PathForResourceWithPathW ( const wchar_t *path, const wchar_t *name, wchar_t *locFile, int locFileLen);
-
-int PathForResourceA ( HMODULE module, const char *name, char *locFile, int locFileLen);
-int PathForResourceWithPathA ( const char *path, const char *name, char *locFile, int locFileLen);
-
-
-#ifdef UNICODE
-#define PathForResource PathForResourceW
-#define PathForResourceWithPath PathForResourceWithPathW
-#else
-#define PathForResource PathForResourceA
-#define PathForResourceWithPath PathForResourceWithPathA
-#endif // UNICODE
-
-
-#ifdef __cplusplus
-}
-#endif // __cplusplus
-
-
-#endif // _loclibrary_h_
diff --git a/mDNSWindows/mDNSWin32.c b/mDNSWindows/mDNSWin32.c
deleted file mode 100755 (executable)
index 6e88056..0000000
+++ /dev/null
@@ -1,5120 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2013, 2015 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.
-
-       To Do:
-       
-       - Get unicode name of machine for nice name instead of just the host name.
-       - 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). 
-
-*/
-
-#define _CRT_RAND_S
-
-#include       <stdarg.h>
-#include       <stddef.h>
-#include       <stdio.h>
-#include       <stdlib.h>
-#include       <crtdbg.h>
-#include       <string.h>
-
-#include       "Poll.h"
-#include       "CommonServices.h"
-#include       "DebugServices.h"
-#include       "Firewall.h"
-#include       "RegNames.h"
-#include       "Secret.h"
-#include       <dns_sd.h>
-
-#include       <Iphlpapi.h>
-#include       <mswsock.h>
-#include       <process.h>
-#include       <ntsecapi.h>
-#include       <lm.h>
-#include       <winioctl.h>
-#include       <ntddndis.h>        // This defines the IOCTL constants.
-
-#include       "mDNSEmbeddedAPI.h"
-#include       "GenLinkedList.h"
-#include       "DNSCommon.h"
-#include       "mDNSWin32.h"
-#include    "dnssec.h"
-#include    "nsec.h"
-
-#if 0
-#pragma mark == Constants ==
-#endif
-
-//===========================================================================================================================
-//     Constants
-//===========================================================================================================================
-
-#define        DEBUG_NAME                                                                      "[mDNSWin32] "
-
-#define        MDNS_WINDOWS_USE_IPV6_IF_ADDRS                          1
-#define        MDNS_WINDOWS_ENABLE_IPV4                                        1
-#define        MDNS_WINDOWS_ENABLE_IPV6                                        1
-#define        MDNS_FIX_IPHLPAPI_PREFIX_BUG                            1
-#define MDNS_SET_HINFO_STRINGS                                         0
-
-#define        kMDNSDefaultName                                                        "My Computer"
-
-#define        kWinSockMajorMin                                                        2
-#define        kWinSockMinorMin                                                        2
-
-#define kRegistryMaxKeyLength                                          255
-#define kRegistryMaxValueName                                          16383
-
-static GUID                                                                                    kWSARecvMsgGUID = WSAID_WSARECVMSG;
-
-#define kIPv6IfIndexBase                                                       (10000000L)
-#define SMBPortAsNumber                                                                445
-#define DEVICE_PREFIX                                                          "\\\\.\\"
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-mDNSlocal mStatus                      SetupNiceName( mDNS * const inMDNS );
-mDNSlocal mStatus                      SetupHostName( mDNS * const inMDNS );
-mDNSlocal mStatus                      SetupName( mDNS * const inMDNS );
-mDNSlocal mStatus                      SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD );
-mDNSlocal mStatus                      TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD );
-mDNSlocal void CALLBACK                FreeInterface( mDNSInterfaceData *inIFD );
-mDNSlocal mStatus                      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  );
-mDNSlocal mStatus                      SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort );
-mDNSlocal OSStatus                     GetWindowsVersionString( char *inBuffer, size_t inBufferSize );
-mDNSlocal int                          getifaddrs( struct ifaddrs **outAddrs );
-mDNSlocal void                         freeifaddrs( struct ifaddrs *inAddrs );
-
-
-// Platform Accessors
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-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 );
-
-
-// Wakeup Structs
-
-#define kMulticastWakeupNumTries                       ( 18 )
-#define kMulticastWakeupSleepBetweenTries      ( 100 )
-
-typedef struct MulticastWakeupStruct
-{
-       mDNS                                    *inMDNS;
-       struct sockaddr_in              addr;
-       INT                                             addrLen;
-       unsigned char                   data[ 102 ];
-       INT                                             dataLen;
-       INT                                             numTries;
-       INT                                             msecSleep;
-} MulticastWakeupStruct;
-
-
-// Utilities
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-       mDNSlocal int   getifaddrs_ipv6( struct ifaddrs **outAddrs );
-#endif
-
-mDNSlocal int getifaddrs_ipv4( struct ifaddrs **outAddrs );
-
-mDNSlocal DWORD                                GetPrimaryInterface();
-mDNSlocal mStatus                      AddressToIndexAndMask( struct sockaddr * address, uint32_t * index, struct sockaddr * mask );
-mDNSlocal mDNSBool                     CanReceiveUnicast( void );
-mDNSlocal mDNSBool                     IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr );
-
-mDNSlocal mStatus                      StringToAddress( mDNSAddr * ip, LPSTR string );
-mDNSlocal mStatus                      RegQueryString( HKEY key, LPCSTR param, LPSTR * string, DWORD * stringLen, DWORD * enabled );
-mDNSlocal struct ifaddrs*      myGetIfAddrs(int refresh);
-mDNSlocal OSStatus                     TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal OSStatus                     WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize );
-mDNSlocal void CALLBACK                TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-mDNSlocal void                         TCPCloseSocket( TCPSocket * socket );
-mDNSlocal void CALLBACK                UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context );
-mDNSlocal void                         UDPCloseSocket( UDPSocket * sock );
-mDNSlocal mStatus           SetupAddr(mDNSAddr *ip, const struct sockaddr *const sa);
-mDNSlocal void                         GetDDNSFQDN( domainname *const fqdn );
-#ifdef UNICODE
-mDNSlocal void                         GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey );
-#else
-mDNSlocal void                         GetDDNSDomains( DNameListElem ** domains, LPCSTR lpSubKey );
-#endif
-mDNSlocal void                         SetDomainSecrets( mDNS * const inMDNS );
-mDNSlocal void                         SetDomainSecret( mDNS * const m, const domainname * inDomain );
-mDNSlocal VOID CALLBACK                CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue );
-mDNSlocal void                         CheckFileShares( mDNS * const inMDNS );
-mDNSlocal void                         SMBCallback(mDNS *const m, ServiceRecordSet *const srs, mStatus result);
-mDNSlocal mDNSu8                       IsWOMPEnabledForAdapter( const char * adapterName );
-mDNSlocal void                         SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep );
-mDNSlocal void _cdecl          SendMulticastWakeupPacket( void *arg );
-
-#ifdef __cplusplus
-       }
-#endif
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-mDNSlocal mDNS_PlatformSupport gMDNSPlatformSupport;
-mDNSs32                                                        mDNSPlatformOneSecond   = 0;
-mDNSlocal UDPSocket            *               gUDPSockets                             = NULL;
-mDNSlocal int                                  gUDPNumSockets                  = 0;
-mDNSlocal BOOL                                 gEnableIPv6                             = TRUE;
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-
-       typedef DWORD
-               ( WINAPI * GetAdaptersAddressesFunctionPtr )( 
-                       ULONG                                   inFamily, 
-                       DWORD                                   inFlags, 
-                       PVOID                                   inReserved, 
-                       PIP_ADAPTER_ADDRESSES   inAdapter, 
-                       PULONG                                  outBufferSize );
-
-       mDNSlocal HMODULE                                                               gIPHelperLibraryInstance                        = NULL;
-       mDNSlocal GetAdaptersAddressesFunctionPtr               gGetAdaptersAddressesFunctionPtr        = NULL;
-
-#endif
-
-#ifndef HCRYPTPROV
-   typedef ULONG_PTR HCRYPTPROV;    // WinCrypt.h, line 249
-#endif
-
-#ifndef CRYPT_MACHINE_KEYSET
-#      define CRYPT_MACHINE_KEYSET    0x00000020
-#endif
-
-#ifndef CRYPT_NEWKEYSET
-#      define CRYPT_NEWKEYSET         0x00000008
-#endif
-
-#ifndef PROV_RSA_FULL
-#  define PROV_RSA_FULL 1
-#endif
-
-typedef BOOL (__stdcall *fnCryptGenRandom)( HCRYPTPROV, DWORD, BYTE* ); 
-typedef BOOL (__stdcall *fnCryptAcquireContext)( HCRYPTPROV*, LPCTSTR, LPCTSTR, DWORD, DWORD);
-typedef BOOL (__stdcall *fnCryptReleaseContext)(HCRYPTPROV, DWORD);
-
-static fnCryptAcquireContext g_lpCryptAcquireContext   = NULL;
-static fnCryptReleaseContext g_lpCryptReleaseContext   = NULL;
-static fnCryptGenRandom                 g_lpCryptGenRandom             = NULL;
-static HINSTANCE                        g_hAAPI32                                      = NULL;
-static HCRYPTPROV                       g_hProvider                            = ( ULONG_PTR ) NULL;
-
-
-typedef DNSServiceErrorType ( DNSSD_API *DNSServiceRegisterFunc )
-    (
-    DNSServiceRef                       *sdRef,
-    DNSServiceFlags                     flags,
-    uint32_t                            interfaceIndex,
-    const char                          *name,         /* may be NULL */
-    const char                          *regtype,
-    const char                          *domain,       /* may be NULL */
-    const char                          *host,         /* may be NULL */
-    uint16_t                            port,
-    uint16_t                            txtLen,
-    const void                          *txtRecord,    /* may be NULL */
-    DNSServiceRegisterReply             callBack,      /* may be NULL */
-    void                                *context       /* may be NULL */
-    );
-
-
-typedef void ( DNSSD_API *DNSServiceRefDeallocateFunc )( DNSServiceRef sdRef );
-
-mDNSlocal HMODULE                                      gDNSSDLibrary                           = NULL;
-mDNSlocal DNSServiceRegisterFunc       gDNSServiceRegister                     = NULL;
-mDNSlocal DNSServiceRefDeallocateFunc gDNSServiceRefDeallocate = NULL;
-mDNSlocal HANDLE                                       gSMBThread                                      = NULL;
-mDNSlocal HANDLE                                       gSMBThreadRegisterEvent         = NULL;
-mDNSlocal HANDLE                                       gSMBThreadDeregisterEvent       = NULL;
-mDNSlocal HANDLE                                       gSMBThreadStopEvent                     = NULL;
-mDNSlocal HANDLE                                       gSMBThreadQuitEvent                     = NULL;
-
-#define        kSMBStopEvent                           ( WAIT_OBJECT_0 + 0 )
-#define        kSMBRegisterEvent                       ( WAIT_OBJECT_0 + 1 )
-#define kSMBDeregisterEvent                    ( WAIT_OBJECT_0 + 2 )
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Support ==
-#endif
-
-//===========================================================================================================================
-//     mDNSPlatformInit
-//===========================================================================================================================
-
-mDNSexport mStatus     mDNSPlatformInit( mDNS * const inMDNS )
-{
-       mStatus         err;
-       OSVERSIONINFO osInfo;
-       BOOL ok;
-       WSADATA         wsaData;
-       int                     supported;
-       struct sockaddr_in      sa4;
-       struct sockaddr_in6 sa6;
-       int                                     sa4len;
-       int                                     sa6len;
-       DWORD                           size;
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "platform init\n" );
-       
-       // Initialize variables. If the PlatformSupport pointer is not null then just assume that a non-Apple client is 
-       // calling mDNS_Init and wants to provide its own storage for the platform-specific data so do not overwrite it.
-       
-       mDNSPlatformMemZero( &gMDNSPlatformSupport, sizeof( gMDNSPlatformSupport ) );
-       if( !inMDNS->p ) inMDNS->p                              = &gMDNSPlatformSupport;
-       inMDNS->p->mainThread                                   = OpenThread( THREAD_ALL_ACCESS, FALSE, GetCurrentThreadId() );
-       require_action( inMDNS->p->mainThread, exit, err = mStatus_UnknownErr );
-       inMDNS->p->checkFileSharesTimer = CreateWaitableTimer( NULL, FALSE, NULL );
-       require_action( inMDNS->p->checkFileSharesTimer, exit, err = mStatus_UnknownErr );
-       inMDNS->p->checkFileSharesTimeout               = 10;           // Retry time for CheckFileShares() in seconds
-       mDNSPlatformOneSecond                                   = 1000;         // Use milliseconds as the quantum of time
-       
-       // Get OS version info
-       
-       osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
-       ok = GetVersionEx( &osInfo );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       inMDNS->p->osMajorVersion = osInfo.dwMajorVersion;
-       inMDNS->p->osMinorVersion = osInfo.dwMinorVersion;
-       
-       // Don't enable IPv6 on anything less recent than Windows Vista
-
-       if ( inMDNS->p->osMajorVersion < 6 )
-       {
-               gEnableIPv6 = FALSE;
-       }
-
-       // Startup WinSock 2.2 or later.
-       
-       err = WSAStartup( MAKEWORD( kWinSockMajorMin, kWinSockMinorMin ), &wsaData );
-       require_noerr( err, exit );
-       
-       supported = ( ( LOBYTE( wsaData.wVersion ) == kWinSockMajorMin ) && ( HIBYTE( wsaData.wVersion ) == kWinSockMinorMin ) );
-       require_action( supported, exit, err = mStatus_UnsupportedErr );
-       
-       inMDNS->CanReceiveUnicastOn5353 = CanReceiveUnicast();
-       
-       // Setup the HINFO HW strings.
-       //<rdar://problem/7245119> device-info should have model=Windows
-
-       strcpy_s( ( char* ) &inMDNS->HIHardware.c[ 1 ], sizeof( inMDNS->HIHardware.c ) - 2, "Windows" );
-       inMDNS->HIHardware.c[ 0 ] = ( mDNSu8 ) mDNSPlatformStrLen( &inMDNS->HIHardware.c[ 1 ] );
-       dlog( kDebugLevelInfo, DEBUG_NAME "HIHardware: %#s\n", inMDNS->HIHardware.c );
-
-       // Setup the HINFO SW strings.
-#if ( MDNS_SET_HINFO_STRINGS )
-       mDNS_snprintf( (char *) &inMDNS->HISoftware.c[ 1 ], sizeof( inMDNS->HISoftware.c ) - 2, 
-               "mDNSResponder (%s %s)", __DATE__, __TIME__ );
-       inMDNS->HISoftware.c[ 0 ] = (mDNSu8) mDNSPlatformStrLen( &inMDNS->HISoftware.c[ 1 ] );
-       dlog( kDebugLevelInfo, DEBUG_NAME "HISoftware: %#s\n", inMDNS->HISoftware.c );
-#endif
-
-       // Set up the IPv4 unicast socket
-
-       inMDNS->p->unicastSock4.fd                      = INVALID_SOCKET;
-       inMDNS->p->unicastSock4.recvMsgPtr      = NULL;
-       inMDNS->p->unicastSock4.ifd                     = NULL;
-       inMDNS->p->unicastSock4.next            = NULL;
-       inMDNS->p->unicastSock4.m                       = inMDNS;
-
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-
-       sa4.sin_family          = AF_INET;
-       sa4.sin_addr.s_addr = INADDR_ANY;
-       err = SetupSocket( inMDNS, (const struct sockaddr*) &sa4, zeroIPPort, &inMDNS->p->unicastSock4.fd );
-       check_noerr( err );
-       sa4len = sizeof( sa4 );
-       err = getsockname( inMDNS->p->unicastSock4.fd, (struct sockaddr*) &sa4, &sa4len );
-       require_noerr( err, exit );
-       inMDNS->p->unicastSock4.port.NotAnInteger = sa4.sin_port;
-       inMDNS->UnicastPort4 = inMDNS->p->unicastSock4.port;
-       err = WSAIoctl( inMDNS->p->unicastSock4.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock4.recvMsgPtr, sizeof( inMDNS->p->unicastSock4.recvMsgPtr ), &size, NULL, NULL );
-               
-       if ( err )
-       {
-               inMDNS->p->unicastSock4.recvMsgPtr = NULL;
-       }
-
-       err = mDNSPollRegisterSocket( inMDNS->p->unicastSock4.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock4 );
-       require_noerr( err, exit ); 
-
-#endif
-
-       // Set up the IPv6 unicast socket
-
-       inMDNS->p->unicastSock6.fd                      = INVALID_SOCKET;
-       inMDNS->p->unicastSock6.recvMsgPtr      = NULL;
-       inMDNS->p->unicastSock6.ifd                     = NULL;
-       inMDNS->p->unicastSock6.next            = NULL;
-       inMDNS->p->unicastSock6.m                       = inMDNS;
-
-#if ( MDNS_WINDOWS_ENABLE_IPV6 )
-
-       if ( gEnableIPv6 )
-       {
-               sa6.sin6_family         = AF_INET6;
-               sa6.sin6_addr           = in6addr_any;
-               sa6.sin6_scope_id       = 0;
-
-               // This call will fail if the machine hasn't installed IPv6.  In that case,
-               // the error will be WSAEAFNOSUPPORT.
-
-               err = SetupSocket( inMDNS, (const struct sockaddr*) &sa6, zeroIPPort, &inMDNS->p->unicastSock6.fd );
-               require_action( !err || ( err == WSAEAFNOSUPPORT ), exit, err = (mStatus) WSAGetLastError() );
-               err = kNoErr;
-               
-               // If we weren't able to create the socket (because IPv6 hasn't been installed) don't do this
-
-               if ( inMDNS->p->unicastSock6.fd != INVALID_SOCKET )
-               {
-                       sa6len = sizeof( sa6 );
-                       err = getsockname( inMDNS->p->unicastSock6.fd, (struct sockaddr*) &sa6, &sa6len );
-                       require_noerr( err, exit );
-                       inMDNS->p->unicastSock6.port.NotAnInteger = sa6.sin6_port;
-                       inMDNS->UnicastPort6 = inMDNS->p->unicastSock6.port;
-
-                       err = WSAIoctl( inMDNS->p->unicastSock6.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &inMDNS->p->unicastSock6.recvMsgPtr, sizeof( inMDNS->p->unicastSock6.recvMsgPtr ), &size, NULL, NULL );
-                       
-                       if ( err != 0 )
-                       {
-                               inMDNS->p->unicastSock6.recvMsgPtr = NULL;
-                       }
-
-                       err = mDNSPollRegisterSocket( inMDNS->p->unicastSock6.fd, FD_READ, UDPSocketNotification, &inMDNS->p->unicastSock6 );
-                       require_noerr( err, exit );
-               }
-       }
-
-#endif
-
-       // Notify core of domain secret keys
-
-       SetDomainSecrets( inMDNS );
-       
-       // Success!
-
-       mDNSCoreInitComplete( inMDNS, err );
-
-       
-exit:
-
-       if ( err )
-       {
-               mDNSPlatformClose( inMDNS );
-       }
-
-       dlog( kDebugLevelTrace, DEBUG_NAME "platform init done (err=%d %m)\n", err, err );
-       return( err );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformClose
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformClose( mDNS * const inMDNS )
-{
-       mStatus         err;
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "platform close\n" );
-       check( inMDNS );
-
-       if ( gSMBThread != NULL )
-       {
-               dlog( kDebugLevelTrace, DEBUG_NAME "tearing down smb registration thread\n" );
-               SetEvent( gSMBThreadStopEvent );
-               
-               if ( WaitForSingleObject( gSMBThreadQuitEvent, 5 * 1000 ) == WAIT_OBJECT_0 )
-               {
-                       if ( gSMBThreadQuitEvent )
-                       {
-                               CloseHandle( gSMBThreadQuitEvent );
-                               gSMBThreadQuitEvent = NULL;
-                       }
-
-                       if ( gSMBThreadStopEvent )
-                       {
-                               CloseHandle( gSMBThreadStopEvent );
-                               gSMBThreadStopEvent = NULL;
-                       }
-
-                       if ( gSMBThreadDeregisterEvent )
-                       {
-                               CloseHandle( gSMBThreadDeregisterEvent );
-                               gSMBThreadDeregisterEvent = NULL;
-                       }
-
-                       if ( gSMBThreadRegisterEvent )
-                       {
-                               CloseHandle( gSMBThreadRegisterEvent );
-                               gSMBThreadRegisterEvent = NULL;
-                       }
-
-                       if ( gDNSSDLibrary )
-                       {
-                               FreeLibrary( gDNSSDLibrary );
-                               gDNSSDLibrary = NULL;
-                       }       
-               }
-               else
-               {
-                       LogMsg( "Unable to stop SMBThread" );
-               }
-
-               inMDNS->p->smbFileSharing = mDNSfalse;
-               inMDNS->p->smbPrintSharing = mDNSfalse;
-       }
-
-       // Tear everything down in reverse order to how it was set up.
-       
-       err = TearDownInterfaceList( inMDNS );
-       check_noerr( err );
-       check( !inMDNS->p->inactiveInterfaceList );
-
-#if ( MDNS_WINDOWS_ENABLE_IPV4 )
-
-       UDPCloseSocket( &inMDNS->p->unicastSock4 );
-
-#endif
-       
-#if ( MDNS_WINDOWS_ENABLE_IPV6 )
-
-       if ( gEnableIPv6 )
-       {
-               UDPCloseSocket( &inMDNS->p->unicastSock6 );
-       }
-
-#endif
-
-       // Free the DLL needed for IPv6 support.
-       
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-       if( gIPHelperLibraryInstance )
-       {
-               gGetAdaptersAddressesFunctionPtr = NULL;
-               
-               FreeLibrary( gIPHelperLibraryInstance );
-               gIPHelperLibraryInstance = NULL;
-       }
-#endif
-
-       if ( g_hAAPI32 )
-       {
-               // Release any resources
-
-               if ( g_hProvider && g_lpCryptReleaseContext )
-               {
-                       ( g_lpCryptReleaseContext )( g_hProvider, 0 );
-               }
-
-               // Free the AdvApi32.dll
-
-               FreeLibrary( g_hAAPI32 );
-
-               // And reset all the data
-
-               g_lpCryptAcquireContext = NULL;
-               g_lpCryptReleaseContext = NULL;
-               g_lpCryptGenRandom              = NULL;
-               g_hProvider                     = ( ULONG_PTR ) NULL;
-               g_hAAPI32                               = NULL;
-       }
-
-       WSACleanup();
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "platform close done\n" );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformLock
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformLock( const mDNS * const inMDNS )
-{
-       ( void ) inMDNS;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformUnlock
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformUnlock( const mDNS * const inMDNS )
-{
-       ( void ) inMDNS;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformStrCopy
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformStrCopy( void *inDst, const void *inSrc )
-{
-       check( inSrc );
-       check( inDst );
-       
-       strcpy( (char *) inDst, (const char*) inSrc );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformStrLCopy
-//===========================================================================================================================
-
-mDNSexport mDNSu32     mDNSPlatformStrLCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-       const char *            src = (const char *) inSrc;
-       
-       if( inSize > 0 )
-       {
-               size_t          n;
-               char *          dst = (char *) inDst;
-               
-               for( n = inSize - 1; n > 0; --n )
-               {
-                       if( ( *dst++ = *src++ ) == '\0' )
-                       {
-                               // Null terminator encountered, so exit.
-                               goto exit;
-                       }
-               }
-               *dst = '\0';
-       }
-       
-       while( *src++ != '\0' )
-       {
-               // Stop at null terminator.
-       }
-       
-exit:
-       return( (mDNSu32)( src - (const char *) inSrc ) - 1 );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformStrLen
-//===========================================================================================================================
-
-mDNSexport mDNSu32     mDNSPlatformStrLen( const void *inSrc )
-{
-       check( inSrc );
-       
-       return( (mDNSu32) strlen( (const char *) inSrc ) );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemCopy
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformMemCopy( void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-       check( inSrc );
-       check( inDst );
-       
-       memcpy( inDst, inSrc, inSize );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemSame
-//===========================================================================================================================
-
-mDNSexport mDNSBool    mDNSPlatformMemSame( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-       check( inSrc );
-       check( inDst );
-       
-       return( (mDNSBool)( memcmp( inSrc, inDst, inSize ) == 0 ) );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemCmp
-//===========================================================================================================================
-
-mDNSexport int mDNSPlatformMemCmp( const void *inDst, const void *inSrc, mDNSu32 inSize )
-{
-       check( inSrc );
-       check( inDst );
-       
-       return( memcmp( inSrc, inDst, inSize ) );
-}
-
-mDNSexport void mDNSPlatformQsort(void *base, int nel, int width, int (*compar)(const void *, const void *))
-{
-       (void)base;
-       (void)nel;
-       (void)width;
-       (void)compar;
-}
-
-// DNSSEC stub functions
-mDNSexport void VerifySignature(mDNS *const m, DNSSECVerifier *dv, DNSQuestion *q)
-       {
-       (void)m;
-       (void)dv;
-       (void)q;
-       }
-
-mDNSexport mDNSBool AddNSECSForCacheRecord(mDNS *const m, CacheRecord *crlist, CacheRecord *negcr, mDNSu8 rcode)
-       {
-       (void)m;
-       (void)crlist;
-       (void)negcr;
-       (void)rcode;
-       return mDNSfalse;
-       }
-
-mDNSexport void BumpDNSSECStats(mDNS *const m, DNSSECStatsAction action, DNSSECStatsType type, mDNSu32 value)
-    {
-    (void)m;
-    (void)action;
-    (void)type;
-    (void)value;
-    }
-
-// Proxy stub functions
-mDNSexport mDNSu8 *DNSProxySetAttributes(DNSQuestion *q, DNSMessageHeader *h, DNSMessage *msg, mDNSu8 *ptr, mDNSu8 *limit)
-{
-    (void) q;
-    (void) h;
-    (void) msg;
-    (void) ptr;
-    (void) limit;
-
-    return ptr;
-}
-
-mDNSexport void DNSProxyInit(mDNS *const m, mDNSu32 IpIfArr[], mDNSu32 OpIf)
-{
-    (void) m;
-    (void) IpIfArr;
-    (void) OpIf;
-}
-
-mDNSexport void DNSProxyTerminate(mDNS *const m)
-{
-    (void) m;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemZero
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformMemZero( void *inDst, mDNSu32 inSize )
-{
-       check( inDst );
-       
-       memset( inDst, 0, inSize );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemAllocate
-//===========================================================================================================================
-
-mDNSexport void *      mDNSPlatformMemAllocate( mDNSu32 inSize )
-{
-       void *          mem;
-       
-       check( inSize > 0 );
-       
-       mem = malloc( inSize );
-       check( mem );
-       
-       return( mem );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformMemFree
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformMemFree( void *inMem )
-{
-       check( inMem );
-       
-       free( inMem );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformRandomNumber
-//===========================================================================================================================
-
-mDNSexport mDNSu32 mDNSPlatformRandomNumber(void)
-{
-       unsigned int    randomNumber;
-       errno_t                 err;
-
-       err = rand_s( &randomNumber );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( err )
-       {
-               randomNumber = rand();
-       }
-
-       return ( mDNSu32 ) randomNumber;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTimeInit
-//===========================================================================================================================
-
-mDNSexport mStatus     mDNSPlatformTimeInit( void )
-{
-       // No special setup is required on Windows -- we just use GetTickCount().
-       return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformRawTime
-//===========================================================================================================================
-
-mDNSexport mDNSs32     mDNSPlatformRawTime( void )
-{
-       return( (mDNSs32) GetTickCount() );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformUTC
-//===========================================================================================================================
-
-mDNSexport mDNSs32     mDNSPlatformUTC( void )
-{
-       return ( mDNSs32 ) time( NULL );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceNameToID
-//===========================================================================================================================
-
-mDNSexport mStatus     mDNSPlatformInterfaceNameToID( mDNS * const inMDNS, const char *inName, mDNSInterfaceID *outID )
-{
-       mStatus                                 err;
-       mDNSInterfaceData *             ifd;
-       
-       check( inMDNS );
-       check( inMDNS->p );
-       check( inName );
-       
-       // Search for an interface with the specified name,
-       
-       for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
-       {
-               if( strcmp( ifd->name, inName ) == 0 )
-               {
-                       break;
-               }
-       }
-       require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
-       
-       // Success!
-       
-       if( outID )
-       {
-               *outID = (mDNSInterfaceID) ifd;
-       }
-       err = mStatus_NoError;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceIDToInfo
-//===========================================================================================================================
-
-mDNSexport mStatus     mDNSPlatformInterfaceIDToInfo( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSPlatformInterfaceInfo *outInfo )
-{
-       mStatus                                 err;
-       mDNSInterfaceData *             ifd;
-       
-       check( inMDNS );
-       check( inID );
-       check( outInfo );
-       
-       // Search for an interface with the specified ID,
-       
-       for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
-       {
-               if( ifd == (mDNSInterfaceData *) inID )
-               {
-                       break;
-               }
-       }
-       require_action_quiet( ifd, exit, err = mStatus_NoSuchNameErr );
-       
-       // Success!
-       
-       outInfo->name   = ifd->name;
-       outInfo->ip     = ifd->interfaceInfo.ip;
-       err                     = mStatus_NoError;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceIDfromInterfaceIndex
-//===========================================================================================================================
-
-mDNSexport mDNSInterfaceID     mDNSPlatformInterfaceIDfromInterfaceIndex( mDNS * const inMDNS, mDNSu32 inIndex )
-{
-       mDNSInterfaceID         id;
-       
-       id = mDNSNULL;
-       if( inIndex == kDNSServiceInterfaceIndexLocalOnly )
-       {
-               id = mDNSInterface_LocalOnly;
-       }
-       else if( inIndex != 0 )
-       {
-               mDNSInterfaceData *             ifd;
-               
-               for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
-               {
-                       if( ( ifd->scopeID == inIndex ) && ifd->interfaceInfo.InterfaceActive )
-                       {
-                               id = ifd->interfaceInfo.InterfaceID;
-                               break;
-                       }
-               }
-               check( ifd );
-       }
-       return( id );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformInterfaceIndexfromInterfaceID
-//===========================================================================================================================
-       
-mDNSexport mDNSu32     mDNSPlatformInterfaceIndexfromInterfaceID( mDNS * const inMDNS, mDNSInterfaceID inID, mDNSBool suppressNetworkChange )
-{
-       mDNSu32         index;
-       
-       (void) suppressNetworkChange;
-
-       index = 0;
-       if( inID == mDNSInterface_LocalOnly )
-       {
-               index = (mDNSu32) kDNSServiceInterfaceIndexLocalOnly;
-       }
-       else if( inID )
-       {
-               mDNSInterfaceData *             ifd;
-               
-               // Search active interfaces.
-               for( ifd = inMDNS->p->interfaceList; ifd; ifd = ifd->next )
-               {
-                       if( (mDNSInterfaceID) ifd == inID )
-                       {
-                               index = ifd->scopeID;
-                               break;
-                       }
-               }
-               
-               // Search inactive interfaces too so remove events for inactive interfaces report the old interface index.
-               
-               if( !ifd )
-               {
-                       for( ifd = inMDNS->p->inactiveInterfaceList; ifd; ifd = ifd->next )
-                       {
-                               if( (mDNSInterfaceID) ifd == inID )
-                               {
-                                       index = ifd->scopeID;
-                                       break;
-                               }
-                       }
-               }
-               check( ifd );
-       }
-       return( index );
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTCPSocket
-//===========================================================================================================================
-
-TCPSocket *
-mDNSPlatformTCPSocket
-       (
-       mDNS                    * const m,
-       TCPSocketFlags          flags,
-       mDNSIPPort                      *       port, 
-       mDNSBool                        useBackgroundTrafficClass
-       )
-{
-       TCPSocket *             sock    = NULL;
-       u_long                          on              = 1;  // "on" for setsockopt
-       struct sockaddr_in      saddr;
-       int                                     len;
-       mStatus                         err             = mStatus_NoError;
-
-       DEBUG_UNUSED( m );
-       DEBUG_UNUSED( useBackgroundTrafficClass );
-
-       require_action( flags == 0, exit, err = mStatus_UnsupportedErr );
-
-       // Setup connection data object
-
-       sock = (TCPSocket *) malloc( sizeof( TCPSocket ) );
-       require_action( sock, exit, err = mStatus_NoMemoryErr );
-       mDNSPlatformMemZero( sock, sizeof( TCPSocket ) );
-       sock->fd                = INVALID_SOCKET;
-       sock->flags             = flags;
-       sock->m                 = m;
-
-       mDNSPlatformMemZero(&saddr, sizeof(saddr));
-       saddr.sin_family                = AF_INET;
-       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 );
-
-       // bind
-
-       err = bind( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr )  );
-       err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
-
-       // Set it to be non-blocking
-
-       err = ioctlsocket( sock->fd, FIONBIO, &on );
-       err = translate_errno( err == 0, WSAGetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
-
-       // Get port number
-
-       mDNSPlatformMemZero( &saddr, 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 )
-       {
-               TCPCloseSocket( sock );
-               free( sock );
-               sock = mDNSNULL;
-       }
-
-       return sock;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTCPConnect
-//===========================================================================================================================
-
-mStatus
-mDNSPlatformTCPConnect
-       (
-       TCPSocket                       *       sock,
-       const mDNSAddr          *       inDstIP, 
-       mDNSOpaque16                    inDstPort, 
-       domainname                      *       hostname,
-       mDNSInterfaceID                 inInterfaceID,
-       TCPConnectionCallback   inCallback, 
-       void *                                  inContext
-       )
-{
-       struct sockaddr_in      saddr;
-       mStatus                         err             = mStatus_NoError;
-
-       DEBUG_UNUSED( hostname );
-       DEBUG_UNUSED( inInterfaceID );
-
-       if ( inDstIP->type != mDNSAddrType_IPv4 )
-       {
-               LogMsg("ERROR: mDNSPlatformTCPConnect - attempt to connect to an IPv6 address: operation not supported");
-               return mStatus_UnknownErr;
-       }
-
-       // Setup connection data object
-
-       sock->userCallback      = inCallback;
-       sock->userContext       = inContext;
-
-       mDNSPlatformMemZero(&saddr, sizeof(saddr));
-       saddr.sin_family        = AF_INET;
-       saddr.sin_port          = inDstPort.NotAnInteger;
-       memcpy(&saddr.sin_addr, &inDstIP->ip.v4.NotAnInteger, sizeof(saddr.sin_addr));
-
-       // Try and do connect
-
-       err = connect( sock->fd, ( struct sockaddr* ) &saddr, sizeof( saddr ) );
-       require_action( !err || ( WSAGetLastError() == WSAEWOULDBLOCK ), exit, err = mStatus_ConnFailed );
-       sock->connected = !err ? TRUE : FALSE;
-
-       err = mDNSPollRegisterSocket( sock->fd, FD_CONNECT | FD_READ | FD_CLOSE, TCPSocketNotification, sock );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( !err )
-       {
-               err = sock->connected ? mStatus_ConnEstablished : mStatus_ConnPending;
-       }
-
-       return err;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTCPAccept
-//===========================================================================================================================
-
-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 );
-       
-       mDNSPlatformMemZero( sock, sizeof( *sock ) );
-
-       sock->fd        = fd;
-       sock->flags = flags;
-
-exit:
-
-       if ( err && sock )
-       {
-               free( sock );
-               sock = NULL;
-       }
-
-       return sock;
-       }
-
-//===========================================================================================================================
-//     mDNSPlatformTCPCloseConnection
-//===========================================================================================================================
-
-mDNSexport void        mDNSPlatformTCPCloseConnection( TCPSocket *sock )
-{
-       check( sock );
-
-       if ( sock )
-       {
-               dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformTCPCloseConnection 0x%x:%d\n", sock, sock->fd );
-
-               if ( sock->fd != INVALID_SOCKET )
-               {
-                       mDNSPollUnregisterSocket( sock->fd );
-                       closesocket( sock->fd );
-                       sock->fd = INVALID_SOCKET;
-               }
-
-               free( sock );
-       }
-}
-
-//===========================================================================================================================
-//     mDNSPlatformReadTCP
-//===========================================================================================================================
-
-mDNSexport long        mDNSPlatformReadTCP( TCPSocket *sock, void *inBuffer, unsigned long inBufferSize, mDNSBool * closed )
-{
-       int                     nread;
-    OSStatus    err;
-
-       *closed = mDNSfalse;
-    nread = recv( sock->fd, inBuffer, inBufferSize, 0 );
-    err = translate_errno( ( nread >= 0 ), WSAGetLastError(), mStatus_UnknownErr );
-       
-       if ( nread > 0 )
-       {
-               dlog( kDebugLevelChatty, DEBUG_NAME "mDNSPlatformReadTCP: 0x%x:%d read %d bytes\n", sock, sock->fd, nread );
-       }
-       else if ( !nread )
-       {
-               *closed = mDNStrue;
-       }
-       else if ( err == WSAECONNRESET )
-       {
-               *closed = mDNStrue;
-               nread = 0;
-       }
-       else if ( err == WSAEWOULDBLOCK )
-       {
-               nread = 0;
-       }
-       else
-       {
-               LogMsg( "ERROR: mDNSPlatformReadTCP - recv: %d\n", err );
-               nread = -1;
-       }
-
-    return nread;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformWriteTCP
-//===========================================================================================================================
-
-mDNSexport long        mDNSPlatformWriteTCP( TCPSocket *sock, const char *inMsg, unsigned long inMsgSize )
-{
-       int                     nsent;
-       OSStatus        err;
-
-       nsent = send( sock->fd, inMsg, inMsgSize, 0 );
-
-       err = translate_errno( ( nsent >= 0 ) || ( WSAGetLastError() == WSAEWOULDBLOCK ), WSAGetLastError(), mStatus_UnknownErr );
-       require_noerr( err, exit );
-
-       if ( nsent < 0)
-       {
-               nsent = 0;
-       }
-               
-exit:
-
-       return nsent;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTCPGetFD
-//===========================================================================================================================
-
-mDNSexport int mDNSPlatformTCPGetFD(TCPSocket *sock )
-{
-       return ( int ) sock->fd;
-}
-
-//===========================================================================================================================
-//     TCPSocketNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-TCPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
-       TCPSocket                               *tcpSock = ( TCPSocket* ) context;
-       TCPConnectionCallback   callback;
-       int                                             err;
-
-       DEBUG_UNUSED( sock );
-
-       require_action( tcpSock, exit, err = mStatus_BadParamErr );
-       callback = ( TCPConnectionCallback ) tcpSock->userCallback;
-       require_action( callback, exit, err = mStatus_BadParamErr );
-
-       if ( event && ( event->lNetworkEvents & FD_CONNECT ) )
-       {
-               if ( event->iErrorCode[ FD_CONNECT_BIT ] == 0 )
-               {
-                       callback( tcpSock, tcpSock->userContext, mDNStrue, 0 );
-                       tcpSock->connected = mDNStrue;
-               }
-               else
-               {
-                       callback( tcpSock, tcpSock->userContext, mDNSfalse, event->iErrorCode[ FD_CONNECT_BIT ] );
-               }
-       }
-       else
-       {
-               callback( tcpSock, tcpSock->userContext, mDNSfalse, 0 );
-       }
-
-exit:
-
-       return;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformUDPSocket
-//===========================================================================================================================
-
-mDNSexport UDPSocket* mDNSPlatformUDPSocket(mDNS *const m, const mDNSIPPort requestedport)
-{
-       UDPSocket*      sock    = NULL;
-       mDNSIPPort      port    = requestedport;
-       mStatus         err             = mStatus_NoError;
-       unsigned        i;
-
-       // Setup connection data object
-
-       sock = ( UDPSocket* ) malloc(sizeof( UDPSocket ) );
-       require_action( sock, exit, err = mStatus_NoMemoryErr );
-       memset( sock, 0, sizeof( UDPSocket ) );
-
-       // Create the socket
-
-       sock->fd                        = INVALID_SOCKET;
-       sock->recvMsgPtr        = m->p->unicastSock4.recvMsgPtr;
-       sock->addr                      = m->p->unicastSock4.addr;
-       sock->ifd                       = NULL;
-       sock->m                         = m;
-
-       // Try at most 10000 times to get a unique random port
-
-       for (i=0; i<10000; i++)
-       {
-               struct sockaddr_in saddr;
-
-               saddr.sin_family                = AF_INET;
-               saddr.sin_addr.s_addr   = 0;
-
-               // The kernel doesn't do cryptographically strong random port
-               // allocation, so we do it ourselves here
-
-        if (mDNSIPPortIsZero(requestedport))
-               {
-                       port = mDNSOpaque16fromIntVal( ( mDNSu16 ) ( 0xC000 + mDNSRandom(0x3FFF) ) );
-               }
-
-               saddr.sin_port = port.NotAnInteger;
-
-        err = SetupSocket(m, ( struct sockaddr* ) &saddr, port, &sock->fd );
-        if (!err) break;
-       }
-
-       require_noerr( err, exit );
-
-       // Set the port
-
-       sock->port = port;
-
-       // Arm the completion routine
-
-       err = mDNSPollRegisterSocket( sock->fd, FD_READ, UDPSocketNotification, sock );
-       require_noerr( err, exit ); 
-
-       // Bookkeeping
-
-       sock->next              = gUDPSockets;
-       gUDPSockets             = sock;
-       gUDPNumSockets++;
-
-exit:
-
-       if ( err && sock )
-       {
-               UDPCloseSocket( sock );
-               free( sock );
-               sock = NULL;
-       }
-
-       return sock;
-}
-       
-//===========================================================================================================================
-//     mDNSPlatformUDPClose
-//===========================================================================================================================
-       
-mDNSexport void mDNSPlatformUDPClose( UDPSocket *sock )
-{
-       UDPSocket       *       current  = gUDPSockets;
-       UDPSocket       *       last = NULL;
-
-       while ( current )
-       {
-               if ( current == sock )
-               {
-                       if ( last == NULL )
-                       {
-                               gUDPSockets = sock->next;
-                       }
-                       else
-                       {
-                               last->next = sock->next;
-                       }
-
-                       UDPCloseSocket( sock );
-                       free( sock );
-
-                       gUDPNumSockets--;
-
-                       break;
-               }
-
-               last    = current;
-               current = current->next;
-       }
-}
-
-//===========================================================================================================================
-//     mDNSPlatformSendUDP
-//===========================================================================================================================
-
-mDNSexport mStatus
-       mDNSPlatformSendUDP( 
-               const mDNS * const                      inMDNS, 
-               const void * const              inMsg, 
-               const mDNSu8 * const            inMsgEnd, 
-               mDNSInterfaceID                         inInterfaceID, 
-               UDPSocket *                                     inSrcSocket,
-               const mDNSAddr *                        inDstIP, 
-               mDNSIPPort                                      inDstPort,
-               mDNSBool                                        useBackgroundTrafficClass )
-{
-       SOCKET                                          sendingsocket = INVALID_SOCKET;
-       mStatus                                         err = mStatus_NoError;
-       mDNSInterfaceData *                     ifd = (mDNSInterfaceData*) inInterfaceID;
-       struct sockaddr_storage         addr;
-       int                                                     n;
-       
-       DEBUG_USE_ONLY( inMDNS );
-       DEBUG_USE_ONLY( useBackgroundTrafficClass );
-       
-       n = (int)( inMsgEnd - ( (const mDNSu8 * const) inMsg ) );
-       check( inMDNS );
-       check( inMsg );
-       check( inMsgEnd );
-       check( inDstIP );
-       
-       dlog( kDebugLevelChatty, DEBUG_NAME "platform send %d bytes to %#a:%u\n", n, inDstIP, ntohs( inDstPort.NotAnInteger ) );
-       
-       if( inDstIP->type == mDNSAddrType_IPv4 )
-       {
-               struct sockaddr_in *            sa4;
-               
-               sa4                                             = (struct sockaddr_in *) &addr;
-               sa4->sin_family                 = AF_INET;
-               sa4->sin_port                   = inDstPort.NotAnInteger;
-               sa4->sin_addr.s_addr    = inDstIP->ip.v4.NotAnInteger;
-               sendingsocket           = ifd ? ifd->sock.fd : inMDNS->p->unicastSock4.fd;
-
-               if (inSrcSocket) { sendingsocket = inSrcSocket->fd; debugf("mDNSPlatformSendUDP using port %d, static port %d, sock %d", mDNSVal16(inSrcSocket->port), inMDNS->p->unicastSock4.fd, sendingsocket); }
-       }
-       else if( inDstIP->type == mDNSAddrType_IPv6 )
-       {
-               struct sockaddr_in6 *           sa6;
-               
-               sa6                                     = (struct sockaddr_in6 *) &addr;
-               sa6->sin6_family        = AF_INET6;
-               sa6->sin6_port          = inDstPort.NotAnInteger;
-               sa6->sin6_flowinfo      = 0;
-               sa6->sin6_addr          = *( (struct in6_addr *) &inDstIP->ip.v6 );
-               sa6->sin6_scope_id      = 0;    // Windows requires the scope ID to be zero. IPV6_MULTICAST_IF specifies interface.
-               sendingsocket           = ifd ? ifd->sock.fd : inMDNS->p->unicastSock6.fd;
-       }
-       else
-       {
-               dlog( kDebugLevelError, DEBUG_NAME "%s: dst is not an IPv4 or IPv6 address (type=%d)\n", __ROUTINE__, inDstIP->type );
-               err = mStatus_BadParamErr;
-               goto exit;
-       }
-       
-       if (IsValidSocket(sendingsocket))
-       {
-               n = sendto( sendingsocket, (char *) inMsg, n, 0, (struct sockaddr *) &addr, sizeof( addr ) );
-               err = translate_errno( n > 0, errno_compat(), kWriteErr );
-
-               if ( err )
-               {
-                       // Don't report EHOSTDOWN (i.e. ARP failure), ENETDOWN, or no route to host for unicast destinations
-
-                       if ( !mDNSAddressIsAllDNSLinkGroup( inDstIP ) && ( WSAGetLastError() == WSAEHOSTDOWN || WSAGetLastError() == WSAENETDOWN || WSAGetLastError() == WSAEHOSTUNREACH || WSAGetLastError() == WSAENETUNREACH ) )
-                       {
-                               err = mStatus_TransientErr;
-                       }
-                       else
-                       {
-                               require_noerr( err, exit );
-                       }
-               }
-       }
-       
-exit:
-       return( err );
-}
-
-mDNSexport void mDNSPlatformUpdateProxyList(mDNS *const m, const mDNSInterfaceID InterfaceID)
-       {
-       DEBUG_UNUSED( m );
-       DEBUG_UNUSED( InterfaceID );
-       }
-
-mDNSexport void mDNSPlatformSetAllowSleep(mDNS *const m, mDNSBool allowSleep, const char *reason)
-       {
-       DEBUG_UNUSED( m );
-       DEBUG_UNUSED( allowSleep );
-       DEBUG_UNUSED( reason );
-       }
-
-//===========================================================================================================================
-//     mDNSPlatformSendRawPacket
-//===========================================================================================================================
-
-mDNSexport void mDNSPlatformSendWakeupPacket(mDNS *const m, mDNSInterfaceID InterfaceID, char *ethaddr, char *ipaddr, int iteration)
-{
-       unsigned char                   mac[ 6 ];
-       unsigned char                   buf[ 102 ];
-       char                                    hex[ 3 ] = { 0 };
-       unsigned char                   *bufPtr = buf;
-       MulticastWakeupStruct   *info;
-       int                                             i;
-       mStatus                                 err;
-
-       (void) InterfaceID; // unused
-       (void) ipaddr;      // unused
-       (void) iteration;   // unused
-
-       require_action( ethaddr, exit, err = mStatus_BadParamErr );
-
-       for ( i = 0; i < 6; i++ )
-       {
-               memcpy( hex, ethaddr + ( i * 3 ), 2 );
-               mac[ i ] = ( unsigned char ) strtoul( hex, NULL, 16 );
-       }
-
-       memset( buf, 0, sizeof( buf ) );
-
-       for ( i = 0; i < 6; i++ )
-       {
-               *bufPtr++ = 0xff;
-       }
-       
-       for ( i = 0; i < 16; i++ )
-       {
-               memcpy( bufPtr, mac, sizeof( mac ) );
-               bufPtr += sizeof( mac );
-       }
-
-       info = ( MulticastWakeupStruct* ) malloc( sizeof( MulticastWakeupStruct ) );
-       require_action( info, exit, err = mStatus_NoMemoryErr );
-       info->inMDNS = m;
-       memset( &info->addr, 0, sizeof( info->addr ) );
-       info->addr.sin_family = AF_INET;
-       info->addr.sin_addr.s_addr = AllDNSLinkGroup_v4.ip.v4.NotAnInteger;
-       info->addr.sin_port = htons( 9 );
-       info->addrLen = sizeof( info->addr );
-       memcpy( info->data, buf, sizeof( buf ) );
-       info->dataLen = sizeof( buf );
-       info->numTries  = kMulticastWakeupNumTries;
-       info->msecSleep = kMulticastWakeupSleepBetweenTries;
-
-       _beginthread( SendMulticastWakeupPacket, 0, ( void* ) info );
-
-exit:
-
-       return;
-}
-
-mDNSexport mDNSBool mDNSPlatformValidRecordForInterface(const AuthRecord *rr, mDNSInterfaceID InterfaceID)
-{
-       DEBUG_UNUSED( rr );
-       DEBUG_UNUSED( InterfaceID );
-
-       return mDNStrue;
-}
-mDNSexport mDNSBool mDNSPlatformValidQuestionForInterface(DNSQuestion *q, const NetworkInterfaceInfo *intf)
-{
-       DEBUG_UNUSED( q );
-       DEBUG_UNUSED( intf );
-
-       return mDNStrue;
-}
-mDNSexport void mDNSPlatformSendRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
-       {
-       DEBUG_UNUSED( msg );
-       DEBUG_UNUSED( end );
-       DEBUG_UNUSED( InterfaceID );
-       }
-
-// Used for debugging purposes. For now, just set the buffer to zero
-mDNSexport void mDNSPlatformFormatTime(unsigned long te, mDNSu8 *buf, int bufsize)
-       {
-       DEBUG_UNUSED( te );
-       if (bufsize) buf[0] = 0;
-       }
-
-mDNSexport void mDNSPlatformSetLocalAddressCacheEntry(mDNS *const m, const mDNSAddr *const tpa, const mDNSEthAddr *const tha, mDNSInterfaceID InterfaceID)
-       {
-       DEBUG_UNUSED( m );
-       DEBUG_UNUSED( tpa );
-       DEBUG_UNUSED( tha );
-       DEBUG_UNUSED( InterfaceID );
-       }
-
-mDNSexport void mDNSPlatformReceiveRawPacket(const void *const msg, const mDNSu8 *const end, mDNSInterfaceID InterfaceID)
-       {
-       DEBUG_UNUSED( msg );
-       DEBUG_UNUSED( end );
-       DEBUG_UNUSED( InterfaceID );
-       }
-
-mDNSexport void mDNSPlatformSetLocalARP( const mDNSv4Addr * const tpa, const mDNSEthAddr * const tha, mDNSInterfaceID InterfaceID )
-       {
-       DEBUG_UNUSED( tpa );
-       DEBUG_UNUSED( tha );
-       DEBUG_UNUSED( InterfaceID );
-       }
-
-mDNSexport void mDNSPlatformWriteDebugMsg(const char *msg)
-       {
-       dlog( kDebugLevelInfo, "%s\n", msg );
-       }
-
-mDNSexport void mDNSPlatformWriteLogMsg( const char * ident, const char * msg, mDNSLogLevel_t loglevel )
-       {
-       extern mDNS mDNSStorage;
-       int type;
-       
-       DEBUG_UNUSED( ident );
-
-       type = EVENTLOG_ERROR_TYPE;
-
-       switch (loglevel) 
-       {
-               case MDNS_LOG_MSG:       type = EVENTLOG_ERROR_TYPE;            break;
-               case MDNS_LOG_OPERATION: type = EVENTLOG_WARNING_TYPE;          break;
-               case MDNS_LOG_SPS:       type = EVENTLOG_INFORMATION_TYPE;  break;
-               case MDNS_LOG_INFO:      type = EVENTLOG_INFORMATION_TYPE;      break;
-               case MDNS_LOG_DEBUG:     type = EVENTLOG_INFORMATION_TYPE;      break;
-               default:
-                       fprintf(stderr, "Unknown loglevel %d, assuming LOG_ERR\n", loglevel);
-                       fflush(stderr);
-                       }
-
-       mDNSStorage.p->reportStatusFunc( type, msg );
-       dlog( kDebugLevelInfo, "%s\n", msg );
-       }
-
-mDNSexport void mDNSPlatformSourceAddrForDest( mDNSAddr * const src, const mDNSAddr * const dst )
-       {
-       DEBUG_UNUSED( src );
-       DEBUG_UNUSED( dst );
-       }
-
-//===========================================================================================================================
-//     mDNSPlatformTLSSetupCerts
-//===========================================================================================================================
-
-mDNSexport mStatus
-mDNSPlatformTLSSetupCerts(void)
-{
-       return mStatus_UnsupportedErr;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformTLSTearDownCerts
-//===========================================================================================================================
-
-mDNSexport void
-mDNSPlatformTLSTearDownCerts(void)
-{
-}
-
-//===========================================================================================================================
-//     mDNSPlatformSetDNSConfig
-//===========================================================================================================================
-
-mDNSlocal void SetDNSServers( mDNS *const m );
-mDNSlocal void SetSearchDomainList( void );
-
-mDNSexport mDNSBool mDNSPlatformSetDNSConfig(mDNS *const m, mDNSBool setservers, mDNSBool setsearch, domainname *const fqdn, DNameListElem **regDomains, DNameListElem **browseDomains, mDNSBool ackConfig)
-{
-       (void) ackConfig;
-
-       if (setservers) SetDNSServers(m);
-       if (setsearch) SetSearchDomainList();
-       
-       if ( fqdn )
-       {
-               GetDDNSFQDN( fqdn );
-       }
-
-       if ( browseDomains )
-       {
-               GetDDNSDomains( browseDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSBrowseDomains );
-       }
-
-       if ( regDomains )
-       {
-               GetDDNSDomains( regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
-       }
-    return mDNStrue;
-}
-
-//===========================================================================================================================
-//     mDNSPlatformDynDNSHostNameStatusChanged
-//===========================================================================================================================
-
-mDNSexport void
-mDNSPlatformDynDNSHostNameStatusChanged(const domainname *const dname, const mStatus status)
-{
-       char            uname[MAX_ESCAPED_DOMAIN_NAME];
-       BYTE            bStatus;
-       LPCTSTR         name;
-       HKEY            key = NULL;
-       mStatus         err;
-       char    *       p;
-       
-       ConvertDomainNameToCString(dname, uname);
-       
-       p = uname;
-
-       while (*p)
-       {
-               *p = (char) tolower(*p);
-               if (!(*(p+1)) && *p == '.') *p = 0; // if last character, strip trailing dot
-               p++;
-       }
-
-       check( strlen( p ) <= MAX_ESCAPED_DOMAIN_NAME );
-       name = kServiceParametersNode TEXT("\\DynDNS\\State\\HostNames");
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, name, &key );
-       require_noerr( err, exit );
-
-       bStatus = ( status ) ? 0 : 1;
-       err = RegSetValueEx( key, kServiceDynDNSStatus, 0, REG_DWORD, (const LPBYTE) &bStatus, sizeof(DWORD) );
-       require_noerr( err, exit );
-
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       return;
-}
-
-//===========================================================================================================================
-//     SetDomainSecrets
-//===========================================================================================================================
-
-// This routine needs to be called whenever the system secrets database changes.
-// We call it from DynDNSConfigDidChange and mDNSPlatformInit
-
-void
-SetDomainSecrets( mDNS * const m )
-{
-       DomainAuthInfo *ptr;
-       domainname              fqdn;
-       DNameListElem * regDomains = NULL;
-
-       // 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.
-       
-       for (ptr = m->AuthInfoList; ptr; ptr = ptr->next)
-               ptr->deltime = NonZeroTime(m->timenow + mDNSPlatformOneSecond*10);
-
-       GetDDNSFQDN( &fqdn );
-
-       if ( fqdn.c[ 0 ] )
-       {
-               SetDomainSecret( m, &fqdn );
-       }
-
-       GetDDNSDomains( &regDomains, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSRegistrationDomains );
-
-       while ( regDomains )
-       {
-               DNameListElem * current = regDomains;
-               SetDomainSecret( m, &current->name );
-               regDomains = regDomains->next;
-               free( current );
-       }
-}
-
-//===========================================================================================================================
-//     SetSearchDomainList
-//===========================================================================================================================
-
-mDNSlocal void SetDomainFromDHCP( void );
-mDNSlocal void SetReverseMapSearchDomainList( void );
-
-mDNSlocal void
-SetSearchDomainList( void )
-{
-       char                    *       searchList      = NULL;
-       DWORD                           searchListLen;
-       //DNameListElem *       head = NULL;
-       //DNameListElem *       current = NULL;
-       char                    *       tok;
-       HKEY                            key;
-       mStatus                         err;
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), &key );
-       require_noerr( err, exit );
-
-       err = RegQueryString( key, "SearchList", &searchList, &searchListLen, NULL );
-       require_noerr( err, exit );
-
-       // Windows separates the search domains with ','
-
-       tok = strtok( searchList, "," );
-       while ( tok )
-       {
-               if ( ( strcmp( tok, "" ) != 0 ) && ( strcmp( tok, "." ) != 0 ) )
-                       mDNS_AddSearchDomain_CString(tok, mDNSNULL);
-               tok = strtok( NULL, "," );
-       }
-
-exit:
-
-       if ( searchList ) 
-       {
-               free( searchList );
-       }
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-
-       SetDomainFromDHCP();
-       SetReverseMapSearchDomainList();
-}
-
-//===========================================================================================================================
-//     SetReverseMapSearchDomainList
-//===========================================================================================================================
-
-mDNSlocal void
-SetReverseMapSearchDomainList( void )
-{
-       struct ifaddrs  *       ifa;
-
-       ifa = myGetIfAddrs( 1 );
-       while (ifa)
-       {
-               mDNSAddr addr;
-               
-               if (ifa->ifa_addr->sa_family == AF_INET && !SetupAddr(&addr, ifa->ifa_addr) && !(ifa->ifa_flags & IFF_LOOPBACK) && ifa->ifa_netmask)
-               {
-                       mDNSAddr        netmask;
-                       char            buffer[256];
-                       
-                       if (!SetupAddr(&netmask, ifa->ifa_netmask))
-                       {
-                               _snprintf(buffer, sizeof( 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]);
-                               mDNS_AddSearchDomain_CString(buffer, mDNSNULL);
-                       }
-               }
-       
-               ifa = ifa->ifa_next;
-       }
-
-       return;
-}
-
-//===========================================================================================================================
-//     SetDNSServers
-//===========================================================================================================================
-
-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;
-       DWORD                                   index;
-       int                                             i                       = 0;
-       mStatus                                 err                     = kUnknownErr;
-
-       // Get the primary interface.
-
-       index = GetPrimaryInterface();
-
-       // This should have the interface index of the primary index.  Fall back in cases where
-       // it can't be determined.
-
-       if ( index )
-       {
-               bufLen = 0;
-
-               for ( i = 0; i < 100; i++ )
-               {
-                       err = GetPerAdapterInfo( index, pAdapterInfo, &bufLen );
-
-                       if ( err != ERROR_BUFFER_OVERFLOW )
-                       {
-                               break;
-                       }
-
-                       pAdapterInfo = (PIP_PER_ADAPTER_INFO) realloc( pAdapterInfo, bufLen );
-                       require_action( pAdapterInfo, exit, err = mStatus_NoMemoryErr );
-               }
-
-               require_noerr( err, exit );
-
-               dnsServerList = &pAdapterInfo->DnsServerList;
-       }
-       else
-       {
-               bufLen = sizeof( FIXED_INFO );
-
-               for ( i = 0; i < 100; i++ )
-               {
-                       if ( fixedInfo )
-                       {
-                               GlobalFree( fixedInfo );
-                               fixedInfo = NULL;
-                       }
-
-                       fixedInfo = (FIXED_INFO*) GlobalAlloc( GPTR, bufLen );
-                       require_action( fixedInfo, exit, err = mStatus_NoMemoryErr );
-          
-                       err = GetNetworkParams( fixedInfo, &bufLen );
-
-                       if ( err != ERROR_BUFFER_OVERFLOW )
-                       {
-                               break;
-                       }
-               }
-
-               require_noerr( err, exit );
-
-               dnsServerList = &fixedInfo->DnsServerList;
-       }
-
-       for ( ipAddr = dnsServerList; ipAddr; ipAddr = ipAddr->Next )
-       {
-               mDNSAddr addr;
-               err = StringToAddress( &addr, ipAddr->IpAddress.String );
-               if ( !err ) mDNS_AddDNSServer(m, mDNSNULL, mDNSInterface_Any, 0, &addr, UnicastDNSPort, kScopeNone, DEFAULT_UDNS_TIMEOUT, mDNSfalse, mDNSfalse, mDNSfalse, 0, mDNStrue, mDNStrue, mDNSfalse);
-       }
-
-exit:
-
-       if ( pAdapterInfo )
-       {
-               free( pAdapterInfo );
-       }
-
-       if ( fixedInfo )
-       {
-               GlobalFree( fixedInfo );
-       }
-}
-
-//===========================================================================================================================
-//     SetDomainFromDHCP
-//===========================================================================================================================
-
-mDNSlocal void
-SetDomainFromDHCP( void )
-{
-       int                                     i                       = 0;
-       IP_ADAPTER_INFO *       pAdapterInfo;
-       IP_ADAPTER_INFO *       pAdapter;
-       DWORD                           bufLen;
-       DWORD                           index;
-       HKEY                            key = NULL;
-       LPSTR                           domain = NULL;
-       DWORD                           dwSize;
-       mStatus                         err = mStatus_NoError;
-
-       pAdapterInfo    = NULL;
-       
-       for ( i = 0; i < 100; i++ )
-       {
-               err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-
-               if ( err != ERROR_BUFFER_OVERFLOW )
-               {
-                       break;
-               }
-
-               pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
-               require_action( pAdapterInfo, exit, err = kNoMemoryErr );
-       }
-
-       require_noerr( err, exit );
-
-       index = GetPrimaryInterface();
-
-       for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
-       {
-               if ( pAdapter->IpAddressList.IpAddress.String &&
-                    pAdapter->IpAddressList.IpAddress.String[0] &&
-                    pAdapter->GatewayList.IpAddress.String &&
-                    pAdapter->GatewayList.IpAddress.String[0] &&
-                    ( !index || ( pAdapter->Index == index ) ) )
-               {
-                       // Found one that will work
-
-                       char keyName[1024];
-
-                       _snprintf( keyName, 1024, "%s%s", "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\", pAdapter->AdapterName );
-
-                       err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyName, &key );
-                       require_noerr( err, exit );
-
-                       err = RegQueryString( key, "Domain", &domain, &dwSize, NULL );
-                       check_noerr( err );
-
-                       if ( !domain || !domain[0] )
-                       {
-                               if ( domain )
-                               {
-                                       free( domain );
-                                       domain = NULL;
-                               }
-
-                               err = RegQueryString( key, "DhcpDomain", &domain, &dwSize, NULL );
-                               check_noerr( err );
-                       }
-
-                       if ( domain && domain[0] ) mDNS_AddSearchDomain_CString(domain, mDNSNULL);
-
-                       break;
-               }
-       }
-
-exit:
-
-       if ( pAdapterInfo )
-       {
-               free( pAdapterInfo );
-       }
-
-       if ( domain )
-       {
-               free( domain );
-       }
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-}
-
-//===========================================================================================================================
-//     mDNSPlatformGetPrimaryInterface
-//===========================================================================================================================
-
-mDNSexport mStatus
-mDNSPlatformGetPrimaryInterface( mDNS * const m, mDNSAddr * v4, mDNSAddr * v6, mDNSAddr * router )
-{
-       IP_ADAPTER_INFO *       pAdapterInfo;
-       IP_ADAPTER_INFO *       pAdapter;
-       DWORD                           bufLen;
-       int                                     i;
-       BOOL                            found;
-       DWORD                           index;
-       mStatus                         err = mStatus_NoError;
-
-       DEBUG_UNUSED( m );
-
-       *v6 = zeroAddr;
-
-       pAdapterInfo    = NULL;
-       bufLen                  = 0;
-       found                   = FALSE;
-
-       for ( i = 0; i < 100; i++ )
-       {
-               err = GetAdaptersInfo( pAdapterInfo, &bufLen);
-
-               if ( err != ERROR_BUFFER_OVERFLOW )
-               {
-                       break;
-               }
-
-               pAdapterInfo = (IP_ADAPTER_INFO*) realloc( pAdapterInfo, bufLen );
-               require_action( pAdapterInfo, exit, err = kNoMemoryErr );
-       }
-
-       require_noerr( err, exit );
-
-       index = GetPrimaryInterface();
-
-       for ( pAdapter = pAdapterInfo; pAdapter; pAdapter = pAdapter->Next )
-       {
-               if ( pAdapter->IpAddressList.IpAddress.String &&
-                    pAdapter->IpAddressList.IpAddress.String[0] &&
-                    pAdapter->GatewayList.IpAddress.String &&
-                    pAdapter->GatewayList.IpAddress.String[0] &&
-                    ( StringToAddress( v4, pAdapter->IpAddressList.IpAddress.String ) == mStatus_NoError ) &&
-                    ( StringToAddress( router, pAdapter->GatewayList.IpAddress.String ) == mStatus_NoError ) &&
-                    ( !index || ( pAdapter->Index == index ) ) )
-               {
-                       // Found one that will work
-
-                       if ( pAdapter->AddressLength == sizeof( m->PrimaryMAC ) )
-                       {
-                               memcpy( &m->PrimaryMAC, pAdapter->Address, pAdapter->AddressLength );
-                       }
-
-                       found = TRUE;
-                       break;
-               }
-       }
-
-exit:
-
-       if ( pAdapterInfo )
-       {
-               free( pAdapterInfo );
-       }
-
-       return err;
-}
-
-mDNSexport void mDNSPlatformSendKeepalive(mDNSAddr *sadd, mDNSAddr *dadd, mDNSIPPort *lport, mDNSIPPort *rport, mDNSu32 seq, mDNSu32 ack, mDNSu16 win)
-{
-       (void) sadd;    // Unused
-       (void) dadd;    // Unused
-       (void) lport;   // Unused
-       (void) rport;   // Unused
-       (void) seq;     // Unused
-       (void) ack;     // Unused
-       (void) win;             // Unused
-}
-
-mDNSexport mStatus mDNSPlatformGetRemoteMacAddr(mDNS *const m, mDNSAddr *raddr)
-{
-       (void) m;               // Unused
-       (void) raddr;   // Unused
-
-       return mStatus_UnsupportedErr;
-}
-
-mDNSexport  mStatus    mDNSPlatformStoreSPSMACAddr(mDNSAddr *spsaddr, char *ifname)
-{
-       (void) spsaddr; // Unused
-       (void) ifname;  // Unused
-
-       return mStatus_UnsupportedErr;
-}
-
-mDNSexport  mStatus    mDNSPlatformClearSPSData(void)
-{
-       return mStatus_UnsupportedErr;
-}
-
-mDNSexport mStatus mDNSPlatformStoreOwnerOptRecord(char *ifname, DNSMessage *msg, int length)
-{
-       (void) ifname;  // Unused
-    (void) msg;     // Unused
-    (void) length;  // Unused
-       return mStatus_UnsupportedErr;
-}
-
-mDNSexport mStatus mDNSPlatformRetrieveTCPInfo(mDNS *const m, mDNSAddr *laddr, mDNSIPPort *lport, mDNSAddr *raddr, mDNSIPPort *rport, mDNSTCPInfo *mti)
-{
-       (void) m;       // Unused
-       (void) laddr;   // Unused
-       (void) raddr;   // Unused
-       (void) lport;   // Unused
-       (void) rport;   // Unused
-       (void) mti;     // Unused
-
-       return mStatus_UnsupportedErr;
-}
-
-mDNSexport void mDNSPlatformSetSocktOpt(void *sock, mDNSTransport_Type transType, mDNSAddr_Type addrType, const DNSQuestion *q)
-    {
-    (void) sock;
-    (void) transType;
-    (void) addrType;
-    (void) q;
-    }
-
-mDNSexport mDNSs32 mDNSPlatformGetPID()
-    {
-    return 0;
-    }
-
-mDNSexport mDNSu16 mDNSPlatformGetUDPPort(UDPSocket *sock)
-{
-       DEBUG_UNUSED( sock );
-       return (mDNSu16)-1;
-}
-
-mDNSexport mDNSBool mDNSPlatformInterfaceIsD2D(mDNSInterfaceID InterfaceID)
-{
-       DEBUG_UNUSED( InterfaceID );
-    
-       return mDNSfalse;
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     debugf_
-//===========================================================================================================================
-#if( MDNS_DEBUGMSGS )
-mDNSexport void        debugf_( const char *inFormat, ... )
-{
-       char            buffer[ 512 ];
-    va_list            args;
-    mDNSu32            length;
-       
-       va_start( args, inFormat );
-       length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-       va_end( args );
-       
-       dlog( kDebugLevelInfo, "%s\n", buffer );
-}
-#endif
-
-//===========================================================================================================================
-//     verbosedebugf_
-//===========================================================================================================================
-
-#if( MDNS_DEBUGMSGS > 1 )
-mDNSexport void        verbosedebugf_( const char *inFormat, ... )
-{
-       char            buffer[ 512 ];
-    va_list            args;
-    mDNSu32            length;
-       
-       va_start( args, inFormat );
-       length = mDNS_vsnprintf( buffer, sizeof( buffer ), inFormat, args );
-       va_end( args );
-       
-       dlog( kDebugLevelVerbose, "%s\n", buffer );
-}
-#endif
-
-#if 0
-#pragma mark -
-#pragma mark == Platform Internals  ==
-#endif
-
-//===========================================================================================================================
-//     SetupNiceName
-//===========================================================================================================================
-
-mStatus        SetupNiceName( mDNS * const inMDNS )
-{
-       HKEY            descKey = NULL;
-       char            utf8[ 256 ];
-       LPCTSTR         s;
-       LPWSTR          joinName;
-       NETSETUP_JOIN_STATUS joinStatus;
-       mStatus         err = 0;
-       DWORD           namelen;
-       BOOL            ok;
-       
-       check( inMDNS );
-       
-       // Set up the nice name.
-       utf8[0] = '\0';
-
-       // First try and open the registry key that contains the computer description value
-       s = TEXT("SYSTEM\\CurrentControlSet\\Services\\lanmanserver\\parameters");
-       err = RegOpenKeyEx( HKEY_LOCAL_MACHINE, s, 0, KEY_READ, &descKey);
-       check_translated_errno( err == 0, errno_compat(), kNameErr );
-
-       if ( !err )
-       {
-               TCHAR   desc[256];
-               DWORD   descSize = sizeof( desc );
-
-               // look for the computer description
-               err = RegQueryValueEx( descKey, TEXT("srvcomment"), 0, NULL, (LPBYTE) &desc, &descSize);
-               
-               if ( !err )
-               {
-                       err = TCHARtoUTF8( desc, utf8, sizeof( utf8 ) );
-               }
-
-               if ( err )
-               {
-                       utf8[ 0 ] = '\0';
-               }
-       }
-
-       // if we can't find it in the registry, then use the hostname of the machine
-       if ( err || ( utf8[ 0 ] == '\0' ) )
-       {
-               TCHAR hostname[256];
-               
-               namelen = sizeof( hostname ) / sizeof( TCHAR );
-
-               ok = GetComputerNameExW( ComputerNamePhysicalDnsHostname, hostname, &namelen );
-               err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
-               check_noerr( err );
-               
-               if( !err )
-               {
-                       err = TCHARtoUTF8( hostname, utf8, sizeof( utf8 ) );
-               }
-
-               if ( err )
-               {
-                       utf8[ 0 ] = '\0';
-               }
-       }
-
-       // if we can't get the hostname
-       if ( err || ( utf8[ 0 ] == '\0' ) )
-       {
-               // Invalidate name so fall back to a default name.
-               
-               strcpy_s( utf8, sizeof( utf8 ), kMDNSDefaultName );
-       }
-
-       utf8[ sizeof( utf8 ) - 1 ]      = '\0'; 
-       inMDNS->nicelabel.c[ 0 ]        = (mDNSu8) (strlen( utf8 ) < MAX_DOMAIN_LABEL ? strlen( utf8 ) : MAX_DOMAIN_LABEL);
-       memcpy( &inMDNS->nicelabel.c[ 1 ], utf8, inMDNS->nicelabel.c[ 0 ] );
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "nice name \"%.*s\"\n", inMDNS->nicelabel.c[ 0 ], &inMDNS->nicelabel.c[ 1 ] );
-       
-       if ( descKey )
-       {
-               RegCloseKey( descKey );
-       }
-
-       ZeroMemory( inMDNS->p->nbname, sizeof( inMDNS->p->nbname ) );
-       ZeroMemory( inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
-
-       namelen = sizeof( inMDNS->p->nbname );
-       ok = GetComputerNameExA( ComputerNamePhysicalNetBIOS, inMDNS->p->nbname, &namelen );
-       check( ok );
-       if ( ok ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios name \"%s\"\n", inMDNS->p->nbname );
-
-       err = NetGetJoinInformation( NULL, &joinName, &joinStatus );
-       check ( err == NERR_Success );
-       if ( err == NERR_Success )
-       {
-               if ( ( joinStatus == NetSetupWorkgroupName ) || ( joinStatus == NetSetupDomainName ) )
-               {
-                       err = TCHARtoUTF8( joinName, inMDNS->p->nbdomain, sizeof( inMDNS->p->nbdomain ) );
-                       check( !err );
-                       if ( !err ) dlog( kDebugLevelInfo, DEBUG_NAME "netbios domain/workgroup \"%s\"\n", inMDNS->p->nbdomain );
-               }
-
-               NetApiBufferFree( joinName );
-               joinName = NULL;
-       }
-
-       err = 0;
-
-       return( err );
-}
-
-//===========================================================================================================================
-//     SetupHostName
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupHostName( mDNS * const inMDNS )
-{
-       mStatus         err = 0;
-       char            tempString[ 256 ];
-       DWORD           tempStringLen;
-       domainlabel tempLabel;
-       BOOL            ok;
-       
-       check( inMDNS );
-
-       // Set up the nice name.
-       tempString[ 0 ] = '\0';
-
-       // use the hostname of the machine
-       tempStringLen = sizeof( tempString );
-       ok = GetComputerNameExA( ComputerNamePhysicalDnsHostname, tempString, &tempStringLen );
-       err = translate_errno( ok, (mStatus) GetLastError(), kNameErr );
-       check_noerr( err );
-
-       // if we can't get the hostname
-       if( err || ( tempString[ 0 ] == '\0' ) )
-       {
-               // Invalidate name so fall back to a default name.
-               
-               strcpy_s( tempString, sizeof( tempString ), kMDNSDefaultName );
-       }
-
-       tempString[ sizeof( tempString ) - 1 ] = '\0';
-       tempLabel.c[ 0 ] = (mDNSu8) (strlen( tempString ) < MAX_DOMAIN_LABEL ? strlen( tempString ) : MAX_DOMAIN_LABEL );
-       memcpy( &tempLabel.c[ 1 ], tempString, tempLabel.c[ 0 ] );
-       
-       // Set up the host name.
-       
-       ConvertUTF8PstringToRFC1034HostLabel( tempLabel.c, &inMDNS->hostlabel );
-       if( inMDNS->hostlabel.c[ 0 ] == 0 )
-       {
-               // Nice name has no characters that are representable as an RFC1034 name (e.g. Japanese) so use the default.
-               
-               MakeDomainLabelFromLiteralString( &inMDNS->hostlabel, kMDNSDefaultName );
-       }
-
-       check( inMDNS->hostlabel.c[ 0 ] != 0 );
-       
-       mDNS_SetFQDN( inMDNS );
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "host name \"%.*s\"\n", inMDNS->hostlabel.c[ 0 ], &inMDNS->hostlabel.c[ 1 ] );
-       
-       return( err );
-}
-
-//===========================================================================================================================
-//     SetupName
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupName( mDNS * const inMDNS )
-{
-       mStatus         err = 0;
-       
-       check( inMDNS );
-       
-       err = SetupNiceName( inMDNS );
-       check_noerr( err );
-
-       err = SetupHostName( inMDNS );
-       check_noerr( err );
-
-       return err;
-}
-
-//===========================================================================================================================
-//     SetupInterfaceList
-//===========================================================================================================================
-
-mStatus        SetupInterfaceList( mDNS * const inMDNS )
-{
-       mStatus                                         err;
-       mDNSInterfaceData **            next;
-       mDNSInterfaceData *                     ifd;
-       struct ifaddrs *                        addrs;
-       struct ifaddrs *                        p;
-       struct ifaddrs *                        loopbackv4;
-       struct ifaddrs *                        loopbackv6;
-       u_int                                           flagMask;
-       u_int                                           flagTest;
-       mDNSBool                                        foundv4;
-       mDNSBool                                        foundv6;
-       mDNSBool                                        foundUnicastSock4DestAddr;
-       mDNSBool                                        foundUnicastSock6DestAddr;
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list\n" );
-       check( inMDNS );
-       check( inMDNS->p );
-       
-       inMDNS->p->registeredLoopback4  = mDNSfalse;
-       inMDNS->p->nextDHCPLeaseExpires = 0x7FFFFFFF;
-       addrs                                                   = NULL;
-       foundv4                                                 = mDNSfalse;
-       foundv6                                                 = mDNSfalse;
-       foundUnicastSock4DestAddr               = mDNSfalse;
-       foundUnicastSock6DestAddr               = mDNSfalse;
-       
-       // Tear down any existing interfaces that may be set up.
-       
-       TearDownInterfaceList( inMDNS );
-
-       // Set up the name of this machine.
-       
-       err = SetupName( inMDNS );
-       check_noerr( err );
-
-       // Set up IPv4 interface(s). We have to set up IPv4 first so any IPv6 interface with an IPv4-routable address
-       // can refer to the IPv4 interface when it registers to allow DNS AAAA records over the IPv4 interface.
-       
-       err = getifaddrs( &addrs );
-       require_noerr( err, exit );
-       
-       loopbackv4      = NULL;
-       loopbackv6      = NULL;
-       next            = &inMDNS->p->interfaceList;
-
-       flagMask = IFF_UP | IFF_MULTICAST;
-       flagTest = IFF_UP | IFF_MULTICAST;
-       
-#if( MDNS_WINDOWS_ENABLE_IPV4 )
-       for( p = addrs; p; p = p->ifa_next )
-       {
-               if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
-               {
-                       continue;
-               }
-               if( p->ifa_flags & IFF_LOOPBACK )
-               {
-                       if( !loopbackv4 )
-                       {
-                               loopbackv4 = p;
-                       }
-                       continue;
-               }
-               dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n", 
-                       p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
-               
-               err = SetupInterface( inMDNS, p, &ifd );
-               require_noerr( err, exit );
-
-               // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
-               // register him, but we also want to note that we haven't found a v4 interface
-               // so that we register loopback so same host operations work
-               
-               if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
-               {
-                       foundv4 = mDNStrue;
-               }
-
-               if ( p->ifa_dhcpEnabled && ( p->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
-               {
-                       inMDNS->p->nextDHCPLeaseExpires = p->ifa_dhcpLeaseExpires;
-               }
-
-               // If we're on a platform that doesn't have WSARecvMsg(), there's no way
-               // of determing the destination address of a packet that is sent to us.
-               // For multicast packets, that's easy to determine.  But for the unicast
-               // sockets, we'll fake it by taking the address of the first interface
-               // that is successfully setup.
-
-               if ( !foundUnicastSock4DestAddr )
-               {
-                       inMDNS->p->unicastSock4.addr = ifd->interfaceInfo.ip;
-                       foundUnicastSock4DestAddr = TRUE;
-               }
-                       
-               *next = ifd;
-               next  = &ifd->next;
-               ++inMDNS->p->interfaceCount;
-       }
-#endif
-       
-       // Set up IPv6 interface(s) after IPv4 is set up (see IPv4 notes above for reasoning).
-       
-#if( MDNS_WINDOWS_ENABLE_IPV6 )
-
-       if ( gEnableIPv6 )
-       {
-               for( p = addrs; p; p = p->ifa_next )
-               {
-                       if( !p->ifa_addr || ( p->ifa_addr->sa_family != AF_INET6 ) || ( ( p->ifa_flags & flagMask ) != flagTest ) )
-                       {
-                               continue;
-                       }
-                       if( p->ifa_flags & IFF_LOOPBACK )
-                       {
-                               if( !loopbackv6 )
-                               {
-                                       loopbackv6 = p;
-                               }
-                               continue;
-                       }
-                       dlog( kDebugLevelVerbose, DEBUG_NAME "Interface %40s (0x%08X) %##a\n", 
-                               p->ifa_name ? p->ifa_name : "<null>", p->ifa_extra.index, p->ifa_addr );
-                       
-                       err = SetupInterface( inMDNS, p, &ifd );
-                       require_noerr( err, exit );
-                                       
-                       // If this guy is point-to-point (ifd->interfaceInfo.McastTxRx == 0 ) we still want to
-                       // register him, but we also want to note that we haven't found a v4 interface
-                       // so that we register loopback so same host operations work
-                       
-                       if ( ifd->interfaceInfo.McastTxRx == mDNStrue )
-                       {
-                               foundv6 = mDNStrue;
-                       }
-
-                       // If we're on a platform that doesn't have WSARecvMsg(), there's no way
-                       // of determing the destination address of a packet that is sent to us.
-                       // For multicast packets, that's easy to determine.  But for the unicast
-                       // sockets, we'll fake it by taking the address of the first interface
-                       // that is successfully setup.
-
-                       if ( !foundUnicastSock6DestAddr )
-                       {
-                               inMDNS->p->unicastSock6.addr = ifd->interfaceInfo.ip;
-                               foundUnicastSock6DestAddr = TRUE;
-                       }
-
-                       *next = ifd;
-                       next  = &ifd->next;
-                       ++inMDNS->p->interfaceCount;
-               }
-       }
-
-#endif
-
-       // If there are no real interfaces, but there is a loopback interface, use that so same-machine operations work.
-
-#if( !MDNS_WINDOWS_ENABLE_IPV4 && !MDNS_WINDOWS_ENABLE_IPV6 )
-       
-       flagMask |= IFF_LOOPBACK;
-       flagTest |= IFF_LOOPBACK;
-       
-       for( p = addrs; p; p = p->ifa_next )
-       {
-               if( !p->ifa_addr || ( ( p->ifa_flags & flagMask ) != flagTest ) )
-               {
-                       continue;
-               }
-               if( ( p->ifa_addr->sa_family != AF_INET ) && ( p->ifa_addr->sa_family != AF_INET6 ) )
-               {
-                       continue;
-               }
-               
-               v4loopback = p;
-               break;
-       }
-       
-#endif
-       
-       if ( !foundv4 && loopbackv4 )
-       {
-               dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n", 
-                       loopbackv4->ifa_name ? loopbackv4->ifa_name : "<null>", loopbackv4->ifa_extra.index, loopbackv4->ifa_addr );
-               
-               err = SetupInterface( inMDNS, loopbackv4, &ifd );
-               require_noerr( err, exit );
-
-               inMDNS->p->registeredLoopback4 = mDNStrue;
-               
-#if( MDNS_WINDOWS_ENABLE_IPV4 )
-
-               // If we're on a platform that doesn't have WSARecvMsg(), there's no way
-               // of determing the destination address of a packet that is sent to us.
-               // For multicast packets, that's easy to determine.  But for the unicast
-               // sockets, we'll fake it by taking the address of the first interface
-               // that is successfully setup.
-
-               if ( !foundUnicastSock4DestAddr )
-               {
-                       inMDNS->p->unicastSock4.addr = ifd->sock.addr;
-                       foundUnicastSock4DestAddr = TRUE;
-               }
-#endif
-
-               *next = ifd;
-               next  = &ifd->next;
-               ++inMDNS->p->interfaceCount;
-       }
-
-       if ( !foundv6 && loopbackv6 )
-       {
-               dlog( kDebugLevelInfo, DEBUG_NAME "Interface %40s (0x%08X) %##a\n", 
-                       loopbackv6->ifa_name ? loopbackv6->ifa_name : "<null>", loopbackv6->ifa_extra.index, loopbackv6->ifa_addr );
-               
-               err = SetupInterface( inMDNS, loopbackv6, &ifd );
-               require_noerr( err, exit );
-               
-#if( MDNS_WINDOWS_ENABLE_IPV6 )
-
-               if ( gEnableIPv6 )
-               {
-                       // If we're on a platform that doesn't have WSARecvMsg(), there's no way
-                       // of determing the destination address of a packet that is sent to us.
-                       // For multicast packets, that's easy to determine.  But for the unicast
-                       // sockets, we'll fake it by taking the address of the first interface
-                       // that is successfully setup.
-
-                       if ( !foundUnicastSock6DestAddr )
-                       {
-                               inMDNS->p->unicastSock6.addr = ifd->sock.addr;
-                               foundUnicastSock6DestAddr = TRUE;
-                       }
-               }
-
-#endif
-
-               *next = ifd;
-               next  = &ifd->next;
-               ++inMDNS->p->interfaceCount;
-       }
-
-       CheckFileShares( inMDNS );
-
-exit:
-       if( err )
-       {
-               TearDownInterfaceList( inMDNS );
-       }
-       if( addrs )
-       {
-               freeifaddrs( addrs );
-       }
-       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface list done (err=%d %m)\n", err, err );
-       return( err );
-}
-
-//===========================================================================================================================
-//     TearDownInterfaceList
-//===========================================================================================================================
-
-mStatus        TearDownInterfaceList( mDNS * const inMDNS )
-{
-       mDNSInterfaceData **            p;
-       mDNSInterfaceData *             ifd;
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list\n" );
-       check( inMDNS );
-       check( inMDNS->p );
-
-       // Free any interfaces that were previously marked inactive and are no longer referenced by the mDNS cache.
-       // Interfaces are marked inactive, but not deleted immediately if they were still referenced by the mDNS cache
-       // so that remove events that occur after an interface goes away can still report the correct interface.
-
-       p = &inMDNS->p->inactiveInterfaceList;
-       while( *p )
-       {
-               ifd = *p;
-               if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) ifd ) > 0 )
-               {
-                       p = &ifd->next;
-                       continue;
-               }
-               
-               dlog( kDebugLevelInfo, DEBUG_NAME "freeing unreferenced, inactive interface %#p %#a\n", ifd, &ifd->interfaceInfo.ip );
-               *p = ifd->next;
-
-               QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) ifd );
-       }
-
-       // Tear down all the interfaces.
-       
-       while( inMDNS->p->interfaceList )
-       {
-               ifd = inMDNS->p->interfaceList;
-               inMDNS->p->interfaceList = ifd->next;
-               
-               TearDownInterface( inMDNS, ifd );
-       }
-       inMDNS->p->interfaceCount = 0;
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "tearing down interface list done\n" );
-       return( mStatus_NoError );
-}
-
-//===========================================================================================================================
-//     SetupInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupInterface( mDNS * const inMDNS, const struct ifaddrs *inIFA, mDNSInterfaceData **outIFD )
-{
-       mDNSInterfaceData       *       ifd;
-       mDNSInterfaceData       *       p;
-       mStatus                                 err;
-       
-       ifd = NULL;
-       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface\n" );
-       check( inMDNS );
-       check( inMDNS->p );
-       check( inIFA );
-       check( inIFA->ifa_addr );
-       check( outIFD );
-       
-       // Allocate memory for the interface and initialize it.
-       
-       ifd = (mDNSInterfaceData *) calloc( 1, sizeof( *ifd ) );
-       require_action( ifd, exit, err = mStatus_NoMemoryErr );
-       ifd->sock.fd    = kInvalidSocketRef;
-       ifd->sock.ifd   = ifd;
-       ifd->sock.next  = NULL;
-       ifd->sock.m             = inMDNS;
-       ifd->index              = inIFA->ifa_extra.index;
-       ifd->scopeID    = inIFA->ifa_extra.index;
-       check( strlen( inIFA->ifa_name ) < sizeof( ifd->name ) );
-       strncpy( ifd->name, inIFA->ifa_name, sizeof( ifd->name ) - 1 );
-       ifd->name[ sizeof( ifd->name ) - 1 ] = '\0';
-       
-       strncpy(ifd->interfaceInfo.ifname, inIFA->ifa_name, sizeof(ifd->interfaceInfo.ifname));
-       ifd->interfaceInfo.ifname[sizeof(ifd->interfaceInfo.ifname)-1] = 0;
-       
-       // We always send and receive using IPv4, but 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.
-       
-       ifd->interfaceInfo.McastTxRx   = ( ( inIFA->ifa_flags & IFF_MULTICAST ) && !( inIFA->ifa_flags & IFF_POINTTOPOINT ) ) ? mDNStrue : mDNSfalse;
-       ifd->interfaceInfo.InterfaceID = NULL;
-
-       for( p = inMDNS->p->interfaceList; p; p = p->next )
-       {
-               if ( strcmp( p->name, ifd->name ) == 0 )
-               {
-                       if (!ifd->interfaceInfo.InterfaceID)
-                       {
-                               ifd->interfaceInfo.InterfaceID  = (mDNSInterfaceID) p;
-                       }
-
-                       if ( ( inIFA->ifa_addr->sa_family != AF_INET ) &&
-                            ( p->interfaceInfo.ip.type == mDNSAddrType_IPv4 ) &&
-                            ( p->interfaceInfo.ip.ip.v4.b[ 0 ] != 169 || p->interfaceInfo.ip.ip.v4.b[ 1 ] != 254 ) )
-                       {
-                               ifd->interfaceInfo.McastTxRx = mDNSfalse;
-                       }
-
-                       break;
-               }
-       }
-
-       if ( !ifd->interfaceInfo.InterfaceID )
-       {
-               ifd->interfaceInfo.InterfaceID = (mDNSInterfaceID) ifd;
-       }
-
-       // Set up a socket for this interface (if needed).
-       
-       if( ifd->interfaceInfo.McastTxRx )
-       {
-               DWORD size;
-                       
-               err = SetupSocket( inMDNS, inIFA->ifa_addr, MulticastDNSPort, &ifd->sock.fd );
-               require_noerr( err, exit );
-               ifd->sock.addr = ( inIFA->ifa_addr->sa_family == AF_INET6 ) ? AllDNSLinkGroup_v6 : AllDNSLinkGroup_v4;
-               ifd->sock.port = MulticastDNSPort;
-               
-               // Get a ptr to the WSARecvMsg function, if supported. Otherwise, we'll fallback to recvfrom.
-
-               err = WSAIoctl( ifd->sock.fd, SIO_GET_EXTENSION_FUNCTION_POINTER, &kWSARecvMsgGUID, sizeof( kWSARecvMsgGUID ), &ifd->sock.recvMsgPtr, sizeof( ifd->sock.recvMsgPtr ), &size, NULL, NULL );
-
-               if ( err )
-               {
-                       ifd->sock.recvMsgPtr = NULL;
-               }
-       }
-
-       if ( inIFA->ifa_dhcpEnabled && ( inIFA->ifa_dhcpLeaseExpires < inMDNS->p->nextDHCPLeaseExpires ) )
-       {
-               inMDNS->p->nextDHCPLeaseExpires = inIFA->ifa_dhcpLeaseExpires;
-       }
-
-       ifd->interfaceInfo.NetWake = inIFA->ifa_womp;
-
-       // Register this interface with mDNS.
-       
-       err = SockAddrToMDNSAddr( inIFA->ifa_addr, &ifd->interfaceInfo.ip, NULL );
-       require_noerr( err, exit );
-       
-       err = SockAddrToMDNSAddr( inIFA->ifa_netmask, &ifd->interfaceInfo.mask, NULL );
-       require_noerr( err, exit );
-
-       memcpy( ifd->interfaceInfo.MAC.b, inIFA->ifa_physaddr, sizeof( ifd->interfaceInfo.MAC.b ) );
-       
-       ifd->interfaceInfo.Advertise = ( mDNSu8 ) inMDNS->AdvertiseLocalAddresses;
-
-       if ( ifd->sock.fd != kInvalidSocketRef )
-       {
-               err = mDNSPollRegisterSocket( ifd->sock.fd, FD_READ, UDPSocketNotification, &ifd->sock );
-               require_noerr( err, exit );
-       }
-
-    // If interface is a direct link, address record will be marked as kDNSRecordTypeKnownUnique
-    // and skip the probe phase of the probe/announce packet sequence.
-    ifd->interfaceInfo.DirectLink = mDNSfalse;
-    ifd->interfaceInfo.SupportsUnicastMDNSResponse = mDNStrue;
-
-       err = mDNS_RegisterInterface( inMDNS, &ifd->interfaceInfo, NormalActivation );
-       require_noerr( err, exit );
-       ifd->hostRegistered = mDNStrue;
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "Registered interface %##a with mDNS\n", inIFA->ifa_addr );
-       
-       // Success!
-       
-       *outIFD = ifd;
-       ifd = NULL;
-       
-exit:
-
-       if( ifd )
-       {
-               TearDownInterface( inMDNS, ifd );
-       }
-       dlog( kDebugLevelTrace, DEBUG_NAME "setting up interface done (err=%d %m)\n", err, err );
-       return( err );
-}
-
-//===========================================================================================================================
-//     TearDownInterface
-//===========================================================================================================================
-
-mDNSlocal mStatus      TearDownInterface( mDNS * const inMDNS, mDNSInterfaceData *inIFD )
-{      
-       check( inMDNS );
-       check( inIFD );
-       
-       // Deregister this interface with mDNS.
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "Deregistering interface %#a with mDNS\n", &inIFD->interfaceInfo.ip );
-       
-       if( inIFD->hostRegistered )
-       {
-               inIFD->hostRegistered = mDNSfalse;
-               mDNS_DeregisterInterface( inMDNS, &inIFD->interfaceInfo, NormalActivation );
-       }
-       
-       // Tear down the multicast socket.
-       
-       UDPCloseSocket( &inIFD->sock );
-
-       // If the interface is still referenced by items in the mDNS cache then put it on the inactive list. This keeps 
-       // the InterfaceID valid so remove events report the correct interface. If it is no longer referenced, free it.
-
-       if( NumCacheRecordsForInterfaceID( inMDNS, (mDNSInterfaceID) inIFD ) > 0 )
-       {
-               inIFD->next = inMDNS->p->inactiveInterfaceList;
-               inMDNS->p->inactiveInterfaceList = inIFD;
-               dlog( kDebugLevelInfo, DEBUG_NAME "deferring free of interface %#p %#a\n", inIFD, &inIFD->interfaceInfo.ip );
-       }
-       else
-       {
-               dlog( kDebugLevelInfo, DEBUG_NAME "freeing interface %#p %#a immediately\n", inIFD, &inIFD->interfaceInfo.ip );
-               QueueUserAPC( ( PAPCFUNC ) FreeInterface, inMDNS->p->mainThread, ( ULONG_PTR ) inIFD );
-       }
-
-       return( mStatus_NoError );
-}
-
-mDNSlocal void CALLBACK FreeInterface( mDNSInterfaceData *inIFD )
-{
-       free( inIFD );
-}
-
-//===========================================================================================================================
-//     SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus      SetupSocket( mDNS * const inMDNS, const struct sockaddr *inAddr, mDNSIPPort port, SocketRef *outSocketRef  )
-{
-       mStatus                 err;
-       SocketRef               sock;
-       int                             option;
-       DWORD                   bytesReturned = 0;
-       BOOL                    behavior = FALSE;
-       
-       DEBUG_UNUSED( inMDNS );
-       
-       dlog( kDebugLevelTrace, DEBUG_NAME "setting up socket %##a\n", inAddr );
-       check( inMDNS );
-       check( outSocketRef );
-       
-       // Set up an IPv4 or IPv6 UDP socket.
-       
-       sock = socket( inAddr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
-       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-               
-       // Turn on reuse address option so multiple servers can listen for Multicast DNS packets,
-       // if we're creating a multicast socket
-       
-       if ( !mDNSIPPortIsZero( port ) )
-       {
-               option = 1;
-               err = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
-       }
-
-       // <rdar://problem/7894393> Bonjour for Windows broken on Windows XP
-       //
-       // Not sure why, but the default behavior for sockets is to behave incorrectly
-       // when using them in Overlapped I/O mode on XP. According to MSDN:
-       //
-       // SIO_UDP_CONNRESET (opcode setting: I, T==3)
-       //     Windows XP:  Controls whether UDP PORT_UNREACHABLE messages are reported. Set to TRUE to enable reporting.
-       //     Set to FALSE to disable reporting.
-       //
-       // Packet traces from misbehaving Bonjour installations showed that ICMP port unreachable
-       // messages were being sent to us after we sent out packets to a multicast address. This is clearly
-       // incorrect behavior, but should be harmless. However, after receiving a port unreachable error, WinSock
-       // will no longer receive any packets from that socket, which is not harmless. This behavior is only
-       // seen on XP.
-       //
-       // So we turn off port unreachable reporting to make sure our sockets that are reading
-       // multicast packets function correctly under all circumstances.
-
-       err = WSAIoctl( sock, SIO_UDP_CONNRESET, &behavior, sizeof(behavior), NULL, 0, &bytesReturned, NULL, NULL );
-       check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-       if( inAddr->sa_family == AF_INET )
-       {
-               mDNSv4Addr                              ipv4;
-               struct sockaddr_in              sa4;
-               struct ip_mreq                  mreqv4;
-               
-               // Bind the socket to the desired port
-               
-               ipv4.NotAnInteger       = ( (const struct sockaddr_in *) inAddr )->sin_addr.s_addr;
-               mDNSPlatformMemZero( &sa4, sizeof( sa4 ) );
-               sa4.sin_family          = AF_INET;
-               sa4.sin_port            = port.NotAnInteger;
-               sa4.sin_addr.s_addr     = ipv4.NotAnInteger;
-               
-               err = bind( sock, (struct sockaddr *) &sa4, sizeof( sa4 ) );
-               check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-               
-               // Turn on option to receive destination addresses and receiving interface.
-               
-               option = 1;
-               err = setsockopt( sock, IPPROTO_IP, IP_PKTINFO, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
-               if ( !mDNSIPPortIsZero( port ) )
-               {
-                       // Join the all-DNS multicast group so we receive Multicast DNS packets
-
-                       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 );
-               
-                       // Specify the interface to send multicast packets on this socket.
-               
-                       sa4.sin_addr.s_addr = ipv4.NotAnInteger;
-                       err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, (char *) &sa4.sin_addr, sizeof( sa4.sin_addr ) );
-                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
-                       // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-               
-                       option = 1;
-                       err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
-                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               }
-
-               // Send unicast packets with TTL 255 (helps against spoofing).
-               
-               option = 255;
-               err = setsockopt( sock, IPPROTO_IP, IP_TTL, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-               // Send multicast packets with TTL 255 (helps against spoofing).
-               
-               option = 255;
-               err = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-       }
-       else if( inAddr->sa_family == AF_INET6 )
-       {
-               struct sockaddr_in6 *           sa6p;
-               struct sockaddr_in6                     sa6;
-               struct ipv6_mreq                        mreqv6;
-               
-               sa6p = (struct sockaddr_in6 *) inAddr;
-               
-               // Bind the socket to the desired port
-               
-               mDNSPlatformMemZero( &sa6, sizeof( sa6 ) );
-               sa6.sin6_family         = AF_INET6;
-               sa6.sin6_port           = port.NotAnInteger;
-               sa6.sin6_flowinfo       = 0;
-               sa6.sin6_addr           = sa6p->sin6_addr;
-               sa6.sin6_scope_id       = sa6p->sin6_scope_id;
-               
-               err = bind( sock, (struct sockaddr *) &sa6, sizeof( sa6 ) );
-               check_translated_errno( err == 0, errno_compat(), kUnknownErr );
-               
-               // Turn on option to receive destination addresses and receiving interface.
-               
-               option = 1;
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_PKTINFO, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
-               // We only want to receive IPv6 packets (not IPv4-mapped IPv6 addresses) because we have a separate socket 
-               // for IPv4, but the IPv6 stack in Windows currently doesn't support IPv4-mapped IPv6 addresses and doesn't
-               // support the IPV6_V6ONLY socket option so the following code would typically not be executed (or needed).
-               
-               #if( defined( IPV6_V6ONLY ) )
-                       option = 1;
-                       err = setsockopt( sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &option, sizeof( option ) );
-                       check_translated_errno( err == 0, errno_compat(), kOptionErr );         
-               #endif
-               
-               if ( !mDNSIPPortIsZero( port ) )
-               {
-                       // Join the all-DNS multicast group so we receive Multicast DNS packets.
-               
-                       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 );
-               
-                       // Specify the interface to send multicast packets on this socket.
-               
-                       option = (int) sa6p->sin6_scope_id;
-                       err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, (char *) &option, sizeof( option ) );
-                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               
-                       // Enable multicast loopback so we receive multicast packets we send (for same-machine operations).
-                       
-                       option = 1;
-                       err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &option, sizeof( option ) );
-                       check_translated_errno( err == 0, errno_compat(), kOptionErr );
-               }
-
-               // Send unicast packets with TTL 255 (helps against spoofing).
-               
-               option = 255;
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
-
-               // Send multicast packets with TTL 255 (helps against spoofing).
-                       
-               option = 255;
-               err = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &option, sizeof( option ) );
-               check_translated_errno( err == 0, errno_compat(), kOptionErr );
-       }
-       else
-       {
-               dlog( kDebugLevelError, DEBUG_NAME "%s: unsupport socket family (%d)\n", __ROUTINE__, inAddr->sa_family );
-               err = kUnsupportedErr;
-               goto exit;
-       }
-       
-       // Success!
-       
-       *outSocketRef = sock;
-       sock = kInvalidSocketRef;
-       err = mStatus_NoError;
-       
-exit:
-       if( IsValidSocket( sock ) )
-       {
-               close_compat( sock );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     SetupSocket
-//===========================================================================================================================
-
-mDNSlocal mStatus      SockAddrToMDNSAddr( const struct sockaddr * const inSA, mDNSAddr *outIP, mDNSIPPort *outPort )
-{
-       mStatus         err;
-       
-       check( inSA );
-       check( outIP );
-       
-       if( inSA->sa_family == AF_INET )
-       {
-               struct sockaddr_in *            sa4;
-               
-               sa4                                             = (struct sockaddr_in *) inSA;
-               outIP->type                             = mDNSAddrType_IPv4;
-               outIP->ip.v4.NotAnInteger       = sa4->sin_addr.s_addr;
-               if( outPort )
-               {
-                       outPort->NotAnInteger   = sa4->sin_port;
-               }
-               err = mStatus_NoError;
-       }
-       else if( inSA->sa_family == AF_INET6 )
-       {
-               struct sockaddr_in6 *           sa6;
-               
-               sa6                     = (struct sockaddr_in6 *) inSA;
-               outIP->type     = mDNSAddrType_IPv6;
-               outIP->ip.v6    = *( (mDNSv6Addr *) &sa6->sin6_addr );
-               if( IN6_IS_ADDR_LINKLOCAL( &sa6->sin6_addr ) )
-               {
-                       outIP->ip.v6.w[ 1 ] = 0;
-               }
-               if( outPort )
-               {
-                       outPort->NotAnInteger = sa6->sin6_port;
-               }
-               err = mStatus_NoError;
-       }
-       else
-       {
-               dlog( kDebugLevelError, DEBUG_NAME "%s: invalid sa_family %d", __ROUTINE__, inSA->sa_family );
-               err = mStatus_BadParamErr;
-       }
-       return( err );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     UDPSocketNotification
-//===========================================================================================================================
-
-mDNSlocal void CALLBACK
-UDPSocketNotification( SOCKET sock, LPWSANETWORKEVENTS event, void *context )
-{
-       UDPSocket                               *udpSock = ( UDPSocket* ) context;
-       WSAMSG                                  wmsg;
-       WSABUF                                  wbuf;
-       struct sockaddr_storage sockSrcAddr;            // This is filled in by the WSARecv* function
-       INT                                             sockSrcAddrLen;         // See above
-       mDNSAddr                                srcAddr;
-       mDNSInterfaceID                 iid;
-       mDNSIPPort                              srcPort;
-       mDNSAddr                                dstAddr;
-       mDNSIPPort                              dstPort;
-       uint8_t                                 controlBuffer[ 128 ];
-       mDNSu8                          *       end;
-       int                                             num;
-       DWORD                                   numTries;
-       mStatus                                 err;
-
-       DEBUG_UNUSED( sock );
-       DEBUG_UNUSED( event );
-
-       require_action( udpSock != NULL, exit, err = mStatus_BadStateErr );
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "%s: sock = %d\n", __ROUTINE__, udpSock->fd );
-       
-       // Initialize the buffer structure
-
-       wbuf.buf                = (char *) &udpSock->packet;
-       wbuf.len                = (u_long) sizeof( udpSock->packet );
-       sockSrcAddrLen  = sizeof( sockSrcAddr );
-
-       numTries = 0;
-
-       do
-       {
-               if ( udpSock->recvMsgPtr )
-               {
-                       DWORD size;
-
-                       wmsg.name                       = ( LPSOCKADDR ) &sockSrcAddr;
-                       wmsg.namelen            = sockSrcAddrLen;
-                       wmsg.lpBuffers          = &wbuf;
-                       wmsg.dwBufferCount      = 1;
-                       wmsg.Control.buf        = ( CHAR* ) controlBuffer;
-                       wmsg.Control.len        = sizeof( controlBuffer );
-                       wmsg.dwFlags            = 0;
-
-                       err = udpSock->recvMsgPtr( udpSock->fd, &wmsg, &size, NULL, NULL );
-                       err = translate_errno( ( err == 0 ), (OSStatus) WSAGetLastError(), kUnknownErr ); 
-                       num = ( int ) size;
-
-                       // <rdar://problem/7824093> iTunes 9.1 fails to install with Bonjour service on Windows 7 Ultimate
-                       //
-                       // There seems to be a bug in some network device drivers that involves calling WSARecvMsg().
-                       // Although all the parameters to WSARecvMsg() are correct, it returns a
-                       // WSAEFAULT error code when there is no actual error. We have found experientially that falling
-                       // back to using WSARecvFrom() when this happens will work correctly.
-
-                       if ( err == WSAEFAULT ) udpSock->recvMsgPtr = NULL;
-               }
-               else
-               {
-                       DWORD flags = 0;
-
-                       num = WSARecvFrom( udpSock->fd, &wbuf, 1, NULL, &flags, ( LPSOCKADDR ) &sockSrcAddr, &sockSrcAddrLen, NULL, NULL );
-                       err = translate_errno( ( num >= 0 ), ( OSStatus ) WSAGetLastError(), kUnknownErr );
-               }
-
-               // According to MSDN <http://msdn.microsoft.com/en-us/library/ms741687(VS.85).aspx>:
-               //
-               // "WSAECONNRESET: For a UDP datagram socket, this error would indicate that a previous
-               //                 send operation resulted in an ICMP "Port Unreachable" message."
-               //
-               // Because this is the case, we want to ignore this error and try again.  Just in case
-               // this is some kind of pathological condition, we'll break out of the retry loop 
-               // after 100 iterations
-
-               require_action( !err || ( err == WSAECONNRESET ) || ( err == WSAEFAULT ), exit, err = WSAGetLastError() );
-       }
-       while ( ( ( err == WSAECONNRESET ) || ( err == WSAEFAULT ) ) && ( numTries++ < 100 ) );
-       
-       require_noerr( err, exit );
-       
-       // Translate the source of this packet into mDNS data types
-
-       SockAddrToMDNSAddr( (struct sockaddr* ) &sockSrcAddr, &srcAddr, &srcPort );
-       
-       // Initialize the destination of this packet. Just in case
-       // we can't determine this info because we couldn't call
-       // WSARecvMsg (recvMsgPtr)
-
-       dstAddr = udpSock->addr;
-       dstPort = udpSock->port;
-
-       if ( udpSock->recvMsgPtr )
-       {
-               LPWSACMSGHDR    header;
-               LPWSACMSGHDR    last = NULL;
-               int                             count = 0;
-               
-               // Parse the control information. Reject packets received on the wrong interface.
-               
-               // <rdar://problem/7832196> INSTALL: Bonjour 2.0 on Windows can not start / stop
-               // 
-               // There seems to be an interaction between Bullguard and this next bit of code.
-               // When a user's machine is running Bullguard, the control information that is
-               // returned is corrupted, and the code would go into an infinite loop. We'll add
-               // two bits of defensive coding here. The first will check that each pointer to
-               // the LPWSACMSGHDR that is returned in the for loop is different than the last.
-               // This fixes the problem with Bullguard. The second will break out of this loop
-               // after 100 iterations, just in case the corruption isn't caught by the first
-               // check.
-
-               for ( header = WSA_CMSG_FIRSTHDR( &wmsg ); header; header = WSA_CMSG_NXTHDR( &wmsg, header ) )
-               {
-                       if ( ( header != last ) && ( ++count < 100 ) )
-                       {
-                               last = header;
-                                       
-                               if ( ( header->cmsg_level == IPPROTO_IP ) && ( header->cmsg_type == IP_PKTINFO ) )
-                               {
-                                       IN_PKTINFO * ipv4PacketInfo;
-                                       
-                                       ipv4PacketInfo = (IN_PKTINFO *) WSA_CMSG_DATA( header );
-
-                                       if ( udpSock->ifd != NULL )
-                                       {
-                                               require_action( ipv4PacketInfo->ipi_ifindex == udpSock->ifd->index, exit, err = ( DWORD ) kMismatchErr );
-                                       }
-
-                                       dstAddr.type                            = mDNSAddrType_IPv4;
-                                       dstAddr.ip.v4.NotAnInteger      = ipv4PacketInfo->ipi_addr.s_addr;
-                               }
-                               else if( ( header->cmsg_level == IPPROTO_IPV6 ) && ( header->cmsg_type == IPV6_PKTINFO ) )
-                               {
-                                       IN6_PKTINFO * ipv6PacketInfo;
-                                               
-                                       ipv6PacketInfo = (IN6_PKTINFO *) WSA_CMSG_DATA( header );
-               
-                                       if ( udpSock->ifd != NULL )
-                                       {
-                                               require_action( ipv6PacketInfo->ipi6_ifindex == ( udpSock->ifd->index - kIPv6IfIndexBase ), exit, err = ( DWORD ) kMismatchErr );
-                                       }
-
-                                       dstAddr.type    = mDNSAddrType_IPv6;
-                                       dstAddr.ip.v6   = *( (mDNSv6Addr *) &ipv6PacketInfo->ipi6_addr );
-                               }
-                       }
-                       else
-                       {
-                               static BOOL loggedMessage = FALSE;
-
-                               if ( !loggedMessage )
-                               {
-                                       LogMsg( "UDPEndRecv: WSARecvMsg control information error." );
-                                       loggedMessage = TRUE;
-                               }
-
-                               break;
-                       }
-               }
-       }
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "packet received\n" );
-       dlog( kDebugLevelChatty, DEBUG_NAME "    size      = %d\n", num );
-       dlog( kDebugLevelChatty, DEBUG_NAME "    src       = %#a:%u\n", &srcAddr, ntohs( srcPort.NotAnInteger ) );
-       dlog( kDebugLevelChatty, DEBUG_NAME "    dst       = %#a:%u\n", &dstAddr, ntohs( dstPort.NotAnInteger ) );
-       
-       if ( udpSock->ifd != NULL )
-       {
-               dlog( kDebugLevelChatty, DEBUG_NAME "    interface = %#a (index=0x%08X)\n", &udpSock->ifd->interfaceInfo.ip, udpSock->ifd->index );
-       }
-
-       dlog( kDebugLevelChatty, DEBUG_NAME "\n" );
-
-       iid = udpSock->ifd ? udpSock->ifd->interfaceInfo.InterfaceID : NULL;
-       end = ( (mDNSu8 *) &udpSock->packet ) + num;
-
-       mDNSCoreReceive( udpSock->m, &udpSock->packet, end, &srcAddr, srcPort, &dstAddr, dstPort, iid );
-
-exit:
-
-       return;
-}
-
-//===========================================================================================================================
-//     InterfaceListDidChange
-//===========================================================================================================================
-void InterfaceListDidChange( mDNS * const inMDNS )
-{
-       mStatus err;
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "interface list changed\n" );
-       check( inMDNS );
-       
-       // Tear down the existing interfaces and set up new ones using the new IP info.
-       
-       err = TearDownInterfaceList( inMDNS );
-       check_noerr( err );
-       
-       err = SetupInterfaceList( inMDNS );
-       check_noerr( err );
-               
-       err = uDNS_SetupDNSConfig( inMDNS );
-       check_noerr( err );
-       
-       // Inform clients of the change.
-       
-       mDNS_ConfigChanged(inMDNS);
-       
-       // Force mDNS to update.
-       
-       mDNSCoreMachineSleep( inMDNS, mDNSfalse ); // What is this for? Mac OS X does not do this
-}
-
-//===========================================================================================================================
-//     ComputerDescriptionDidChange
-//===========================================================================================================================
-void ComputerDescriptionDidChange( mDNS * const inMDNS )
-{      
-       dlog( kDebugLevelInfo, DEBUG_NAME "computer description has changed\n" );
-       check( inMDNS );
-
-       // redo the names
-       SetupNiceName( inMDNS );
-}
-
-//===========================================================================================================================
-//     TCPIPConfigDidChange
-//===========================================================================================================================
-void TCPIPConfigDidChange( mDNS * const inMDNS )
-{
-       mStatus         err;
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "TCP/IP config has changed\n" );
-       check( inMDNS );
-
-       err = uDNS_SetupDNSConfig( inMDNS );
-       check_noerr( err );
-}
-
-//===========================================================================================================================
-//     DynDNSConfigDidChange
-//===========================================================================================================================
-void DynDNSConfigDidChange( mDNS * const inMDNS )
-{
-       mStatus         err;
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "DynDNS config has changed\n" );
-       check( inMDNS );
-
-       SetDomainSecrets( inMDNS );
-
-       err = uDNS_SetupDNSConfig( inMDNS );
-       check_noerr( err );
-}
-
-//===========================================================================================================================
-//     FileSharingDidChange
-//===========================================================================================================================
-void FileSharingDidChange( mDNS * const inMDNS )
-{      
-       dlog( kDebugLevelInfo, DEBUG_NAME "File shares has changed\n" );
-       check( inMDNS );
-
-       CheckFileShares( inMDNS );
-}
-
-//===========================================================================================================================
-//     FilewallDidChange
-//===========================================================================================================================
-void FirewallDidChange( mDNS * const inMDNS )
-{      
-       dlog( kDebugLevelInfo, DEBUG_NAME "Firewall has changed\n" );
-       check( inMDNS );
-
-       CheckFileShares( inMDNS );
-}
-
-#if 0
-#pragma mark -
-#pragma mark == Utilities ==
-#endif
-
-//===========================================================================================================================
-//     getifaddrs
-//===========================================================================================================================
-
-mDNSlocal int  getifaddrs( struct ifaddrs **outAddrs )
-{
-       int             err;
-       
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-       
-       // Try to the load the GetAdaptersAddresses function from the IP Helpers DLL. This API is only available on Windows
-       // XP or later. Looking up the symbol at runtime allows the code to still work on older systems without that API.
-       
-       if( !gIPHelperLibraryInstance )
-       {
-               gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
-               if( gIPHelperLibraryInstance )
-               {
-                       gGetAdaptersAddressesFunctionPtr = 
-                               (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
-                       if( !gGetAdaptersAddressesFunctionPtr )
-                       {
-                               BOOL            ok;
-                               
-                               ok = FreeLibrary( gIPHelperLibraryInstance );
-                               check_translated_errno( ok, GetLastError(), kUnknownErr );
-                               gIPHelperLibraryInstance = NULL;
-                       }
-               }
-       }
-       
-       // Use the new IPv6-capable routine if supported. Otherwise, fall back to the old and compatible IPv4-only code.
-       // <rdar://problem/4278934>  Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 fails
-       // <rdar://problem/6145913>  Fall back to using getifaddrs_ipv4 if getifaddrs_ipv6 returns no addrs
-
-       if( !gGetAdaptersAddressesFunctionPtr || ( ( ( err = getifaddrs_ipv6( outAddrs ) ) != mStatus_NoError ) || ( ( outAddrs != NULL ) && ( *outAddrs == NULL ) ) ) )
-       {
-               err = getifaddrs_ipv4( outAddrs );
-               require_noerr( err, exit );
-       }
-       
-#else
-
-       err = getifaddrs_ipv4( outAddrs );
-       require_noerr( err, exit );
-
-#endif
-
-exit:
-       return( err );
-}
-
-#if( MDNS_WINDOWS_USE_IPV6_IF_ADDRS )
-//===========================================================================================================================
-//     getifaddrs_ipv6
-//===========================================================================================================================
-
-mDNSlocal int  getifaddrs_ipv6( struct ifaddrs **outAddrs )
-{
-       DWORD                                           err;
-       int                                                     i;
-       DWORD                                           flags;
-       struct ifaddrs *                        head;
-       struct ifaddrs **                       next;
-       IP_ADAPTER_ADDRESSES *          iaaList;
-       ULONG                                           iaaListSize;
-       IP_ADAPTER_ADDRESSES *          iaa;
-       size_t                                          size;
-       struct ifaddrs *                        ifa;
-       
-       check( gGetAdaptersAddressesFunctionPtr );
-       
-       head    = NULL;
-       next    = &head;
-       iaaList = NULL;
-       
-       // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
-       // This loops to handle the case where the interface changes in the window after getting the size, but before the
-       // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
-       
-       flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
-       i = 0;
-       for( ;; )
-       {
-               iaaListSize = 0;
-               err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
-               check( err == ERROR_BUFFER_OVERFLOW );
-               check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
-               
-               iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
-               require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
-               
-               err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
-               if( err == ERROR_SUCCESS ) break;
-               
-               free( iaaList );
-               iaaList = NULL;
-               ++i;
-               require( i < 100, exit );
-               dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
-       }
-       
-       for( iaa = iaaList; iaa; iaa = iaa->Next )
-       {
-               int                                                             addrIndex;
-               IP_ADAPTER_UNICAST_ADDRESS      *       addr;
-               DWORD                                                   ipv6IfIndex;
-               IP_ADAPTER_PREFIX                       *       firstPrefix;
-
-               if( iaa->IfIndex > 0xFFFFFF )
-               {
-                       dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv4 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->IfIndex );
-               }
-               if( iaa->Ipv6IfIndex > 0xFF )
-               {
-                       dlog( kDebugLevelAlert, DEBUG_NAME "%s: IPv6 ifindex out-of-range (0x%08X)\n", __ROUTINE__, iaa->Ipv6IfIndex );
-               }
-
-               // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the 
-               // following code to crash when iterating through the prefix list.  This seems
-               // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
-               // This shouldn't happen according to Microsoft docs which states:
-               //
-               //     "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
-               //
-               // So the data structure seems to be corrupted when we return from
-               // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
-               // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
-               // modify iaa to have the correct values.
-
-               if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
-               {
-                       ipv6IfIndex = iaa->Ipv6IfIndex;
-                       firstPrefix = iaa->FirstPrefix;
-               }
-               else
-               {
-                       ipv6IfIndex     = 0;
-                       firstPrefix = NULL;
-               }
-
-               // Skip pseudo and tunnel interfaces.
-               
-               if( ( ( ipv6IfIndex == 1 ) && ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
-               {
-                       continue;
-               }
-               
-               // Add each address as a separate interface to emulate the way getifaddrs works.
-               
-               for( addrIndex = 0, addr = iaa->FirstUnicastAddress; addr; ++addrIndex, addr = addr->Next )
-               {                       
-                       int                                             family;
-                       IP_ADAPTER_PREFIX *             prefix;
-                       uint32_t                                ipv4Index;
-                       struct sockaddr_in              ipv4Netmask;
-
-                       family = addr->Address.lpSockaddr->sa_family;
-                       if( ( family != AF_INET ) && ( family != AF_INET6 ) ) continue;
-                       
-                       // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
-                       // Seems as if the problem here is a buggy implementation of some network interface
-                       // driver. It is reporting that is has a link-local address when it is actually
-                       // disconnected. This was causing a problem in AddressToIndexAndMask.
-                       // The solution is to call AddressToIndexAndMask first, and if unable to lookup
-                       // the address, to ignore that address.
-
-                       ipv4Index = 0;
-                       memset( &ipv4Netmask, 0, sizeof( ipv4Netmask ) );
-                       
-                       if ( family == AF_INET )
-                       {
-                               err = AddressToIndexAndMask( addr->Address.lpSockaddr, &ipv4Index, ( struct sockaddr* ) &ipv4Netmask );
-                               
-                               if ( err )
-                               {
-                                       err = 0;
-                                       continue;
-                               }
-                       }
-
-                       ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
-                       require_action( ifa, exit, err = WSAENOBUFS );
-                       
-                       *next = ifa;
-                       next  = &ifa->ifa_next;
-                       
-                       // Get the name.
-                       
-                       size = strlen( iaa->AdapterName ) + 1;
-                       ifa->ifa_name = (char *) malloc( size );
-                       require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
-                       memcpy( ifa->ifa_name, iaa->AdapterName, size );
-                       
-                       // Get interface flags.
-                       
-                       ifa->ifa_flags = 0;
-                       if( iaa->OperStatus == IfOperStatusUp )                 ifa->ifa_flags |= IFF_UP;
-                       if( iaa->IfType == IF_TYPE_SOFTWARE_LOOPBACK )  ifa->ifa_flags |= IFF_LOOPBACK;
-                       else if ( IsPointToPoint( addr ) )                              ifa->ifa_flags |= IFF_POINTTOPOINT;
-                       if( !( iaa->Flags & IP_ADAPTER_NO_MULTICAST ) ) ifa->ifa_flags |= IFF_MULTICAST;
-
-                       
-                       // <rdar://problem/4045657> Interface index being returned is 512
-                       //
-                       // Windows does not have a uniform scheme for IPv4 and IPv6 interface indexes.
-                       // This code used to shift the IPv4 index up to ensure uniqueness between
-                       // it and IPv6 indexes.  Although this worked, it was somewhat confusing to developers, who
-                       // then see interface indexes passed back that don't correspond to anything
-                       // that is seen in Win32 APIs or command line tools like "route".  As a relatively
-                       // small percentage of developers are actively using IPv6, it seems to 
-                       // make sense to make our use of IPv4 as confusion free as possible.
-                       // So now, IPv6 interface indexes will be shifted up by a
-                       // constant value which will serve to uniquely identify them, and we will
-                       // leave IPv4 interface indexes unmodified.
-                       
-                       switch( family )
-                       {
-                               case AF_INET:  ifa->ifa_extra.index = iaa->IfIndex; break;
-                               case AF_INET6: ifa->ifa_extra.index = ipv6IfIndex + kIPv6IfIndexBase;    break;
-                               default: break;
-                       }
-
-                       // Get lease lifetime
-
-                       if ( ( iaa->IfType != IF_TYPE_SOFTWARE_LOOPBACK ) && ( addr->LeaseLifetime != 0 ) && ( addr->ValidLifetime != 0xFFFFFFFF ) )
-                       {
-                               ifa->ifa_dhcpEnabled            = TRUE;
-                               ifa->ifa_dhcpLeaseExpires       = time( NULL ) + addr->ValidLifetime;
-                       }
-                       else
-                       {
-                               ifa->ifa_dhcpEnabled            = FALSE;
-                               ifa->ifa_dhcpLeaseExpires       = 0;
-                       }
-
-                       if ( iaa->PhysicalAddressLength == sizeof( ifa->ifa_physaddr ) )
-                       {
-                               memcpy( ifa->ifa_physaddr, iaa->PhysicalAddress, iaa->PhysicalAddressLength );
-                       }
-
-                       // Because we don't get notified of womp changes, we're going to just assume
-                       // that all wired interfaces have it enabled. Before we go to sleep, we'll check
-                       // if the interface actually supports it, and update mDNS->SystemWakeOnLANEnabled
-                       // accordingly
-
-                       ifa->ifa_womp = ( iaa->IfType == IF_TYPE_ETHERNET_CSMACD ) ? mDNStrue : mDNSfalse;
-                       
-                       // Get address.
-                       
-                       switch( family )
-                       {
-                               case AF_INET:
-                               case AF_INET6:
-                                       ifa->ifa_addr = (struct sockaddr *) calloc( 1, (size_t) addr->Address.iSockaddrLength );
-                                       require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                                       memcpy( ifa->ifa_addr, addr->Address.lpSockaddr, (size_t) addr->Address.iSockaddrLength );
-                                       break;
-                               
-                               default:
-                                       break;
-                       }
-                       check( ifa->ifa_addr );
-                       
-                       // Get subnet mask (IPv4)/link prefix (IPv6). It is specified as a bit length (e.g. 24 for 255.255.255.0).
-
-                       switch ( family )
-                       {
-                               case AF_INET:
-                               {
-                                       struct sockaddr_in * sa4;
-                                       
-                                       sa4 = (struct sockaddr_in *) calloc( 1, sizeof( *sa4 ) );
-                                       require_action( sa4, exit, err = WSAENOBUFS );
-                                       sa4->sin_family = AF_INET;
-                                       sa4->sin_addr.s_addr = ipv4Netmask.sin_addr.s_addr;
-
-                                       dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv4 mask = %s\n", __ROUTINE__, inet_ntoa( sa4->sin_addr ) );
-                                       ifa->ifa_netmask = (struct sockaddr *) sa4;
-                                       break;
-                               }
-
-                               case AF_INET6:
-                               {
-                                       struct sockaddr_in6 *sa6;
-                                       char buf[ 256 ] = { 0 };
-                                       DWORD buflen = sizeof( buf );
-
-                                       sa6 = (struct sockaddr_in6 *) calloc( 1, sizeof( *sa6 ) );
-                                       require_action( sa6, exit, err = WSAENOBUFS );
-                                       sa6->sin6_family = AF_INET6;
-                                       memset( sa6->sin6_addr.s6_addr, 0xFF, sizeof( sa6->sin6_addr.s6_addr ) );
-                                       ifa->ifa_netmask = (struct sockaddr *) sa6;
-
-                                       for ( prefix = firstPrefix; prefix; prefix = prefix->Next )
-                                       {
-                                               IN6_ADDR        mask;
-                                               IN6_ADDR        maskedAddr;
-                                               int                     maskIndex;
-                                               DWORD           len;
-
-                                               // According to MSDN:
-                                               // "On Windows Vista and later, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
-                                               // include three IP adapter prefixes for each IP address assigned to the adapter. These include the host IP address prefix,
-                                               // the subnet IP address prefix, and the subnet broadcast IP address prefix.
-                                               // In addition, for each adapter there is a multicast address prefix and a broadcast address prefix.
-                                               // On Windows XP with SP1 and later prior to Windows Vista, the linked IP_ADAPTER_PREFIX structures pointed to by the FirstPrefix member
-                                               // include only a single IP adapter prefix for each IP address assigned to the adapter."
-                                               
-                                               // We're only interested in the subnet IP address prefix.  We'll determine if the prefix is the
-                                               // subnet prefix by masking our address with a mask (computed from the prefix length) and see if that is the same
-                                               // as the prefix address.
-
-                                               if ( ( prefix->PrefixLength == 0 ) ||
-                                                    ( prefix->PrefixLength > 128 ) ||
-                                                    ( addr->Address.iSockaddrLength != prefix->Address.iSockaddrLength ) ||
-                                                        ( memcmp( addr->Address.lpSockaddr, prefix->Address.lpSockaddr, addr->Address.iSockaddrLength ) == 0 ) )
-                                               {
-                                                       continue;
-                                               }
-
-                                               // Compute the mask
-
-                                               memset( mask.s6_addr, 0, sizeof( mask.s6_addr ) );
-
-                                               for ( len = (int) prefix->PrefixLength, maskIndex = 0; len > 0; len -= 8 )
-                                               {
-                                                       uint8_t maskByte = ( len >= 8 ) ? 0xFF : (uint8_t)( ( 0xFFU << ( 8 - len ) ) & 0xFFU );
-                                                       mask.s6_addr[ maskIndex++ ] = maskByte;
-                                               }
-
-                                               // Apply the mask
-
-                                               for ( i = 0; i < 16; i++ )
-                                               {
-                                                       maskedAddr.s6_addr[ i ] = ( ( struct sockaddr_in6* ) addr->Address.lpSockaddr )->sin6_addr.s6_addr[ i ] & mask.s6_addr[ i ];
-                                               }
-
-                                               // Compare
-
-                                               if ( memcmp( ( ( struct sockaddr_in6* ) prefix->Address.lpSockaddr )->sin6_addr.s6_addr, maskedAddr.s6_addr, sizeof( maskedAddr.s6_addr ) ) == 0 )
-                                               {
-                                                       memcpy( sa6->sin6_addr.s6_addr, mask.s6_addr, sizeof( mask.s6_addr ) );
-                                                       break;
-                                               }
-                                       }
-
-                                       WSAAddressToStringA( ( LPSOCKADDR ) sa6, sizeof( struct sockaddr_in6 ), NULL, buf, &buflen );
-                                       dlog( kDebugLevelInfo, DEBUG_NAME "%s: IPv6 mask = %s\n", __ROUTINE__, buf );                           
-
-                                       break;
-                               }
-                               
-                               default:
-                                       break;
-                       }
-               }
-       }
-       
-       // Success!
-       
-       if( outAddrs )
-       {
-               *outAddrs = head;
-               head = NULL;
-       }
-       err = ERROR_SUCCESS;
-       
-exit:
-       if( head )
-       {
-               freeifaddrs( head );
-       }
-       if( iaaList )
-       {
-               free( iaaList );
-       }
-       return( (int) err );
-}
-
-#endif // MDNS_WINDOWS_USE_IPV6_IF_ADDRS
-
-//===========================================================================================================================
-//     getifaddrs_ipv4
-//===========================================================================================================================
-
-mDNSlocal int  getifaddrs_ipv4( struct ifaddrs **outAddrs )
-{
-       int                                             err;
-       SOCKET                                  sock;
-       DWORD                                   size;
-       DWORD                                   actualSize;
-       INTERFACE_INFO *                buffer;
-       INTERFACE_INFO *                tempBuffer;
-       INTERFACE_INFO *                ifInfo;
-       int                                             n;
-       int                                             i;
-       struct ifaddrs *                head;
-       struct ifaddrs **               next;
-       struct ifaddrs *                ifa;
-       
-       sock    = INVALID_SOCKET;
-       buffer  = NULL;
-       head    = NULL;
-       next    = &head;
-       
-       // Get the interface list. WSAIoctl is called with SIO_GET_INTERFACE_LIST, but since this does not provide a 
-       // way to determine the size of the interface list beforehand, we have to start with an initial size guess and
-       // call WSAIoctl repeatedly with increasing buffer sizes until it succeeds. Limit this to 100 tries for safety.
-       
-       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       err = translate_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-               
-       n = 0;
-       size = 16 * sizeof( INTERFACE_INFO );
-       for( ;; )
-       {
-               tempBuffer = (INTERFACE_INFO *) realloc( buffer, size );
-               require_action( tempBuffer, exit, err = WSAENOBUFS );
-               buffer = tempBuffer;
-               
-               err = WSAIoctl( sock, SIO_GET_INTERFACE_LIST, NULL, 0, buffer, size, &actualSize, NULL, NULL );
-               if( err == 0 )
-               {
-                       break;
-               }
-               
-               ++n;
-               require_action( n < 100, exit, err = WSAEADDRNOTAVAIL );
-               
-               size += ( 16 * sizeof( INTERFACE_INFO ) );
-       }
-       check( actualSize <= size );
-       check( ( actualSize % sizeof( INTERFACE_INFO ) ) == 0 );
-       n = (int)( actualSize / sizeof( INTERFACE_INFO ) );
-       
-       // Process the raw interface list and build a linked list of IPv4 interfaces.
-       
-       for( i = 0; i < n; ++i )
-       {
-               uint32_t ifIndex;
-               struct sockaddr_in netmask;
-               
-               ifInfo = &buffer[ i ];
-               if( ifInfo->iiAddress.Address.sa_family != AF_INET )
-               {
-                       continue;
-               }
-               
-               // <rdar://problem/6220642> iTunes 8: Bonjour doesn't work after upgrading iTunes 8
-               // See comment in getifaddrs_ipv6
-
-               ifIndex = 0;
-               memset( &netmask, 0, sizeof( netmask ) );
-               err = AddressToIndexAndMask( ( struct sockaddr* ) &ifInfo->iiAddress.AddressIn, &ifIndex, ( struct sockaddr* ) &netmask );
-
-               if ( err )
-               {
-                       continue;
-               }
-
-               ifa = (struct ifaddrs *) calloc( 1, sizeof( struct ifaddrs ) );
-               require_action( ifa, exit, err = WSAENOBUFS );
-               
-               *next = ifa;
-               next  = &ifa->ifa_next;
-               
-               // Get the name.
-               
-               ifa->ifa_name = (char *) malloc( 16 );
-               require_action( ifa->ifa_name, exit, err = WSAENOBUFS );
-               _snprintf( ifa->ifa_name, 16, "%d", i + 1 );
-               
-               // Get interface flags.
-               
-               ifa->ifa_flags = (u_int) ifInfo->iiFlags;
-               
-               // Get addresses.
-               
-               if ( ifInfo->iiAddress.Address.sa_family == AF_INET )
-               {
-                       struct sockaddr_in *            sa4;
-                       
-                       sa4 = &ifInfo->iiAddress.AddressIn;
-                       ifa->ifa_addr = (struct sockaddr *) calloc( 1, sizeof( *sa4 ) );
-                       require_action( ifa->ifa_addr, exit, err = WSAENOBUFS );
-                       memcpy( ifa->ifa_addr, sa4, sizeof( *sa4 ) );
-
-                       ifa->ifa_netmask = (struct sockaddr*) calloc(1, sizeof( *sa4 ) );
-                       require_action( ifa->ifa_netmask, exit, err = WSAENOBUFS );
-
-                       // <rdar://problem/4076478> Service won't start on Win2K. The address
-                       // family field was not being initialized.
-
-                       ifa->ifa_netmask->sa_family = AF_INET;
-                       ( ( struct sockaddr_in* ) ifa->ifa_netmask )->sin_addr = netmask.sin_addr;
-                       ifa->ifa_extra.index = ifIndex;
-               }
-               else
-               {
-                       // Emulate an interface index.
-               
-                       ifa->ifa_extra.index = (uint32_t)( i + 1 );
-               }
-       }
-       
-       // Success!
-       
-       if( outAddrs )
-       {
-               *outAddrs = head;
-               head = NULL;
-       }
-       err = 0;
-       
-exit:
-
-       if( head )
-       {
-               freeifaddrs( head );
-       }
-       if( buffer )
-       {
-               free( buffer );
-       }
-       if( sock != INVALID_SOCKET )
-       {
-               closesocket( sock );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     freeifaddrs
-//===========================================================================================================================
-
-mDNSlocal void freeifaddrs( struct ifaddrs *inIFAs )
-{
-       struct ifaddrs *                p;
-       struct ifaddrs *                q;
-       
-       // Free each piece of the structure. Set to null after freeing to handle macro-aliased fields.
-       
-       for( p = inIFAs; p; p = q )
-       {
-               q = p->ifa_next;
-               
-               if( p->ifa_name )
-               {
-                       free( p->ifa_name );
-                       p->ifa_name = NULL;
-               }
-               if( p->ifa_addr )
-               {
-                       free( p->ifa_addr );
-                       p->ifa_addr = NULL;
-               }
-               if( p->ifa_netmask )
-               {
-                       free( p->ifa_netmask );
-                       p->ifa_netmask = NULL;
-               }
-               if( p->ifa_broadaddr )
-               {
-                       free( p->ifa_broadaddr );
-                       p->ifa_broadaddr = NULL;
-               }
-               if( p->ifa_dstaddr )
-               {
-                       free( p->ifa_dstaddr );
-                       p->ifa_dstaddr = NULL;
-               }
-               if( p->ifa_data )
-               {
-                       free( p->ifa_data );
-                       p->ifa_data = NULL;
-               }
-               free( p );
-       }
-}
-
-//===========================================================================================================================
-//     GetPrimaryInterface
-//===========================================================================================================================
-
-mDNSlocal DWORD
-GetPrimaryInterface()
-{
-       PMIB_IPFORWARDTABLE     pIpForwardTable = NULL;
-       DWORD                           dwSize                  = 0;
-       BOOL                            bOrder                  = FALSE;
-       OSStatus                        err;
-       DWORD                           index                   = 0;
-       DWORD                           metric                  = 0;
-       unsigned long int       i;
-
-       // Find out how big our buffer needs to be.
-
-       err = GetIpForwardTable(NULL, &dwSize, bOrder);
-       require_action( err == ERROR_INSUFFICIENT_BUFFER, exit, err = kUnknownErr );
-
-       // Allocate the memory for the table
-
-       pIpForwardTable = (PMIB_IPFORWARDTABLE) malloc( dwSize );
-       require_action( pIpForwardTable, exit, err = kNoMemoryErr );
-  
-       // Now get the table.
-
-       err = GetIpForwardTable(pIpForwardTable, &dwSize, bOrder);
-       require_noerr( err, exit );
-
-       // Search for the row in the table we want.
-
-       for ( i = 0; i < pIpForwardTable->dwNumEntries; i++)
-       {
-               // Look for a default route
-
-               if ( pIpForwardTable->table[i].dwForwardDest == 0 )
-               {
-                       if ( index && ( pIpForwardTable->table[i].dwForwardMetric1 >= metric ) )
-                       {
-                               continue;
-                       }
-
-                       index   = pIpForwardTable->table[i].dwForwardIfIndex;
-                       metric  = pIpForwardTable->table[i].dwForwardMetric1;
-               }
-       }
-
-exit:
-
-       if ( pIpForwardTable != NULL )
-       {
-               free( pIpForwardTable );
-       }
-
-       return index;
-}
-
-//===========================================================================================================================
-//     AddressToIndexAndMask
-//===========================================================================================================================
-
-mDNSlocal mStatus
-AddressToIndexAndMask( struct sockaddr * addr, uint32_t * ifIndex, struct sockaddr * mask  )
-{
-       // Before calling AddIPAddress we use GetIpAddrTable to get
-       // an adapter to which we can add the IP.
-       
-       PMIB_IPADDRTABLE        pIPAddrTable    = NULL;
-       DWORD                           dwSize                  = 0;
-       mStatus                         err                             = mStatus_UnknownErr;
-       DWORD                           i;
-
-       // For now, this is only for IPv4 addresses.  That is why we can safely cast
-       // addr's to sockaddr_in.
-
-       require_action( addr->sa_family == AF_INET, exit, err = mStatus_UnknownErr );
-
-       // Make an initial call to GetIpAddrTable to get the
-       // necessary size into the dwSize variable
-
-       for ( i = 0; i < 100; i++ )
-       {
-               err = GetIpAddrTable( pIPAddrTable, &dwSize, 0 );
-
-               if ( err != ERROR_INSUFFICIENT_BUFFER )
-               {
-                       break;
-               }
-
-               pIPAddrTable = (MIB_IPADDRTABLE *) realloc( pIPAddrTable, dwSize );
-               require_action( pIPAddrTable, exit, err = WSAENOBUFS );
-       }
-
-       require_noerr( err, exit );
-       err = mStatus_UnknownErr;
-
-       for ( i = 0; i < pIPAddrTable->dwNumEntries; i++ )
-       {
-               if ( ( ( struct sockaddr_in* ) addr )->sin_addr.s_addr == pIPAddrTable->table[i].dwAddr )
-               {
-                       *ifIndex                                                                                        = pIPAddrTable->table[i].dwIndex;
-                       ( ( struct sockaddr_in*) mask )->sin_addr.s_addr        = pIPAddrTable->table[i].dwMask;
-                       err                                                                                                     = mStatus_NoError;
-                       break;
-               }
-       }
-
-exit:
-
-       if ( pIPAddrTable )
-       {
-               free( pIPAddrTable );
-       }
-
-       return err;
-}
-
-//===========================================================================================================================
-//     CanReceiveUnicast
-//===========================================================================================================================
-
-mDNSlocal mDNSBool     CanReceiveUnicast( void )
-{
-       mDNSBool                                ok;
-       SocketRef                               sock;
-       struct sockaddr_in              addr;
-       
-       // Try to bind to the port without the SO_REUSEADDR option to test if someone else has already bound to it.
-       
-       sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
-       check_translated_errno( IsValidSocket( sock ), errno_compat(), kUnknownErr );
-       ok = IsValidSocket( sock );
-       if( ok )
-       {
-               mDNSPlatformMemZero( &addr, sizeof( addr ) );
-               addr.sin_family                 = AF_INET;
-               addr.sin_port                   = MulticastDNSPort.NotAnInteger;
-               addr.sin_addr.s_addr    = htonl( INADDR_ANY );
-               
-               ok = ( bind( sock, (struct sockaddr *) &addr, sizeof( addr ) ) == 0 );
-               close_compat( sock );
-       }
-       
-       dlog( kDebugLevelInfo, DEBUG_NAME "Unicast UDP responses %s\n", ok ? "okay" : "*not allowed*" );
-       return( ok );
-}
-
-//===========================================================================================================================
-//     IsPointToPoint
-//===========================================================================================================================
-
-mDNSlocal mDNSBool IsPointToPoint( IP_ADAPTER_UNICAST_ADDRESS * addr )
-{
-       struct ifaddrs  *       addrs   =       NULL;
-       struct ifaddrs  *       p               =       NULL;
-       OSStatus                        err;
-       mDNSBool                        ret             =       mDNSfalse;
-
-       // For now, only works for IPv4 interfaces
-
-       if ( addr->Address.lpSockaddr->sa_family == AF_INET )
-       {
-               // The getifaddrs_ipv4 call will give us correct information regarding IFF_POINTTOPOINT flags.
-
-               err = getifaddrs_ipv4( &addrs );
-               require_noerr( err, exit );
-
-               for ( p = addrs; p; p = p->ifa_next )
-               {
-                       if ( ( addr->Address.lpSockaddr->sa_family == p->ifa_addr->sa_family ) &&
-                            ( ( ( struct sockaddr_in* ) addr->Address.lpSockaddr )->sin_addr.s_addr == ( ( struct sockaddr_in* ) p->ifa_addr )->sin_addr.s_addr ) )
-                       {
-                               ret = ( p->ifa_flags & IFF_POINTTOPOINT ) ? mDNStrue : mDNSfalse;
-                               break;
-                       }
-               }
-       }
-
-exit:
-
-       if ( addrs )
-       {
-               freeifaddrs( addrs );
-       }
-
-       return ret;
-}
-
-//===========================================================================================================================
-//     GetWindowsVersionString
-//===========================================================================================================================
-
-mDNSlocal OSStatus     GetWindowsVersionString( char *inBuffer, size_t inBufferSize )
-{
-#if( !defined( VER_PLATFORM_WIN32_CE ) )
-       #define VER_PLATFORM_WIN32_CE           3
-#endif
-
-       OSStatus                                err;
-       OSVERSIONINFO                   osInfo;
-       BOOL                                    ok;
-       const char *                    versionString;
-       DWORD                                   platformID;
-       DWORD                                   majorVersion;
-       DWORD                                   minorVersion;
-       DWORD                                   buildNumber;
-       
-       versionString = "unknown Windows version";
-       
-       osInfo.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );
-       ok = GetVersionEx( &osInfo );
-       err = translate_errno( ok, (OSStatus) GetLastError(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       platformID              = osInfo.dwPlatformId;
-       majorVersion    = osInfo.dwMajorVersion;
-       minorVersion    = osInfo.dwMinorVersion;
-       buildNumber             = osInfo.dwBuildNumber & 0xFFFF;
-       
-       if( ( platformID == VER_PLATFORM_WIN32_WINDOWS ) && ( majorVersion == 4 ) )
-       {
-               if( ( minorVersion < 10 ) && ( buildNumber == 950 ) )
-               {
-                       versionString   = "Windows 95";
-               }
-               else if( ( minorVersion < 10 ) && ( ( buildNumber > 950 ) && ( buildNumber <= 1080 ) ) )
-               {
-                       versionString   = "Windows 95 SP1";
-               }
-               else if( ( minorVersion < 10 ) && ( buildNumber > 1080 ) )
-               {
-                       versionString   = "Windows 95 OSR2";
-               }
-               else if( ( minorVersion == 10 ) && ( buildNumber == 1998 ) )
-               {
-                       versionString   = "Windows 98";
-               }
-               else if( ( minorVersion == 10 ) && ( ( buildNumber > 1998 ) && ( buildNumber < 2183 ) ) )
-               {
-                       versionString   = "Windows 98 SP1";
-               }
-               else if( ( minorVersion == 10 ) && ( buildNumber >= 2183 ) )
-               {
-                       versionString   = "Windows 98 SE";
-               }
-               else if( minorVersion == 90 )
-               {
-                       versionString   = "Windows ME";
-               }
-       }
-       else if( platformID == VER_PLATFORM_WIN32_NT )
-       {
-               if( ( majorVersion == 3 ) && ( minorVersion == 51 ) )
-               {
-                       versionString   = "Windows NT 3.51";
-               }
-               else if( ( majorVersion == 4 ) && ( minorVersion == 0 ) )
-               {
-                       versionString   = "Windows NT 4";
-               }
-               else if( ( majorVersion == 5 ) && ( minorVersion == 0 ) )
-               {
-                       versionString   = "Windows 2000";
-               }
-               else if( ( majorVersion == 5 ) && ( minorVersion == 1 ) )
-               {
-                       versionString   = "Windows XP";
-               }
-               else if( ( majorVersion == 5 ) && ( minorVersion == 2 ) )
-               {
-                       versionString   = "Windows Server 2003";
-               }
-       }
-       else if( platformID == VER_PLATFORM_WIN32_CE )
-       {
-               versionString           = "Windows CE";
-       }
-       
-exit:
-       if( inBuffer && ( inBufferSize > 0 ) )
-       {
-               inBufferSize -= 1;
-               strncpy( inBuffer, versionString, inBufferSize );
-               inBuffer[ inBufferSize ] = '\0';
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     RegQueryString
-//===========================================================================================================================
-
-mDNSlocal mStatus
-RegQueryString( HKEY key, LPCSTR valueName, LPSTR * string, DWORD * stringLen, DWORD * enabled )
-{
-       DWORD   type;
-       int             i;
-       mStatus err;
-
-       *stringLen      = MAX_ESCAPED_DOMAIN_NAME;
-       *string         = NULL;
-       i                       = 0;
-
-       do
-       {
-               if ( *string )
-               {
-                       free( *string );
-               }
-
-               *string = (char*) malloc( *stringLen );
-               require_action( *string, exit, err = mStatus_NoMemoryErr );
-
-               err = RegQueryValueExA( key, valueName, 0, &type, (LPBYTE) *string, stringLen );
-
-               i++;
-       }
-       while ( ( err == ERROR_MORE_DATA ) && ( i < 100 ) );
-
-       require_noerr_quiet( err, exit );
-
-       if ( enabled )
-       {
-               DWORD dwSize = sizeof( DWORD );
-
-               err = RegQueryValueEx( key, TEXT("Enabled"), NULL, NULL, (LPBYTE) enabled, &dwSize );
-               check_noerr( err );
-
-               err = kNoErr;
-       }
-
-exit:
-
-       return err;
-}
-
-//===========================================================================================================================
-//     StringToAddress
-//===========================================================================================================================
-
-mDNSlocal mStatus StringToAddress( mDNSAddr * ip, LPSTR string )
-{
-       struct sockaddr_in6 sa6;
-       struct sockaddr_in      sa4;
-       INT                                     dwSize;
-       mStatus                         err;
-
-       sa6.sin6_family = AF_INET6;
-       dwSize                  = sizeof( sa6 );
-
-       err = WSAStringToAddressA( string, AF_INET6, NULL, (struct sockaddr*) &sa6, &dwSize );
-
-       if ( err == mStatus_NoError )
-       {
-               err = SetupAddr( ip, (struct sockaddr*) &sa6 );
-               require_noerr( err, exit );
-       }
-       else
-       {
-               sa4.sin_family = AF_INET;
-               dwSize = sizeof( sa4 );
-
-               err = WSAStringToAddressA( string, AF_INET, NULL, (struct sockaddr*) &sa4, &dwSize );
-               err = translate_errno( err == 0, WSAGetLastError(), kUnknownErr );
-               require_noerr( err, exit );
-                       
-               err = SetupAddr( ip, (struct sockaddr*) &sa4 );
-               require_noerr( err, exit );
-       }
-
-exit:
-
-       return err;
-}
-
-//===========================================================================================================================
-//     myGetIfAddrs
-//===========================================================================================================================
-
-mDNSlocal struct ifaddrs*
-myGetIfAddrs(int refresh)
-{
-       static struct ifaddrs *ifa = NULL;
-       
-       if (refresh && ifa)
-       {
-               freeifaddrs(ifa);
-               ifa = NULL;
-       }
-       
-       if (ifa == NULL)
-       {
-               getifaddrs(&ifa);
-       }
-       
-       return ifa;
-}
-
-//===========================================================================================================================
-//     TCHARtoUTF8
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-TCHARtoUTF8( const TCHAR *inString, char *inBuffer, size_t inBufferSize )
-{
-#if( defined( UNICODE ) || defined( _UNICODE ) )
-       OSStatus                err;
-       int                             len;
-       
-       len = WideCharToMultiByte( CP_UTF8, 0, inString, -1, inBuffer, (int) inBufferSize, NULL, NULL );
-       err = translate_errno( len > 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-       
-exit:
-       return( err );
-#else
-       return( WindowsLatin1toUTF8( inString, inBuffer, inBufferSize ) );
-#endif
-}
-
-//===========================================================================================================================
-//     WindowsLatin1toUTF8
-//===========================================================================================================================
-
-mDNSlocal OSStatus
-WindowsLatin1toUTF8( const char *inString, char *inBuffer, size_t inBufferSize )
-{
-       OSStatus                err;
-       WCHAR *                 utf16;
-       int                             len;
-       
-       utf16 = NULL;
-       
-       // Windows doesn't support going directly from Latin-1 to UTF-8 so we have to go from Latin-1 to UTF-16 first.
-       
-       len = MultiByteToWideChar( CP_ACP, 0, inString, -1, NULL, 0 );
-       err = translate_errno( len > 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       utf16 = (WCHAR *) malloc( len * sizeof( *utf16 ) );
-       require_action( utf16, exit, err = kNoMemoryErr );
-       
-       len = MultiByteToWideChar( CP_ACP, 0, inString, -1, utf16, len );
-       err = translate_errno( len > 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-       
-       // Now convert the temporary UTF-16 to UTF-8.
-       
-       len = WideCharToMultiByte( CP_UTF8, 0, utf16, -1, inBuffer, (int) inBufferSize, NULL, NULL );
-       err = translate_errno( len > 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-
-exit:
-       if( utf16 ) free( utf16 );
-       return( err );
-}
-
-//===========================================================================================================================
-//     TCPCloseSocket
-//===========================================================================================================================
-
-mDNSlocal void
-TCPCloseSocket( TCPSocket * sock )
-{
-       dlog( kDebugLevelChatty, DEBUG_NAME "closing TCPSocket 0x%x:%d\n", sock, sock->fd );
-
-       if ( sock->fd != INVALID_SOCKET )
-       {
-               closesocket( sock->fd );
-               sock->fd = INVALID_SOCKET;
-       }
-}
-
-//===========================================================================================================================
-//  UDPCloseSocket
-//===========================================================================================================================
-
-mDNSlocal void
-UDPCloseSocket( UDPSocket * sock )
-{
-       dlog( kDebugLevelChatty, DEBUG_NAME "closing UDPSocket %d\n", sock->fd );
-
-       if ( sock->fd != INVALID_SOCKET )
-       {
-               mDNSPollUnregisterSocket( sock->fd );
-               closesocket( sock->fd );
-               sock->fd = INVALID_SOCKET;
-       }
-}
-
-//===========================================================================================================================
-//     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);
-       }
-
-mDNSlocal void GetDDNSFQDN( domainname *const fqdn )
-{
-       LPSTR           name = NULL;
-       DWORD           dwSize;
-       DWORD           enabled;
-       HKEY            key = NULL;
-       OSStatus        err;
-
-       check( fqdn );
-
-       // Initialize
-
-       fqdn->c[0] = '\0';
-
-       // Get info from Bonjour registry key
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode TEXT("\\DynDNS\\Setup\\") kServiceDynDNSHostNames, &key );
-       require_noerr( err, exit );
-
-       err = RegQueryString( key, "", &name, &dwSize, &enabled );
-       if ( !err && ( name[0] != '\0' ) && enabled )
-       {
-               if ( !MakeDomainNameFromDNSNameString( fqdn, name ) || !fqdn->c[0] )
-               {
-                       dlog( kDebugLevelError, "bad DDNS host name in registry: %s", name[0] ? name : "(unknown)");
-               }
-       }
-
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-               key = NULL;
-       }
-
-       if ( name )
-       {
-               free( name );
-               name = NULL;
-       }
-}
-
-#ifdef UNICODE
-mDNSlocal void GetDDNSDomains( DNameListElem ** domains, LPCWSTR lpSubKey )
-#else
-mDNSlocal void GetDDNSConfig( DNameListElem ** domains, LPCSTR lpSubKey )
-#endif
-{
-       char            subKeyName[kRegistryMaxKeyLength + 1];
-       DWORD           cSubKeys = 0;
-       DWORD           cbMaxSubKey;
-       DWORD           cchMaxClass;
-       DWORD           dwSize;
-       HKEY            key = NULL;
-       HKEY            subKey = NULL;
-       domainname      dname;
-       DWORD           i;
-       OSStatus        err;
-
-       check( domains );
-
-       // Initialize
-
-       *domains = NULL;
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, lpSubKey, &key );
-       require_noerr( err, exit );
-
-       // Get information about this node
-
-       err = RegQueryInfoKey( key, NULL, NULL, NULL, &cSubKeys, &cbMaxSubKey, &cchMaxClass, NULL, NULL, NULL, NULL, NULL );       
-       require_noerr( err, exit );
-
-       for ( i = 0; i < cSubKeys; i++)
-       {
-               DWORD enabled;
-
-               dwSize = kRegistryMaxKeyLength;
-        
-               err = RegEnumKeyExA( key, i, subKeyName, &dwSize, NULL, NULL, NULL, NULL );
-
-               if ( !err )
-               {
-                       err = RegOpenKeyExA( key, subKeyName, 0, KEY_READ, &subKey );
-                       require_noerr( err, exit );
-
-                       dwSize = sizeof( DWORD );
-                       err = RegQueryValueExA( subKey, "Enabled", NULL, NULL, (LPBYTE) &enabled, &dwSize );
-
-                       if ( !err && ( subKeyName[0] != '\0' ) && enabled )
-                       {
-                               if ( !MakeDomainNameFromDNSNameString( &dname, subKeyName ) || !dname.c[0] )
-                               {
-                                       dlog( kDebugLevelError, "bad DDNS domain in registry: %s", subKeyName[0] ? subKeyName : "(unknown)");
-                               }
-                               else
-                               {
-                                       DNameListElem * domain = (DNameListElem*) malloc( sizeof( DNameListElem ) );
-                                       require_action( domain, exit, err = mStatus_NoMemoryErr );
-                                       
-                                       AssignDomainName(&domain->name, &dname);
-                                       domain->next = *domains;
-
-                                       *domains = domain;
-                               }
-                       }
-
-                       RegCloseKey( subKey );
-                       subKey = NULL;
-               }
-       }
-
-exit:
-
-       if ( subKey )
-       {
-               RegCloseKey( subKey );
-       }
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-}
-
-mDNSlocal void SetDomainSecret( mDNS * const m, const domainname * inDomain )
-{
-       char                                    domainUTF8[ 256 ];
-       DomainAuthInfo                  *foundInList;
-       DomainAuthInfo                  *ptr;
-       char                                    outDomain[ 256 ];
-       char                                    outKey[ 256 ];
-       char                                    outSecret[ 256 ];
-       OSStatus                                err;
-       
-       ConvertDomainNameToCString( inDomain, domainUTF8 );
-       
-       // If we're able to find a secret for this domain
-
-       if ( LsaGetSecret( domainUTF8, outDomain, sizeof( outDomain ), outKey, sizeof( outKey ), outSecret, sizeof( outSecret ) ) )
-       {
-               domainname domain;
-               domainname key;
-
-               // Tell the core about this secret
-
-               MakeDomainNameFromDNSNameString( &domain, outDomain );
-               MakeDomainNameFromDNSNameString( &key, outKey );
-
-               for (foundInList = m->AuthInfoList; foundInList; foundInList = foundInList->next)
-                       if (SameDomainName(&foundInList->domain, &domain ) ) break;
-
-               ptr = foundInList;
-       
-               if (!ptr)
-               {
-                       ptr = (DomainAuthInfo*)malloc(sizeof(DomainAuthInfo));
-                       require_action( ptr, exit, err = mStatus_NoMemoryErr );
-               }
-
-               err = mDNS_SetSecretForDomain(m, ptr, &domain, &key, outSecret, NULL, NULL, FALSE );
-               require_action( err != mStatus_BadParamErr, exit, if (!foundInList ) mDNSPlatformMemFree( ptr ) );
-
-               debugf("Setting shared secret for zone %s with key %##s", outDomain, key.c);
-       }
-
-exit:
-
-       return;
-}
-
-mDNSlocal VOID CALLBACK
-CheckFileSharesProc( LPVOID arg, DWORD dwTimerLowValue, DWORD dwTimerHighValue )
-{
-       mDNS * const m = ( mDNS * const ) arg;
-
-       ( void ) dwTimerLowValue;
-       ( void ) dwTimerHighValue;
-
-       CheckFileShares( m );
-}
-
-mDNSlocal unsigned __stdcall 
-SMBRegistrationThread( void * arg )
-{
-       mDNS * const m = ( mDNS * const ) arg;
-       DNSServiceRef sref = NULL;
-       HANDLE          handles[ 3 ];
-       mDNSu8          txtBuf[ 256 ];
-       mDNSu8  *       txtPtr;
-       size_t          keyLen;
-       size_t          valLen;
-       mDNSIPPort      port = { { SMBPortAsNumber >> 8, SMBPortAsNumber & 0xFF } };
-       DNSServiceErrorType err;
-
-       DEBUG_UNUSED( arg );
-
-       handles[ 0 ] = gSMBThreadStopEvent;
-       handles[ 1 ] = gSMBThreadRegisterEvent;
-       handles[ 2 ] = gSMBThreadDeregisterEvent;
-
-       memset( txtBuf, 0, sizeof( txtBuf )  );
-       txtPtr = txtBuf;
-       keyLen = strlen( "netbios=" );
-       valLen = strlen( m->p->nbname );
-       require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
-       *txtPtr++ = ( mDNSu8 ) ( keyLen + valLen );
-       memcpy( txtPtr, "netbios=", keyLen );
-       txtPtr += keyLen;
-       if ( valLen ) { memcpy( txtPtr, m->p->nbname, valLen ); txtPtr += ( mDNSu8 ) valLen; }
-       keyLen = strlen( "domain=" );
-       valLen = strlen( m->p->nbdomain );
-       require_action( valLen < 32, exit, err = kUnknownErr ); // This should never happen, but check to avoid further memory corruption
-       *txtPtr++ = ( mDNSu8 )( keyLen + valLen );
-       memcpy( txtPtr, "domain=", keyLen );
-       txtPtr += keyLen;
-       if ( valLen ) { memcpy( txtPtr, m->p->nbdomain, valLen ); txtPtr += valLen; }
-       
-       for ( ;; )
-       {
-               DWORD ret;
-
-               ret = WaitForMultipleObjects( 3, handles, FALSE, INFINITE );
-
-               if ( ret != WAIT_FAILED )
-               {
-                       if ( ret == kSMBStopEvent )
-                       {
-                               break;
-                       }
-                       else if ( ret == kSMBRegisterEvent )
-                       {
-                               err = gDNSServiceRegister( &sref, 0, 0, NULL, "_smb._tcp,_file", NULL, NULL, ( uint16_t ) port.NotAnInteger, ( mDNSu16 )( txtPtr - txtBuf ), txtBuf, NULL, NULL );
-
-                               if ( err )
-                               {
-                                       LogMsg( "SMBRegistrationThread: DNSServiceRegister returned %d\n", err );
-                                       sref = NULL;
-                                       break;
-                               }
-                       }
-                       else if ( ret == kSMBDeregisterEvent )
-                       {
-                               if ( sref )
-                               {
-                                       gDNSServiceRefDeallocate( sref );
-                                       sref = NULL;
-                               }
-                       }
-               }
-               else
-               {
-                       LogMsg( "SMBRegistrationThread:  WaitForMultipleObjects returned %d\n", GetLastError() );
-                       break;
-               }
-       }
-
-exit:
-
-       if ( sref != NULL )
-       {
-               gDNSServiceRefDeallocate( sref );
-               sref = NULL;
-       }
-
-       SetEvent( gSMBThreadQuitEvent );
-       _endthreadex( 0 );
-       return 0;
-}
-
-mDNSlocal void
-CheckFileShares( mDNS * const m )
-{
-       PSHARE_INFO_1   bufPtr = ( PSHARE_INFO_1 ) NULL;
-       DWORD                   entriesRead = 0;
-       DWORD                   totalEntries = 0;
-       DWORD                   resume = 0;
-       mDNSBool                advertise = mDNSfalse;
-       mDNSBool                fileSharing = mDNSfalse;
-       mDNSBool                printSharing = mDNSfalse;
-       HKEY                    key = NULL;
-       BOOL                    retry = FALSE;
-       NET_API_STATUS  res;
-       mStatus                 err;
-
-       check( m );
-
-       // Only do this if we're not shutting down
-
-       require_action_quiet( m->AdvertiseLocalAddresses && !m->ShutdownTime, exit, err = kNoErr );
-
-       err = RegCreateKey( HKEY_LOCAL_MACHINE, kServiceParametersNode L"\\Services\\SMB", &key );
-
-       if ( !err )
-       {
-               DWORD dwSize = sizeof( DWORD );
-               RegQueryValueEx( key, L"Advertise", NULL, NULL, (LPBYTE) &advertise, &dwSize );
-       }
-
-       if ( advertise && mDNSIsFileAndPrintSharingEnabled( &retry ) )
-       {
-               dlog( kDebugLevelTrace, DEBUG_NAME "Sharing is enabled\n" );
-
-               res = NetShareEnum( NULL, 1, ( LPBYTE* )&bufPtr, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resume );
-
-               if ( ( res == ERROR_SUCCESS ) || ( res == ERROR_MORE_DATA ) )
-               {
-                       PSHARE_INFO_1 p = bufPtr;
-                       DWORD i;
-
-                       for( i = 0; i < entriesRead; i++ ) 
-                       {
-                               // We are only interested if the user is sharing anything other 
-                               // than the built-in "print$" source
-
-                               if ( ( p->shi1_type == STYPE_DISKTREE ) && ( wcscmp( p->shi1_netname, TEXT( "print$" ) ) != 0 ) )
-                               {
-                                       fileSharing = mDNStrue;
-                               }
-                               else if ( p->shi1_type == STYPE_PRINTQ )
-                               {
-                                       printSharing = mDNStrue;
-                               }
-
-                               p++;
-                       }
-
-                       NetApiBufferFree( bufPtr );
-                       bufPtr = NULL;
-                       retry = FALSE;
-               }
-               else if ( res == NERR_ServerNotStarted )
-               {
-                       retry = TRUE;
-               }
-       }
-       
-       if ( retry )
-       {
-               __int64                 qwTimeout;
-               LARGE_INTEGER   liTimeout;
-
-               qwTimeout = -m->p->checkFileSharesTimeout * 10000000;
-               liTimeout.LowPart  = ( DWORD )( qwTimeout & 0xFFFFFFFF );
-               liTimeout.HighPart = ( LONG )( qwTimeout >> 32 );
-
-               SetWaitableTimer( m->p->checkFileSharesTimer, &liTimeout, 0, CheckFileSharesProc, m, FALSE );
-       }
-
-       if ( !m->p->smbFileSharing && fileSharing )
-       {
-               if ( !gSMBThread )
-               {
-                       if ( !gDNSSDLibrary )
-                       {
-                               gDNSSDLibrary = LoadLibrary( TEXT( "dnssd.dll" ) );
-                               require_action( gDNSSDLibrary, exit, err = GetLastError() );
-                       }
-
-                       if ( !gDNSServiceRegister )
-                       {
-                               gDNSServiceRegister = ( DNSServiceRegisterFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRegister" );
-                               require_action( gDNSServiceRegister, exit, err = GetLastError() );
-                       }
-
-                       if ( !gDNSServiceRefDeallocate )
-                       {
-                               gDNSServiceRefDeallocate = ( DNSServiceRefDeallocateFunc ) GetProcAddress( gDNSSDLibrary, "DNSServiceRefDeallocate" );
-                               require_action( gDNSServiceRefDeallocate, exit, err = GetLastError() );
-                       }
-
-                       if ( !gSMBThreadRegisterEvent )
-                       {
-                               gSMBThreadRegisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-                               require_action( gSMBThreadRegisterEvent != NULL, exit, err = GetLastError() );
-                       }
-
-                       if ( !gSMBThreadDeregisterEvent )
-                       {
-                               gSMBThreadDeregisterEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-                               require_action( gSMBThreadDeregisterEvent != NULL, exit, err = GetLastError() );
-                       }
-
-                       if ( !gSMBThreadStopEvent )
-                       {
-                               gSMBThreadStopEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-                               require_action( gSMBThreadStopEvent != NULL, exit, err = GetLastError() );
-                       }
-
-                       if ( !gSMBThreadQuitEvent )
-                       {
-                               gSMBThreadQuitEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
-                               require_action( gSMBThreadQuitEvent != NULL, exit, err = GetLastError() );
-                       }
-
-                       gSMBThread = ( HANDLE ) _beginthreadex( NULL, 0, SMBRegistrationThread, m, 0, NULL );
-                       require_action( gSMBThread != NULL, exit, err = GetLastError() );
-               }
-
-               SetEvent( gSMBThreadRegisterEvent );
-
-               m->p->smbFileSharing = mDNStrue;
-       }
-       else if ( m->p->smbFileSharing && !fileSharing )
-       {
-               dlog( kDebugLevelTrace, DEBUG_NAME "deregistering smb type\n" );
-
-               if ( gSMBThreadDeregisterEvent != NULL )
-               {
-                       SetEvent( gSMBThreadDeregisterEvent );
-               }
-
-               m->p->smbFileSharing = mDNSfalse;
-       }
-
-exit:
-
-       if ( key )
-       {
-               RegCloseKey( key );
-       }
-}
-
-BOOL
-IsWOMPEnabled( mDNS * const m )
-{
-       BOOL enabled;
-
-       mDNSInterfaceData * ifd;
-
-       enabled = FALSE;
-
-       for( ifd = m->p->interfaceList; ifd; ifd = ifd->next )
-       {
-               if ( IsWOMPEnabledForAdapter( ifd->name ) )
-               {
-                       enabled = TRUE;
-                       break;
-               }
-       }
-
-       return enabled;
-}
-
-mDNSlocal mDNSu8
-IsWOMPEnabledForAdapter( const char * adapterName )
-{
-       char                                            fileName[80];
-       NDIS_OID                                        oid;
-    DWORD                                              count;
-    HANDLE                                             handle  = INVALID_HANDLE_VALUE;
-       NDIS_PNP_CAPABILITIES   *       pNPC    = NULL;
-       int                                                     err;
-       mDNSu8                                          ok              = TRUE;
-
-       require_action( adapterName != NULL, exit, ok = FALSE );
-
-       dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter: %s\n", adapterName );
-       
-    // Construct a device name to pass to CreateFile
-
-       strncpy_s( fileName, sizeof( fileName ), DEVICE_PREFIX, strlen( DEVICE_PREFIX ) );
-       strcat_s( fileName, sizeof( fileName ), adapterName );
-    handle = CreateFileA( fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, INVALID_HANDLE_VALUE );
-       require_action ( handle != INVALID_HANDLE_VALUE, exit, ok = FALSE );
-
-       // We successfully opened the driver, format the IOCTL to pass the driver.
-               
-       oid = OID_PNP_CAPABILITIES;
-       pNPC = ( NDIS_PNP_CAPABILITIES * ) malloc( sizeof( NDIS_PNP_CAPABILITIES ) );
-       require_action( pNPC != NULL, exit, ok = FALSE );
-       ok = ( mDNSu8 ) DeviceIoControl( handle, IOCTL_NDIS_QUERY_GLOBAL_STATS, &oid, sizeof( oid ), pNPC, sizeof( NDIS_PNP_CAPABILITIES ), &count, NULL );
-       err = translate_errno( ok, GetLastError(), kUnknownErr );
-       require_action( !err, exit, ok = FALSE );
-       ok = ( mDNSu8 ) ( ( count == sizeof( NDIS_PNP_CAPABILITIES ) ) && ( pNPC->Flags & NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE ) );
-       
-exit:
-
-       if ( pNPC != NULL )
-       {
-               free( pNPC );
-       }
-
-    if ( handle != INVALID_HANDLE_VALUE )
-    {
-               CloseHandle( handle );
-    }
-
-       dlog( kDebugLevelTrace, DEBUG_NAME "IsWOMPEnabledForAdapter returns %s\n", ok ? "true" : "false" );
-
-       return ( mDNSu8 ) ok;
-}
-
-mDNSlocal void
-SendWakeupPacket( mDNS * const inMDNS, LPSOCKADDR addr, INT addrlen, const char * buf, INT buflen, INT numTries, INT msecSleep )
-{
-       mDNSBool        repeat = ( numTries == 1 ) ? mDNStrue : mDNSfalse;
-       SOCKET          sock;
-       int                     num;
-       mStatus         err;
-
-       ( void ) inMDNS;
-
-       sock = socket( addr->sa_family, SOCK_DGRAM, IPPROTO_UDP );
-       require_action( sock != INVALID_SOCKET, exit, err = mStatus_UnknownErr );
-
-       while ( numTries-- )
-       {
-               num = sendto( sock, ( const char* ) buf, buflen, 0, addr, addrlen );
-
-               if ( num != buflen )
-               {
-                       LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
-               }
-
-               if ( repeat )
-               {
-                       num = sendto( sock, buf, buflen, 0, addr, addrlen );
-
-                       if ( num != buflen )
-                       {
-                               LogMsg( "SendWakeupPacket error: sent %d bytes: %d\n", num, WSAGetLastError() );
-                       }
-               }
-
-               if ( msecSleep )
-               {
-                       Sleep( msecSleep );
-               }
-       }
-
-exit:
-
-       if ( sock != INVALID_SOCKET )
-       {
-               closesocket( sock );
-       }
-} 
-
-mDNSlocal void _cdecl
-SendMulticastWakeupPacket( void *arg )
-{
-       MulticastWakeupStruct *info = ( MulticastWakeupStruct* ) arg;
-       
-       if ( info )
-       {
-               SendWakeupPacket( info->inMDNS, ( LPSOCKADDR ) &info->addr, sizeof( info->addr ), ( const char* ) info->data, sizeof( info->data ), info->numTries, info->msecSleep );
-               free( info );
-       }
-
-       _endthread();
-}
-
-mDNSexport void FreeEtcHosts(mDNS *const m, AuthRecord *const rr, mStatus result)
-{
-       DEBUG_UNUSED( m );
-       DEBUG_UNUSED( rr );
-       DEBUG_UNUSED( result );
-}
diff --git a/mDNSWindows/mDNSWin32.h b/mDNSWindows/mDNSWin32.h
deleted file mode 100755 (executable)
index 6b5b435..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2002-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef        __MDNS_WIN32__
-#define        __MDNS_WIN32__
-
-#include       "CommonServices.h"
-
-#if( !defined( _WIN32_WCE ) )
-       #include        <mswsock.h>
-#endif
-
-#include       "mDNSEmbeddedAPI.h"
-#include       "uDNS.h"
-
-#ifdef __cplusplus
-       extern "C" {
-#endif
-
-
-typedef void ( *TCPUserCallback )();
-
-struct TCPSocket_struct
-{
-       TCPSocketFlags                          flags;          // MUST BE FIRST FIELD -- mDNSCore expects every TCPSocket_struct to begin with TCPSocketFlags flags
-       SOCKET                                          fd;
-       BOOL                                            connected;
-       TCPUserCallback                         userCallback;
-       void                                    *       userContext;
-       BOOL                                            closed;
-       mDNS                                    *       m;
-};
-
-
-struct UDPSocket_struct
-{
-       mDNSIPPort                                      port;           // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
-       mDNSAddr                                        addr;           // This is initialized by our code. If we don't get the 
-                                                                                       // dstAddr from WSARecvMsg we use this value instead.
-       SOCKET                                          fd;
-       LPFN_WSARECVMSG                         recvMsgPtr;
-       DNSMessage                                      packet;
-       struct mDNSInterfaceData        *ifd;
-       UDPSocket                                       *next;
-       mDNS                                            *m;
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         mDNSInterfaceData
-
-       @abstract       Structure containing interface-specific data.
-*/
-
-typedef struct mDNSInterfaceData       mDNSInterfaceData;
-struct mDNSInterfaceData
-{
-       char                                            name[ 128 ];
-       uint32_t                                        index;
-       uint32_t                                        scopeID;
-       struct UDPSocket_struct         sock;
-       NetworkInterfaceInfo            interfaceInfo;
-       mDNSBool                                        hostRegistered;
-       mDNSInterfaceData               *       next;
-};
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @typedef        ReportStatusFunc
-*/
-typedef void           (*ReportStatusFunc)(int inType, const char *inFormat, ...);
-
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         mDNS_PlatformSupport_struct
-
-       @abstract       Structure containing platform-specific data.
-*/
-
-struct mDNS_PlatformSupport_struct
-{
-       HANDLE                                          mainThread;
-       HANDLE                                          checkFileSharesTimer;
-       mDNSs32                                         checkFileSharesTimeout;
-       ReportStatusFunc                        reportStatusFunc;
-       time_t                                          nextDHCPLeaseExpires;
-       char                                            nbname[ 32 ];
-       char                                            nbdomain[ 32 ];
-       mDNSBool                                        smbFileSharing;
-       mDNSBool                                        smbPrintSharing;
-       ServiceRecordSet                        smbSRS;
-       AuthRecord                                      smbSubTypes[ 2 ];
-       mDNSBool                                        registeredLoopback4;
-       int                                                     interfaceCount;
-       mDNSInterfaceData *                     interfaceList;
-       mDNSInterfaceData *                     inactiveInterfaceList;
-       struct UDPSocket_struct         unicastSock4;
-       struct UDPSocket_struct         unicastSock6;
-       DWORD                                           osMajorVersion;
-       DWORD                                           osMinorVersion;
-};
-
-//---------------------------------------------------------------------------------------------------------------------------
-/*!    @struct         ifaddrs
-
-       @abstract       Interface information
-*/
-
-struct ifaddrs
-{
-       struct ifaddrs *        ifa_next;
-       char *                          ifa_name;
-       u_int                           ifa_flags;
-       struct sockaddr *       ifa_addr;
-       struct sockaddr *       ifa_netmask;
-       struct sockaddr *       ifa_broadaddr;
-       struct sockaddr *       ifa_dstaddr;
-       BYTE                            ifa_physaddr[6];
-       BOOL                            ifa_dhcpEnabled;
-       time_t                          ifa_dhcpLeaseExpires;
-       mDNSu8                          ifa_womp;
-       void *                          ifa_data;
-       
-       struct
-       {
-               uint32_t                index;
-       
-       }       ifa_extra;
-};
-
-
-extern void            InterfaceListDidChange( mDNS * const inMDNS );
-extern void            ComputerDescriptionDidChange( mDNS * const inMDNS );
-extern void            TCPIPConfigDidChange( mDNS * const inMDNS );
-extern void            DynDNSConfigDidChange( mDNS * const inMDNS );
-extern void            FileSharingDidChange( mDNS * const inMDNS );
-extern void            FirewallDidChange( mDNS * const inMDNS );
-extern mStatus  TCPAddSocket( mDNS * const inMDNS, TCPSocket *sock );
-extern mStatus SetupInterfaceList( mDNS * const inMDNS );
-extern mStatus TearDownInterfaceList( mDNS * const inMDNS );
-extern BOOL            IsWOMPEnabled();
-extern void     DispatchSocketEvents( mDNS * const inMDNS );
-
-
-#ifdef __cplusplus
-       }
-#endif
-
-#endif // __MDNS_WIN32__
diff --git a/mDNSWindows/mdnsNSP/ReadMe.txt b/mDNSWindows/mdnsNSP/ReadMe.txt
deleted file mode 100644 (file)
index 7a6e2cc..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-The mdnsNSP is a NameSpace Provider. It hooks into the Windows name resolution infrastructure to allow any software using the standard Windows APIs for resolving names to work with DNS-SD. For example, when the mdnsNSP is installed, you can type "http://computer.local./" in Internet Explorer and it will resolve "computer.local." using DNS-SD and go to the web site (assuming you have a computer named "computer" on the local network and advertised via DNS-SD).
-
-NSP's are implemented DLLs and must be installed to work. NSP DLLs export an NSPStartup function, which is called when the NSP is used, and NSPStartup provides information about itself (e.g. version number, compatibility information, and a list of function pointers for each of the supported NSP routines).
-
-If you need to register the mdnsNSP, you can use the NSPTool (sources for it are provided along with the mdnsNSP) with the following line from the DOS command line prompt ("<path>" is the actual parent path of the DLL):
-
-NSPTool -install "mdnsNSP" "B600E6E9-553B-4a19-8696-335E5C896153" "<path>"
-
-You can remove remove the mdnsNSP with the following line:
-
-NSPTool -remove "B600E6E9-553B-4a19-8696-335E5C896153"
-
-For more information, check out the following URL:
-
-<http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/name_space_service_providers_2.asp>
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.aps b/mDNSWindows/mdnsNSP/mdnsNSP.aps
deleted file mode 100644 (file)
index 2e3b63a..0000000
Binary files a/mDNSWindows/mdnsNSP/mdnsNSP.aps and /dev/null differ
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.c b/mDNSWindows/mdnsNSP/mdnsNSP.c
deleted file mode 100644 (file)
index 21baa86..0000000
+++ /dev/null
@@ -1,2433 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * 
- *     http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include       <stdio.h>
-#include       <stdlib.h>
-#include       <string.h>
-
-#include       "ClientCommon.h"
-#include       "CommonServices.h"
-#include       "DebugServices.h"
-
-#include       <iphlpapi.h>
-#include       <guiddef.h>
-#include       <ws2spi.h>
-#include       <shlwapi.h>
-
-
-
-#include       "dns_sd.h"
-
-#pragma comment(lib, "DelayImp.lib")
-
-#ifdef _MSC_VER
-#define swprintf _snwprintf
-#define snprintf _snprintf
-#endif
-
-#define MAX_LABELS 128
-
-#if 0
-#pragma mark == Structures ==
-#endif
-
-//===========================================================================================================================
-//     Structures
-//===========================================================================================================================
-
-typedef struct Query *         QueryRef;
-typedef struct Query           Query;
-struct Query
-{
-       QueryRef                        next;
-       int                                     refCount;
-       DWORD                           querySetFlags;
-       WSAQUERYSETW *          querySet;
-       size_t                          querySetSize;
-       HANDLE                          data4Event;
-       HANDLE                          data6Event;
-       HANDLE                          cancelEvent;
-       HANDLE                          waitHandles[ 3 ];
-       DWORD                           waitCount;
-       DNSServiceRef           resolver4;
-       DNSServiceRef           resolver6;
-       char                            name[ kDNSServiceMaxDomainName ];
-       size_t                          nameSize;
-       uint8_t                         numValidAddrs;
-       uint32_t                        addr4;
-       bool                            addr4Valid;
-       uint8_t                         addr6[16];
-       u_long                          addr6ScopeId;
-       bool                            addr6Valid;
-};
-
-#define BUFFER_INITIAL_SIZE            4192
-#define ALIASES_INITIAL_SIZE   5
-
-typedef struct HostsFile
-{
-       int                     m_bufferSize;
-       char    *       m_buffer;
-       FILE    *       m_fp;
-} HostsFile;
-
-
-typedef struct HostsFileInfo
-{
-       struct hostent          m_host;
-       struct HostsFileInfo    *       m_next;
-} HostsFileInfo;
-
-
-#if 0
-#pragma mark == Prototypes ==
-#endif
-
-//===========================================================================================================================
-//     Prototypes
-//===========================================================================================================================
-
-// DLL Exports
-
-BOOL WINAPI            DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved );
-STDAPI                 DllRegisterServer( void );
-STDAPI                 DllRegisterServer( void );
-
-       
-// NSP SPIs
-
-int    WSPAPI  NSPCleanup( LPGUID inProviderID );
-
-DEBUG_LOCAL int WSPAPI
-       NSPLookupServiceBegin(
-               LPGUID                                  inProviderID,
-               LPWSAQUERYSETW                  inQuerySet,
-               LPWSASERVICECLASSINFOW  inServiceClassInfo,
-               DWORD                                   inFlags,   
-               LPHANDLE                                outLookup );
-
-DEBUG_LOCAL int WSPAPI
-       NSPLookupServiceNext(  
-               HANDLE                  inLookup,
-               DWORD                   inFlags,
-               LPDWORD                 ioBufferLength,
-               LPWSAQUERYSETW  outResults );
-
-DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup );
-
-DEBUG_LOCAL int WSPAPI
-       NSPSetService(
-               LPGUID                                  inProviderID,                                           
-               LPWSASERVICECLASSINFOW  inServiceClassInfo,   
-               LPWSAQUERYSETW                  inRegInfo,                                
-               WSAESETSERVICEOP                inOperation,                       
-               DWORD                                   inFlags );
-
-DEBUG_LOCAL int WSPAPI NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo );
-DEBUG_LOCAL int WSPAPI NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID );
-DEBUG_LOCAL int WSPAPI NSPGetServiceClassInfo( LPGUID inProviderID, LPDWORD ioBufSize, LPWSASERVICECLASSINFOW ioServiceClassInfo );
-
-// Private
-
-#define        NSPLock()               EnterCriticalSection( &gLock );
-#define        NSPUnlock()             LeaveCriticalSection( &gLock );
-
-DEBUG_LOCAL OSStatus   QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef );
-DEBUG_LOCAL OSStatus   QueryRetain( QueryRef inRef );
-DEBUG_LOCAL OSStatus   QueryRelease( QueryRef inRef );
-
-DEBUG_LOCAL void CALLBACK_COMPAT
-       QueryRecordCallback4(
-               DNSServiceRef           inRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inErrorCode,
-               const char *            inName,    
-               uint16_t                        inRRType,
-               uint16_t                        inRRClass,
-               uint16_t                        inRDataSize,
-               const void *            inRData,
-               uint32_t                        inTTL,
-               void *                          inContext );
-
-DEBUG_LOCAL void CALLBACK_COMPAT
-       QueryRecordCallback6(
-               DNSServiceRef           inRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inErrorCode,
-               const char *            inName,    
-               uint16_t                        inRRType,
-               uint16_t                        inRRClass,
-               uint16_t                        inRDataSize,
-               const void *            inRData,
-               uint32_t                        inTTL,
-               void *                          inContext );
-
-DEBUG_LOCAL OSStatus
-       QueryCopyQuerySet( 
-               QueryRef                                inRef, 
-               const WSAQUERYSETW *    inQuerySet, 
-               DWORD                                   inQuerySetFlags, 
-               WSAQUERYSETW **                 outQuerySet, 
-               size_t *                                outSize );
-
-DEBUG_LOCAL void
-       QueryCopyQuerySetTo( 
-               QueryRef                                inRef, 
-               const WSAQUERYSETW *    inQuerySet, 
-               DWORD                                   inQuerySetFlags, 
-               WSAQUERYSETW *                  outQuerySet );
-
-DEBUG_LOCAL size_t     QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags );
-
-#if( DEBUG )
-       void    DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet );
-       
-       #define dlog_query_set( LEVEL, SET )            DebugDumpQuerySet( LEVEL, SET )
-#else
-       #define dlog_query_set( LEVEL, SET )
-#endif
-
-DEBUG_LOCAL BOOL               InHostsTable( const char * name );
-DEBUG_LOCAL BOOL               IsLocalName( HostsFileInfo * node );
-DEBUG_LOCAL BOOL               IsSameName( HostsFileInfo * node, const char * name );
-DEBUG_LOCAL OSStatus   HostsFileOpen( HostsFile ** self, const char * fname );
-DEBUG_LOCAL OSStatus   HostsFileClose( HostsFile * self );
-DEBUG_LOCAL void               HostsFileInfoFree( HostsFileInfo * info );
-DEBUG_LOCAL OSStatus   HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo );
-DEBUG_LOCAL DWORD              GetScopeId( DWORD ifIndex );
-
-#ifdef ENABLE_REVERSE_LOOKUP
-DEBUG_LOCAL OSStatus   IsReverseLookup( LPCWSTR name, size_t size );
-#endif
-
-
-#if 0
-#pragma mark == Globals ==
-#endif
-
-//===========================================================================================================================
-//     Globals
-//===========================================================================================================================
-
-// {B600E6E9-553B-4a19-8696-335E5C896153}
-DEBUG_LOCAL HINSTANCE                          gInstance                       = NULL;
-DEBUG_LOCAL wchar_t                            *       gNSPName                        = L"mdnsNSP";
-DEBUG_LOCAL GUID                                       gNSPGUID                        = { 0xb600e6e9, 0x553b, 0x4a19, { 0x86, 0x96, 0x33, 0x5e, 0x5c, 0x89, 0x61, 0x53 } };
-DEBUG_LOCAL LONG                                       gRefCount                       = 0;
-DEBUG_LOCAL CRITICAL_SECTION           gLock;
-DEBUG_LOCAL bool                                       gLockInitialized        = false;
-DEBUG_LOCAL QueryRef                           gQueryList                      = NULL;
-DEBUG_LOCAL HostsFileInfo              *       gHostsFileInfo          = NULL;
-typedef DWORD
-       ( WINAPI * GetAdaptersAddressesFunctionPtr )( 
-                       ULONG                                   inFamily, 
-                       DWORD                                   inFlags, 
-                       PVOID                                   inReserved, 
-                       PIP_ADAPTER_ADDRESSES   inAdapter, 
-                       PULONG                                  outBufferSize );
-
-DEBUG_LOCAL HMODULE                                                            gIPHelperLibraryInstance                        = NULL;
-DEBUG_LOCAL GetAdaptersAddressesFunctionPtr            gGetAdaptersAddressesFunctionPtr        = NULL;
-
-
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     DllMain
-//===========================================================================================================================
-
-BOOL APIENTRY  DllMain( HINSTANCE inInstance, DWORD inReason, LPVOID inReserved )
-{
-       DEBUG_USE_ONLY( inInstance );
-       DEBUG_UNUSED( inReserved );
-
-       switch( inReason )
-       {
-               case DLL_PROCESS_ATTACH:                        
-                       gInstance = inInstance;         
-                       gHostsFileInfo  = NULL;
-                       debug_initialize( kDebugOutputTypeWindowsEventLog, "mDNS NSP", inInstance );
-                       debug_set_property( kDebugPropertyTagPrintLevel, kDebugLevelNotice );
-                       dlog( kDebugLevelTrace, "\n" );
-                       dlog( kDebugLevelVerbose, "%s: process attach\n", __ROUTINE__ );
-
-                       break;
-               
-               case DLL_PROCESS_DETACH:
-                       HostsFileInfoFree( gHostsFileInfo );
-                       gHostsFileInfo = NULL;
-                       dlog( kDebugLevelVerbose, "%s: process detach\n", __ROUTINE__ );
-                       break;
-               
-               case DLL_THREAD_ATTACH:
-                       dlog( kDebugLevelVerbose, "%s: thread attach\n", __ROUTINE__ );
-                       break;
-               
-               case DLL_THREAD_DETACH:
-                       dlog( kDebugLevelVerbose, "%s: thread detach\n", __ROUTINE__ );
-                       break;
-               
-               default:
-                       dlog( kDebugLevelNotice, "%s: unknown reason code (%d)\n", __ROUTINE__, inReason );
-                       break;
-       }
-
-       return( TRUE );
-}
-
-
-//===========================================================================================================================
-//     DllRegisterServer
-//===========================================================================================================================
-
-STDAPI DllRegisterServer( void )
-{
-       WSADATA         wsd;
-       WCHAR           path[ MAX_PATH ];
-       HRESULT         err;
-       
-       dlog( kDebugLevelTrace, "DllRegisterServer\n" );
-
-       err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-
-       // Unregister before registering to workaround an installer
-       // problem during upgrade installs.
-
-       WSCUnInstallNameSpace( &gNSPGUID );
-
-       err = GetModuleFileNameW( gInstance, path, MAX_PATH );
-       err = translate_errno( err != 0, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-
-       err = WSCInstallNameSpace( gNSPName, path, NS_DNS, 1, &gNSPGUID );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       
-exit:
-
-       WSACleanup();
-       return( err );
-}
-
-//===========================================================================================================================
-//     DllUnregisterServer
-//===========================================================================================================================
-
-STDAPI DllUnregisterServer( void )
-{
-       WSADATA         wsd;
-       HRESULT err;
-       
-       dlog( kDebugLevelTrace, "DllUnregisterServer\n" );
-       
-       err = WSAStartup( MAKEWORD( 2, 2 ), &wsd );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-       
-       err = WSCUnInstallNameSpace( &gNSPGUID );
-       err = translate_errno( err == 0, errno_compat(), WSAEINVAL );
-       require_noerr( err, exit );
-               
-exit:
-
-       WSACleanup();
-       return err;
-}
-
-
-//===========================================================================================================================
-//     NSPStartup
-//
-//     This function is called when our namespace DLL is loaded. It sets up the NSP functions we implement and initializes us.
-//===========================================================================================================================
-
-int WSPAPI     NSPStartup( LPGUID inProviderID, LPNSP_ROUTINE outRoutines )
-{
-       OSStatus                err;
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
-       
-       // Only initialize if this is the first time NSPStartup is called. 
-       
-       if( InterlockedIncrement( &gRefCount ) != 1 )
-       {
-               err = NO_ERROR;
-               goto exit;
-       }
-       
-       // Initialize our internal state.
-       
-       InitializeCriticalSection( &gLock );
-       gLockInitialized = true;
-       
-       // Set the size to exclude NSPIoctl because we don't implement it.
-       
-       outRoutines->cbSize                                     = FIELD_OFFSET( NSP_ROUTINE, NSPIoctl );
-       outRoutines->dwMajorVersion                     = 4;
-       outRoutines->dwMinorVersion                     = 4;
-       outRoutines->NSPCleanup                         = NSPCleanup;
-       outRoutines->NSPLookupServiceBegin      = NSPLookupServiceBegin;
-       outRoutines->NSPLookupServiceNext       = NSPLookupServiceNext;
-       outRoutines->NSPLookupServiceEnd        = NSPLookupServiceEnd;
-       outRoutines->NSPSetService                      = NSPSetService;
-       outRoutines->NSPInstallServiceClass     = NSPInstallServiceClass;
-       outRoutines->NSPRemoveServiceClass      = NSPRemoveServiceClass;
-       outRoutines->NSPGetServiceClassInfo     = NSPGetServiceClassInfo;
-       
-       // See if we can get the address for the GetAdaptersAddresses() API.  This is only in XP, but we want our
-       // code to run on older versions of Windows
-
-       if ( !gIPHelperLibraryInstance )
-       {
-               gIPHelperLibraryInstance = LoadLibrary( TEXT( "Iphlpapi" ) );
-               if( gIPHelperLibraryInstance )
-               {
-                       gGetAdaptersAddressesFunctionPtr = (GetAdaptersAddressesFunctionPtr) GetProcAddress( gIPHelperLibraryInstance, "GetAdaptersAddresses" );
-               }
-       }
-
-       err = NO_ERROR;
-       
-exit:
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       if( err != NO_ERROR )
-       {
-               NSPCleanup( inProviderID );
-               SetLastError( (DWORD) err );
-               return( SOCKET_ERROR );
-       }
-       return( NO_ERROR );
-}
-
-//===========================================================================================================================
-//     NSPCleanup
-//
-//     This function is called when our namespace DLL is unloaded. It cleans up anything we set up in NSPStartup.
-//===========================================================================================================================
-
-int    WSPAPI  NSPCleanup( LPGUID inProviderID )
-{
-       DEBUG_USE_ONLY( inProviderID );
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       dlog( kDebugLevelTrace, "%s (GUID=%U, refCount=%ld)\n", __ROUTINE__, inProviderID, gRefCount );
-       
-       // Only initialize if this is the first time NSPStartup is called.
-       
-       if( InterlockedDecrement( &gRefCount ) != 0 )
-       {
-               goto exit;
-       }
-       
-       // Stop any outstanding queries.
-       
-       if( gLockInitialized )
-       {
-               NSPLock();
-       }
-       while( gQueryList )
-       {
-               check_string( gQueryList->refCount == 1, "NSPCleanup with outstanding queries!" );
-               QueryRelease( gQueryList );
-       }
-       if( gLockInitialized )
-       {
-               NSPUnlock();
-       }
-       
-       if( gLockInitialized )
-       {
-               gLockInitialized = false;
-               DeleteCriticalSection( &gLock );
-       }
-
-       if( gIPHelperLibraryInstance )
-       {
-               BOOL ok;
-                               
-               ok = FreeLibrary( gIPHelperLibraryInstance );
-               check_translated_errno( ok, GetLastError(), kUnknownErr );
-               gIPHelperLibraryInstance = NULL;
-       }
-       
-exit:
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       return( NO_ERROR );
-}
-
-//===========================================================================================================================
-//     NSPLookupServiceBegin
-//
-//     This function maps to the WinSock WSALookupServiceBegin function. It starts the lookup process and returns a HANDLE 
-//     that can be used in subsequent operations. Subsequent calls only need to refer to this query by the handle as 
-//     opposed to specifying the query parameters each time.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI
-       NSPLookupServiceBegin(
-               LPGUID                                  inProviderID,
-               LPWSAQUERYSETW                  inQuerySet,
-               LPWSASERVICECLASSINFOW  inServiceClassInfo,
-               DWORD                                   inFlags,   
-               LPHANDLE                                outLookup )
-{
-       OSStatus                err;
-       QueryRef                obj;
-       LPCWSTR                 name;
-       size_t                  size;
-       LPCWSTR                 p;
-       DWORD           type;
-       DWORD                   n;
-       DWORD                   i;
-       INT                             family;
-       INT                             protocol;
-       
-       DEBUG_UNUSED( inProviderID );
-       DEBUG_UNUSED( inServiceClassInfo );
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       
-       obj = NULL;
-       require_action( inQuerySet, exit, err = WSAEINVAL );
-       name = inQuerySet->lpszServiceInstanceName;
-       require_action_quiet( name, exit, err = WSAEINVAL );
-       require_action( outLookup, exit, err = WSAEINVAL );
-       
-       dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=\"%S\")\n", __ROUTINE__, inFlags, name );
-       dlog_query_set( kDebugLevelVerbose, inQuerySet );
-       
-       // Check if we can handle this type of request and if we support any of the protocols being requested.
-       // We only support the DNS namespace, TCP and UDP protocols, and IPv4. Only blob results are supported.
-       
-       require_action_quiet( inFlags & (LUP_RETURN_ADDR|LUP_RETURN_BLOB), exit, err = WSASERVICE_NOT_FOUND );
-       
-       type = inQuerySet->dwNameSpace;
-       require_action_quiet( ( type == NS_DNS ) || ( type == NS_ALL ), exit, err = WSASERVICE_NOT_FOUND );
-       
-       n = inQuerySet->dwNumberOfProtocols;
-       if( n > 0 )
-       {
-               require_action( inQuerySet->lpafpProtocols, exit, err = WSAEINVAL );
-               for( i = 0; i < n; ++i )
-               {
-                       family = inQuerySet->lpafpProtocols[ i ].iAddressFamily;
-                       protocol = inQuerySet->lpafpProtocols[ i ].iProtocol;
-                       if( ( family == AF_INET ) && ( ( protocol == IPPROTO_UDP ) || ( protocol == IPPROTO_TCP ) ) )
-                       {
-                               break;
-                       }
-               }
-               require_action_quiet( i < n, exit, err = WSASERVICE_NOT_FOUND );
-       }
-       
-       // Check if the name ends in ".local" and if not, exit with an error since we only resolve .local names.
-       // The name may or may not end with a "." (fully qualified) so handle both cases. DNS is also case 
-       // insensitive the check for .local has to be case insensitive (.LoCaL is equivalent to .local). This
-       // manually does the wchar_t strlen and stricmp to avoid needing any special wchar_t versions of the 
-       // libraries. It is probably faster to do the inline compare than invoke functions to do it anyway.
-       
-       for( p = name; *p; ++p ) {}             // Find end of string
-       size = (size_t)( p - name );
-       require_action_quiet( size > sizeof_string( ".local" ), exit, err = WSASERVICE_NOT_FOUND );
-       
-       p = name + ( size - 1 );
-       p = ( *p == '.' ) ? ( p - sizeof_string( ".local" ) ) : ( ( p - sizeof_string( ".local" ) ) + 1 );
-       if      ( ( ( p[ 0 ] != '.' )                                           ||
-               ( ( p[ 1 ] != 'L' ) && ( p[ 1 ] != 'l' ) )      ||
-               ( ( p[ 2 ] != 'O' ) && ( p[ 2 ] != 'o' ) )      ||
-               ( ( p[ 3 ] != 'C' ) && ( p[ 3 ] != 'c' ) )      ||
-               ( ( p[ 4 ] != 'A' ) && ( p[ 4 ] != 'a' ) )      ||
-               ( ( p[ 5 ] != 'L' ) && ( p[ 5 ] != 'l' ) ) ) )
-       {
-#ifdef ENABLE_REVERSE_LOOKUP
-
-               err = IsReverseLookup( name, size );
-
-#else
-
-               err = WSASERVICE_NOT_FOUND;
-
-#endif
-
-               require_noerr( err, exit );
-       }
-       else
-       {
-               const char      *       replyDomain;
-               char                    translated[ kDNSServiceMaxDomainName ];
-               int                             n;
-               int                             labels          = 0;
-               const char      *       label[MAX_LABELS];
-               char                    text[64];
-
-               n = WideCharToMultiByte( CP_UTF8, 0, name, -1, translated, sizeof( translated ), NULL, NULL );
-               require_action( n > 0, exit, err = WSASERVICE_NOT_FOUND );
-
-               // <rdar://problem/4050633>
-
-               // Don't resolve multi-label name
-
-               // <rdar://problem/5914160> Eliminate use of GetNextLabel in mdnsNSP
-               // Add checks for GetNextLabel returning NULL, individual labels being greater than
-               // 64 bytes, and the number of labels being greater than MAX_LABELS
-               replyDomain = translated;
-
-               while (replyDomain && *replyDomain && labels < MAX_LABELS)
-               {
-                       label[labels++] = replyDomain;
-                       replyDomain             = GetNextLabel(replyDomain, text);
-               }
-
-               require_action( labels == 2, exit, err = WSASERVICE_NOT_FOUND );
-
-               // <rdar://problem/3936771>
-               //
-               // Check to see if the name of this host is in the hosts table. If so,
-               // don't try and resolve it
-               
-               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.
-               
-       NSPLock();
-       
-       err = QueryCreate( inQuerySet, inFlags, &obj );
-       NSPUnlock();
-       require_noerr( err, exit );
-       
-       *outLookup = (HANDLE) obj;
-       
-exit:
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       if( err != NO_ERROR )
-       {
-               SetLastError( (DWORD) err );
-               return( SOCKET_ERROR );
-       }
-       return( NO_ERROR );
-}
-
-//===========================================================================================================================
-//     NSPLookupServiceNext
-//
-//     This function maps to the Winsock call WSALookupServiceNext. This routine takes a handle to a previously defined 
-//     query and attempts to locate a service matching the criteria defined by the query. If so, that instance is returned 
-//     in the lpqsResults parameter.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI
-       NSPLookupServiceNext(  
-               HANDLE                  inLookup,
-               DWORD                   inFlags,
-               LPDWORD                 ioSize,
-               LPWSAQUERYSETW  outResults )
-{
-       BOOL                    data4;
-       BOOL                    data6;
-       OSStatus                err;
-       QueryRef                obj;
-       DWORD                   waitResult;
-       size_t                  size;
-       
-       DEBUG_USE_ONLY( inFlags );
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       
-       data4 = FALSE;
-       data6 = FALSE;
-       obj = NULL;
-       NSPLock();
-       err = QueryRetain( (QueryRef) inLookup );
-       require_noerr( err, exit );
-       obj = (QueryRef) inLookup;
-       require_action( ioSize, exit, err = WSAEINVAL );
-       require_action( outResults, exit, err = WSAEINVAL );
-       
-       dlog( kDebugLevelTrace, "%s (lookup=%#p, flags=0x%08X, *ioSize=%d)\n", __ROUTINE__, inLookup, inFlags, *ioSize );
-       
-       // Wait for data or a cancel. Release the lock while waiting. This is safe because we've retained the query.
-
-       NSPUnlock();
-       waitResult = WaitForMultipleObjects( obj->waitCount, obj->waitHandles, FALSE, 2 * 1000 );
-       NSPLock();
-       require_action_quiet( waitResult != ( WAIT_OBJECT_0 ), exit, err = WSA_E_CANCELLED );
-       err = translate_errno( ( waitResult == WAIT_OBJECT_0 + 1 ) || ( waitResult == WAIT_OBJECT_0 + 2 ), (OSStatus) GetLastError(), WSASERVICE_NOT_FOUND );
-       require_noerr_quiet( err, exit );
-
-       // If we've received an IPv4 reply, then hang out briefly for an IPv6 reply
-
-       if ( waitResult == WAIT_OBJECT_0 + 1 )
-       {
-               data4 = TRUE;
-               data6 = WaitForSingleObject( obj->data6Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
-       }
-
-       // Else we've received an IPv6 reply, so hang out briefly for an IPv4 reply
-
-       else if ( waitResult == WAIT_OBJECT_0 + 2 )
-       {
-               data4 = WaitForSingleObject( obj->data4Event, 100 ) == WAIT_OBJECT_0 ? TRUE : FALSE;
-               data6 = TRUE;
-       }
-
-       if ( data4 )
-       {
-               __try
-               {
-                       err = DNSServiceProcessResult(obj->resolver4);
-               }
-               __except( EXCEPTION_EXECUTE_HANDLER )
-               {
-                       err = kUnknownErr;
-               }
-
-               require_noerr( err, exit );
-       }
-
-       if ( data6 )
-       {
-               __try
-               {
-                       err = DNSServiceProcessResult( obj->resolver6 );
-               }
-               __except( EXCEPTION_EXECUTE_HANDLER )
-               {
-                       err = kUnknownErr;
-               }
-
-               require_noerr( err, exit );
-       }
-
-       require_action_quiet( obj->addr4Valid || obj->addr6Valid, exit, err = WSA_E_NO_MORE );
-
-       // Copy the externalized query results to the callers buffer (if it fits).
-       
-       size = QueryCopyQuerySetSize( obj, obj->querySet, obj->querySetFlags );
-       require_action( size <= (size_t) *ioSize, exit, err = WSAEFAULT );
-       
-       QueryCopyQuerySetTo( obj, obj->querySet, obj->querySetFlags, outResults );
-       outResults->dwOutputFlags = RESULT_IS_ADDED;
-       obj->addr4Valid = false;
-       obj->addr6Valid = false;
-
-exit:
-       if( obj )
-       {
-               QueryRelease( obj );
-       }
-       NSPUnlock();
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       if( err != NO_ERROR )
-       {
-               SetLastError( (DWORD) err );
-               return( SOCKET_ERROR );
-       }
-       return( NO_ERROR );
-}
-
-//===========================================================================================================================
-//     NSPLookupServiceEnd
-//
-//     This function maps to the Winsock call WSALookupServiceEnd. Once the user process has finished is query (usually 
-//     indicated when WSALookupServiceNext returns the error WSA_E_NO_MORE) a call to this function is made to release any 
-//     allocated resources associated with the query.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPLookupServiceEnd( HANDLE inLookup )
-{
-       OSStatus                err;
-
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       
-       dlog( kDebugLevelTrace, "%s (lookup=%#p)\n", __ROUTINE__, inLookup );
-       
-       NSPLock();
-       err = QueryRelease( (QueryRef) inLookup );
-       NSPUnlock();
-       require_noerr( err, exit );
-       
-exit:
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       if( err != NO_ERROR )
-       {
-               SetLastError( (DWORD) err );
-               return( SOCKET_ERROR );
-       }
-       return( NO_ERROR );
-}
-
-//===========================================================================================================================
-//     NSPSetService
-//
-//     This function maps to the Winsock call WSASetService. This routine is called when the user wants to register or 
-//     deregister an instance of a server with our service. For registration, the user needs to associate the server with a 
-//     service class. For deregistration the service class is required along with the servicename. The inRegInfo parameter 
-//     contains a WSAQUERYSET structure defining the server (such as protocol and address where it is).
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI
-       NSPSetService(
-               LPGUID                                  inProviderID,                                           
-               LPWSASERVICECLASSINFOW  inServiceClassInfo,   
-               LPWSAQUERYSETW                  inRegInfo,                                
-               WSAESETSERVICEOP                inOperation,                       
-               DWORD                                   inFlags )
-{
-       DEBUG_UNUSED( inProviderID );
-       DEBUG_UNUSED( inServiceClassInfo );
-       DEBUG_UNUSED( inRegInfo );
-       DEBUG_UNUSED( inOperation );
-       DEBUG_UNUSED( inFlags );
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-       
-       // We don't allow services to be registered so always return an error.
-       
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       return( WSAEINVAL );
-}
-
-//===========================================================================================================================
-//     NSPInstallServiceClass
-//
-//     This function maps to the Winsock call WSAInstallServiceClass. This routine is used to install a service class which 
-//     is used to define certain characteristics for a group of services. After a service class is registered, an actual
-//     instance of a server may be registered.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPInstallServiceClass( LPGUID inProviderID, LPWSASERVICECLASSINFOW inServiceClassInfo )
-{
-       DEBUG_UNUSED( inProviderID );
-       DEBUG_UNUSED( inServiceClassInfo );
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-       
-       // We don't allow service classes to be installed so always return an error.
-
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       return( WSA_INVALID_PARAMETER );
-}
-
-//===========================================================================================================================
-//     NSPRemoveServiceClass
-//
-//     This function maps to the Winsock call WSARemoveServiceClass. This routine removes a previously registered service 
-//     class. This is accomplished by connecting to the namespace service and writing the GUID which defines the given 
-//     service class.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPRemoveServiceClass( LPGUID inProviderID, LPGUID inServiceClassID )
-{
-       DEBUG_UNUSED( inProviderID );
-       DEBUG_UNUSED( inServiceClassID );
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-       
-       // We don't allow service classes to be installed so always return an error.
-       
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       return( WSATYPE_NOT_FOUND );
-}
-
-//===========================================================================================================================
-//     NSPGetServiceClassInfo
-//
-//     This function maps to the Winsock call WSAGetServiceClassInfo. This routine returns the information associated with 
-//     a given service class.
-//===========================================================================================================================
-
-DEBUG_LOCAL int WSPAPI NSPGetServiceClassInfo( LPGUID inProviderID, LPDWORD ioSize, LPWSASERVICECLASSINFOW ioServiceClassInfo )
-{
-       DEBUG_UNUSED( inProviderID );
-       DEBUG_UNUSED( ioSize );
-       DEBUG_UNUSED( ioServiceClassInfo );
-       
-       dlog( kDebugLevelTrace, "%s begin (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       dlog( kDebugLevelTrace, "%s\n", __ROUTINE__ );
-       
-       // We don't allow service classes to be installed so always return an error.
-       
-       dlog( kDebugLevelTrace, "%s end   (ticks=%d)\n", __ROUTINE__, GetTickCount() );
-       return( WSATYPE_NOT_FOUND );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-//===========================================================================================================================
-//     QueryCreate
-//
-//     Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   QueryCreate( const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags, QueryRef *outRef )
-{
-       OSStatus                err;
-       QueryRef                obj;
-       char                    name[ kDNSServiceMaxDomainName ];
-       int                             n;
-       QueryRef *              p;
-       SOCKET                  s4;
-       SOCKET                  s6;
-
-       obj = NULL;
-       check( inQuerySet );
-       check( inQuerySet->lpszServiceInstanceName );
-       check( outRef );
-       
-       // Convert the wchar_t name to UTF-8.
-       
-       n = WideCharToMultiByte( CP_UTF8, 0, inQuerySet->lpszServiceInstanceName, -1, name, sizeof( name ), NULL, NULL );
-       err = translate_errno( n > 0, (OSStatus) GetLastError(), WSAEINVAL );
-       require_noerr( err, exit );
-       
-       // Allocate the object and append it to the list. Append immediately so releases of partial objects work.
-       
-       obj = (QueryRef) calloc( 1, sizeof( *obj ) );
-       require_action( obj, exit, err = WSA_NOT_ENOUGH_MEMORY );
-       
-       obj->refCount = 1;
-       
-       for( p = &gQueryList; *p; p = &( *p )->next ) {}        // Find the end of the list.
-       *p = obj;
-       
-       // Set up cancel event
-
-       obj->cancelEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
-       require_action( obj->cancelEvent, exit, err = WSA_NOT_ENOUGH_MEMORY );
-
-       // Set up events to signal when A record data is ready
-       
-       obj->data4Event = CreateEvent( NULL, TRUE, FALSE, NULL );
-       require_action( obj->data4Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
-       
-       // Start the query.  Handle delay loaded DLL errors.
-
-       __try
-       {
-               err = DNSServiceQueryRecord( &obj->resolver4, 0, 0, name, kDNSServiceType_A, kDNSServiceClass_IN, QueryRecordCallback4, obj );
-       }
-       __except( EXCEPTION_EXECUTE_HANDLER )
-       {
-               err = kUnknownErr;
-       }
-
-       require_noerr( err, exit );
-
-       // Attach the socket to the event
-
-       __try
-       {
-               s4 = DNSServiceRefSockFD(obj->resolver4);
-       }
-       __except( EXCEPTION_EXECUTE_HANDLER )
-       {
-               s4 = INVALID_SOCKET;
-       }
-
-       err = translate_errno( s4 != INVALID_SOCKET, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-
-       WSAEventSelect(s4, obj->data4Event, FD_READ|FD_CLOSE);
-       
-       // Set up events to signal when AAAA record data is ready
-       
-       obj->data6Event = CreateEvent( NULL, TRUE, FALSE, NULL );
-       require_action( obj->data6Event, exit, err = WSA_NOT_ENOUGH_MEMORY );
-       
-       // Start the query.  Handle delay loaded DLL errors.
-
-       __try
-       {
-               err = DNSServiceQueryRecord( &obj->resolver6, 0, 0, name, kDNSServiceType_AAAA, kDNSServiceClass_IN, QueryRecordCallback6, obj );
-       }
-       __except( EXCEPTION_EXECUTE_HANDLER )
-       {
-               err = kUnknownErr;
-       }
-
-       require_noerr( err, exit );
-
-       // Attach the socket to the event
-
-       __try
-       {
-               s6 = DNSServiceRefSockFD(obj->resolver6);
-       }
-       __except( EXCEPTION_EXECUTE_HANDLER )
-       {
-               s6 = INVALID_SOCKET;
-       }
-
-       err = translate_errno( s6 != INVALID_SOCKET, errno_compat(), kUnknownErr );
-       require_noerr( err, exit );
-
-       WSAEventSelect(s6, obj->data6Event, FD_READ|FD_CLOSE);
-
-       obj->waitCount = 0;
-       obj->waitHandles[ obj->waitCount++ ] = obj->cancelEvent;
-       obj->waitHandles[ obj->waitCount++ ] = obj->data4Event;
-       obj->waitHandles[ obj->waitCount++ ] = obj->data6Event;
-       
-       check( obj->waitCount == sizeof_array( obj->waitHandles ) );
-       
-       // Copy the QuerySet so it can be returned later.
-       
-       obj->querySetFlags = inQuerySetFlags;
-       inQuerySetFlags = ( inQuerySetFlags & ~( LUP_RETURN_ADDR | LUP_RETURN_BLOB ) ) | LUP_RETURN_NAME;
-       err = QueryCopyQuerySet( obj, inQuerySet, inQuerySetFlags, &obj->querySet, &obj->querySetSize );
-       require_noerr( err, exit );
-       
-       // Success!
-       
-       *outRef = obj;
-       obj     = NULL;
-       err     = NO_ERROR;
-
-exit:
-       if( obj )
-       {
-               QueryRelease( obj );
-       }
-       return( err );
-}
-
-//===========================================================================================================================
-//     QueryRetain
-//
-//     Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   QueryRetain( QueryRef inRef )
-{
-       OSStatus                err;
-       QueryRef                obj;
-       
-       for( obj = gQueryList; obj; obj = obj->next )
-       {
-               if( obj == inRef )
-               {
-                       break;
-               }
-       }
-       require_action( obj, exit, err = WSA_INVALID_HANDLE );
-       
-       ++inRef->refCount;
-       err = NO_ERROR;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     QueryRelease
-//
-//     Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus   QueryRelease( QueryRef inRef )
-{
-       OSStatus                err;
-       QueryRef *              p;
-       BOOL                    ok;
-               
-       // Find the item in the list.
-       
-       for( p = &gQueryList; *p; p = &( *p )->next )
-       {
-               if( *p == inRef )
-               {
-                       break;
-               }
-       }
-       require_action( *p, exit, err = WSA_INVALID_HANDLE );
-       
-       // Signal a cancel to unblock any threads waiting for results.
-       
-       if( inRef->cancelEvent )
-       {
-               ok = SetEvent( inRef->cancelEvent );
-               check_translated_errno( ok, GetLastError(), WSAEINVAL );
-       }
-       
-       // Stop the query.
-       
-       if( inRef->resolver4 )
-       {
-               __try
-               {
-                       DNSServiceRefDeallocate( inRef->resolver4 );
-               }
-               __except( EXCEPTION_EXECUTE_HANDLER )
-               {
-               }
-               
-               inRef->resolver4 = NULL;
-       }
-
-       if ( inRef->resolver6 )
-       {
-               __try
-               {
-                       DNSServiceRefDeallocate( inRef->resolver6 );
-               }
-               __except( EXCEPTION_EXECUTE_HANDLER )
-               {
-               }
-
-               inRef->resolver6 = NULL;
-       }
-       
-       // Decrement the refCount. Fully release if it drops to 0. If still referenced, just exit.
-       
-       if( --inRef->refCount != 0 )
-       {
-               err = NO_ERROR;
-               goto exit;
-       }
-       *p = inRef->next;
-       
-       // Release resources.
-       
-       if( inRef->cancelEvent )
-       {
-               ok = CloseHandle( inRef->cancelEvent );
-               check_translated_errno( ok, GetLastError(), WSAEINVAL );
-       }
-       if( inRef->data4Event )
-       {
-               ok = CloseHandle( inRef->data4Event );
-               check_translated_errno( ok, GetLastError(), WSAEINVAL );
-       }
-       if( inRef->data6Event )
-       {
-               ok = CloseHandle( inRef->data6Event );
-               check_translated_errno( ok, GetLastError(), WSAEINVAL );
-       }
-       if( inRef->querySet )
-       {
-               free( inRef->querySet );
-       }
-       free( inRef );
-       err = NO_ERROR;
-       
-exit:
-       return( err );
-}
-
-//===========================================================================================================================
-//     QueryRecordCallback4
-//===========================================================================================================================
-
-DEBUG_LOCAL void CALLBACK_COMPAT
-       QueryRecordCallback4(
-               DNSServiceRef           inRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inErrorCode,
-               const char *            inName,    
-               uint16_t                        inRRType,
-               uint16_t                        inRRClass,
-               uint16_t                        inRDataSize,
-               const void *            inRData,
-               uint32_t                        inTTL,
-               void *                          inContext )
-{
-       QueryRef                        obj;
-       const char *            src;
-       char *                          dst;
-       BOOL                            ok;
-       
-       DEBUG_UNUSED( inFlags );
-       DEBUG_UNUSED( inInterfaceIndex );
-       DEBUG_UNUSED( inTTL );
-
-       NSPLock();
-       obj = (QueryRef) inContext;
-       check( obj );
-       require_noerr( inErrorCode, exit );
-       require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
-       require( inRRClass   == kDNSServiceClass_IN, exit );
-       require( inRRType    == kDNSServiceType_A, exit );
-       require( inRDataSize == 4, exit );
-       
-       dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n", 
-               __ROUTINE__, inFlags, inName, inRRType, inRDataSize );
-               
-       // Copy the name if needed.
-       
-       if( obj->name[ 0 ] == '\0' )
-       {
-               src = inName;
-               dst = obj->name;
-               while( *src != '\0' )
-               {
-                       *dst++ = *src++;
-               }
-               *dst = '\0';
-               obj->nameSize = (size_t)( dst - obj->name );
-               check( obj->nameSize < sizeof( obj->name ) );
-       }
-       
-       // Copy the data.
-       
-       memcpy( &obj->addr4, inRData, inRDataSize );
-       obj->addr4Valid = true;
-       obj->numValidAddrs++;
-       
-       // Signal that a result is ready.
-       
-       check( obj->data4Event );
-       ok = SetEvent( obj->data4Event );
-       check_translated_errno( ok, GetLastError(), WSAEINVAL );
-       
-       // Stop the resolver after the first response.
-       
-       __try
-       {
-               DNSServiceRefDeallocate( inRef );
-       }
-       __except( EXCEPTION_EXECUTE_HANDLER )
-       {
-       }
-
-       obj->resolver4 = NULL;
-
-exit:
-       NSPUnlock();
-}
-
-#if 0
-#pragma mark -
-#endif
-
-
-//===========================================================================================================================
-//     QueryRecordCallback6
-//===========================================================================================================================
-
-DEBUG_LOCAL void CALLBACK_COMPAT
-       QueryRecordCallback6(
-               DNSServiceRef           inRef,
-               DNSServiceFlags         inFlags,
-               uint32_t                        inInterfaceIndex,
-               DNSServiceErrorType     inErrorCode,
-               const char *            inName,    
-               uint16_t                        inRRType,
-               uint16_t                        inRRClass,
-               uint16_t                        inRDataSize,
-               const void *            inRData,
-               uint32_t                        inTTL,
-               void *                          inContext )
-{
-       QueryRef                        obj;
-       const char *            src;
-       char *                          dst;
-       BOOL                            ok;
-       
-       DEBUG_UNUSED( inFlags );
-       DEBUG_UNUSED( inInterfaceIndex );
-       DEBUG_UNUSED( inTTL );
-
-       NSPLock();
-       obj = (QueryRef) inContext;
-       check( obj );
-       require_noerr( inErrorCode, exit );
-       require_quiet( inFlags & kDNSServiceFlagsAdd, exit );
-       require( inRRClass   == kDNSServiceClass_IN, exit );
-       require( inRRType    == kDNSServiceType_AAAA, exit );
-       require( inRDataSize == 16, exit );
-       
-       dlog( kDebugLevelTrace, "%s (flags=0x%08X, name=%s, rrType=%d, rDataSize=%d)\n", 
-               __ROUTINE__, inFlags, inName, inRRType, inRDataSize );
-
-       // Copy the name if needed.
-       
-       if( obj->name[ 0 ] == '\0' )
-       {
-               src = inName;
-               dst = obj->name;
-               while( *src != '\0' )
-               {
-                       *dst++ = *src++;
-               }
-               *dst = '\0';
-               obj->nameSize = (size_t)( dst - obj->name );
-               check( obj->nameSize < sizeof( obj->name ) );
-       }
-       
-       // Copy the data.
-       
-       memcpy( &obj->addr6, inRData, inRDataSize );
-
-       obj->addr6ScopeId = GetScopeId( inInterfaceIndex );
-       require( obj->addr6ScopeId, exit );
-       obj->addr6Valid   = true;
-       obj->numValidAddrs++;
-
-       // Signal that we're done
-       
-       check( obj->data6Event );
-       ok = SetEvent( obj->data6Event );
-       check_translated_errno( ok, GetLastError(), WSAEINVAL );
-
-       // Stop the resolver after the first response.
-       
-       __try
-       {
-               DNSServiceRefDeallocate( inRef );
-       }
-       __except( EXCEPTION_EXECUTE_HANDLER )
-       {
-       }
-
-       obj->resolver6 = NULL;
-
-exit:
-
-       
-       
-       NSPUnlock();
-}
-
-
-//===========================================================================================================================
-//     QueryCopyQuerySet
-//
-//     Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-       QueryCopyQuerySet( 
-               QueryRef                                inRef, 
-               const WSAQUERYSETW *    inQuerySet, 
-               DWORD                                   inQuerySetFlags, 
-               WSAQUERYSETW **                 outQuerySet, 
-               size_t *                                outSize )
-{
-       OSStatus                        err;
-       size_t                          size;
-       WSAQUERYSETW *          qs;
-       
-       check( inQuerySet );
-       check( outQuerySet );
-       
-       size  = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
-       qs = (WSAQUERYSETW *) calloc( 1, size );
-       require_action( qs, exit, err = WSA_NOT_ENOUGH_MEMORY  );
-       
-       QueryCopyQuerySetTo( inRef, inQuerySet, inQuerySetFlags, qs );
-       
-       *outQuerySet = qs;
-       if( outSize )
-       {
-               *outSize = size;
-       }
-       qs = NULL;
-       err = NO_ERROR;
-       
-exit:
-       if( qs )
-       {
-               free( qs );
-       }
-       return( err );  
-}
-
-
-
-//===========================================================================================================================
-//     QueryCopyQuerySetTo
-//
-//     Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL void
-       QueryCopyQuerySetTo( 
-               QueryRef                                inRef, 
-               const WSAQUERYSETW *    inQuerySet, 
-               DWORD                                   inQuerySetFlags, 
-               WSAQUERYSETW *                  outQuerySet )
-{
-       uint8_t *               dst;
-       LPCWSTR                 s;
-       LPWSTR                  q;
-       DWORD                   n;
-       DWORD                   i;
-       
-#if( DEBUG )
-       size_t                  debugSize;
-       
-       debugSize = QueryCopyQuerySetSize( inRef, inQuerySet, inQuerySetFlags );
-#endif
-
-       check( inQuerySet );
-       check( outQuerySet );
-
-       dst = (uint8_t *) outQuerySet;
-       
-       // Copy the static portion of the results.
-       
-       *outQuerySet = *inQuerySet;
-       dst += sizeof( *inQuerySet );
-       
-       if( inQuerySetFlags & LUP_RETURN_NAME )
-       {
-               s = inQuerySet->lpszServiceInstanceName;
-               if( s )
-               {
-                       outQuerySet->lpszServiceInstanceName = (LPWSTR) dst;
-                       q = (LPWSTR) dst;
-                       while( ( *q++ = *s++ ) != 0 ) {}
-                       dst = (uint8_t *) q;
-               }
-       }
-       else
-       {
-               outQuerySet->lpszServiceInstanceName = NULL;
-       }
-       
-       if( inQuerySet->lpServiceClassId )
-       {
-               outQuerySet->lpServiceClassId  = (LPGUID) dst;
-               *outQuerySet->lpServiceClassId = *inQuerySet->lpServiceClassId;
-               dst += sizeof( *inQuerySet->lpServiceClassId );
-       }
-       
-       if( inQuerySet->lpVersion )
-       {
-               outQuerySet->lpVersion  = (LPWSAVERSION) dst;
-               *outQuerySet->lpVersion = *inQuerySet->lpVersion;
-               dst += sizeof( *inQuerySet->lpVersion );
-       }
-       
-       s = inQuerySet->lpszComment;
-       if( s )
-       {
-               outQuerySet->lpszComment = (LPWSTR) dst;
-               q = (LPWSTR) dst;
-               while( ( *q++ = *s++ ) != 0 ) {}
-               dst = (uint8_t *) q;
-       }
-       
-       if( inQuerySet->lpNSProviderId )
-       {
-               outQuerySet->lpNSProviderId  = (LPGUID) dst;
-               *outQuerySet->lpNSProviderId = *inQuerySet->lpNSProviderId;
-               dst += sizeof( *inQuerySet->lpNSProviderId );
-       }
-       
-       s = inQuerySet->lpszContext;
-       if( s )
-       {
-               outQuerySet->lpszContext = (LPWSTR) dst;
-               q = (LPWSTR) dst;
-               while( ( *q++ = *s++ ) != 0 ) {}
-               dst = (uint8_t *) q;
-       }
-               
-       n = inQuerySet->dwNumberOfProtocols;
-
-       if( n > 0 )
-       {
-               check( inQuerySet->lpafpProtocols );
-               
-               outQuerySet->lpafpProtocols = (LPAFPROTOCOLS) dst;
-               for( i = 0; i < n; ++i )
-               {
-                       outQuerySet->lpafpProtocols[ i ] = inQuerySet->lpafpProtocols[ i ];
-                       dst += sizeof( *inQuerySet->lpafpProtocols );
-               }
-       }
-               
-       s = inQuerySet->lpszQueryString;
-       if( s )
-       {
-               outQuerySet->lpszQueryString = (LPWSTR) dst;
-               q = (LPWSTR) dst;
-               while( ( *q++ = *s++ ) != 0 ) {}
-               dst = (uint8_t *) q;
-       }
-       
-       // Copy the address(es).
-       
-       if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && ( inRef->numValidAddrs > 0 ) )
-       {
-               struct sockaddr_in      *       addr4;
-               struct sockaddr_in6     *       addr6;
-               int                                             index;
-               
-               outQuerySet->dwNumberOfCsAddrs  = inRef->numValidAddrs;
-               outQuerySet->lpcsaBuffer                = (LPCSADDR_INFO) dst;
-               dst                                                     += ( sizeof( *outQuerySet->lpcsaBuffer ) ) * ( inRef->numValidAddrs ) ;
-               index                                                   = 0;
-               
-               if ( inRef->addr4Valid )
-               {       
-                       outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr                  = NULL;
-                       outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength             = 0;
-               
-                       outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr                 = (LPSOCKADDR) dst;
-                       outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength    = sizeof( struct sockaddr_in );
-               
-                       addr4                                                                                                                   = (struct sockaddr_in *) dst;
-                       memset( addr4, 0, sizeof( *addr4 ) );
-                       addr4->sin_family                                                                                               = AF_INET;
-                       memcpy( &addr4->sin_addr, &inRef->addr4, 4 );
-                       dst                                                                                                                     += sizeof( *addr4 );
-               
-                       outQuerySet->lpcsaBuffer[ index ].iSocketType                                   = AF_INET;              // Emulate Tcpip NSP
-                       outQuerySet->lpcsaBuffer[ index ].iProtocol                                             = IPPROTO_UDP;  // Emulate Tcpip NSP
-
-                       index++;
-               }
-
-               if ( inRef->addr6Valid )
-               {
-                       outQuerySet->lpcsaBuffer[ index ].LocalAddr.lpSockaddr                  = NULL;
-                       outQuerySet->lpcsaBuffer[ index ].LocalAddr.iSockaddrLength             = 0;
-               
-                       outQuerySet->lpcsaBuffer[ index ].RemoteAddr.lpSockaddr                 = (LPSOCKADDR) dst;
-                       outQuerySet->lpcsaBuffer[ index ].RemoteAddr.iSockaddrLength    = sizeof( struct sockaddr_in6 );
-               
-                       addr6                                                                                                                   = (struct sockaddr_in6 *) dst;
-                       memset( addr6, 0, sizeof( *addr6 ) );
-                       addr6->sin6_family                                                                                              = AF_INET6;
-                       addr6->sin6_scope_id                                                                                    = inRef->addr6ScopeId;
-                       memcpy( &addr6->sin6_addr, &inRef->addr6, 16 );
-                       dst                                                                                                                     += sizeof( *addr6 );
-               
-                       outQuerySet->lpcsaBuffer[ index ].iSocketType                                   = AF_INET6;             // Emulate Tcpip NSP
-                       outQuerySet->lpcsaBuffer[ index ].iProtocol                                             = IPPROTO_UDP;  // Emulate Tcpip NSP
-               }
-       }
-       else
-       {
-               outQuerySet->dwNumberOfCsAddrs  = 0;
-               outQuerySet->lpcsaBuffer                = NULL;
-       }
-       
-       // Copy the hostent blob.
-       
-       if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
-       {
-               uint8_t *                               base;
-               struct hostent *                he;
-               uintptr_t *                             p;
-
-               outQuerySet->lpBlob      = (LPBLOB) dst;
-               dst                             += sizeof( *outQuerySet->lpBlob );
-               
-               base = dst;
-               he       = (struct hostent *) dst;
-               dst += sizeof( *he );
-               
-               he->h_name = (char *)( dst - base );
-               memcpy( dst, inRef->name, inRef->nameSize + 1 );
-               dst += ( inRef->nameSize + 1 );
-               
-               he->h_aliases   = (char **)( dst - base );
-               p                               = (uintptr_t *) dst;
-               *p++                    = 0;
-               dst                     = (uint8_t *) p;
-               
-               he->h_addrtype  = AF_INET;
-               he->h_length    = 4;
-               
-               he->h_addr_list = (char **)( dst - base );
-               p                               = (uintptr_t *) dst;
-               dst                += ( 2 * sizeof( *p ) );
-               *p++                    = (uintptr_t)( dst - base );
-               *p++                    = 0;
-               p                               = (uintptr_t *) dst;
-               *p++                    = (uintptr_t) inRef->addr4;
-               dst                     = (uint8_t *) p;
-               
-               outQuerySet->lpBlob->cbSize     = (ULONG)( dst - base );
-               outQuerySet->lpBlob->pBlobData  = (BYTE *) base;
-       }
-       dlog_query_set( kDebugLevelVerbose, outQuerySet );
-
-       check( (size_t)( dst - ( (uint8_t *) outQuerySet ) ) == debugSize );
-}
-
-//===========================================================================================================================
-//     QueryCopyQuerySetSize
-//
-//     Warning: Assumes the NSP lock is held.
-//===========================================================================================================================
-
-DEBUG_LOCAL size_t     QueryCopyQuerySetSize( QueryRef inRef, const WSAQUERYSETW *inQuerySet, DWORD inQuerySetFlags )
-{
-       size_t          size;
-       LPCWSTR         s;
-       LPCWSTR         p;
-       
-       check( inRef );
-       check( inQuerySet );
-       
-       // Calculate the size of the static portion of the results.
-       
-       size = sizeof( *inQuerySet );
-       
-       if( inQuerySetFlags & LUP_RETURN_NAME )
-       {
-               s = inQuerySet->lpszServiceInstanceName;
-               if( s )
-               {
-                       for( p = s; *p; ++p ) {}
-                       size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
-               }
-       }
-       
-       if( inQuerySet->lpServiceClassId )
-       {
-               size += sizeof( *inQuerySet->lpServiceClassId );
-       }
-       
-       if( inQuerySet->lpVersion )
-       {
-               size += sizeof( *inQuerySet->lpVersion );
-       }
-       
-       s = inQuerySet->lpszComment;
-       if( s )
-       {
-               for( p = s; *p; ++p ) {}
-               size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
-       }
-       
-       if( inQuerySet->lpNSProviderId )
-       {
-               size += sizeof( *inQuerySet->lpNSProviderId );
-       }
-       
-       s = inQuerySet->lpszContext;
-       if( s )
-       {
-               for( p = s; *p; ++p ) {}
-               size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
-       }
-       
-       size += ( inQuerySet->dwNumberOfProtocols * sizeof( *inQuerySet->lpafpProtocols ) );
-       
-       s = inQuerySet->lpszQueryString;
-       if( s )
-       {
-               for( p = s; *p; ++p ) {}
-               size += (size_t)( ( ( p - s ) + 1 ) * sizeof( *p ) );
-       }
-       
-       // Calculate the size of the address(es).
-       
-       if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr4Valid )
-       {
-               size += sizeof( *inQuerySet->lpcsaBuffer );
-               size += sizeof( struct sockaddr_in );
-       }
-
-       if( ( inQuerySetFlags & LUP_RETURN_ADDR ) && inRef->addr6Valid )
-       {
-               size += sizeof( *inQuerySet->lpcsaBuffer );
-               size += sizeof( struct sockaddr_in6 );
-       }
-       
-       // Calculate the size of the hostent blob.
-       
-       if( ( inQuerySetFlags & LUP_RETURN_BLOB ) && inRef->addr4Valid )
-       {
-               size += sizeof( *inQuerySet->lpBlob );  // Blob ptr/size structure
-               size += sizeof( struct hostent );               // Old-style hostent structure
-               size += ( inRef->nameSize + 1 );                // Name and null terminator
-               size += 4;                                                              // Alias list terminator (0 offset)
-               size += 4;                                                              // Offset to address.
-               size += 4;                                                              // Address list terminator (0 offset)
-               size += 4;                                                              // IPv4 address
-       }
-       return( size );
-}
-
-#if 0
-#pragma mark -
-#endif
-
-#if( DEBUG )
-//===========================================================================================================================
-//     DebugDumpQuerySet
-//===========================================================================================================================
-
-#define        DebugSocketFamilyToString( FAM )        ( ( FAM ) == AF_INET )  ? "AF_INET"  : \
-                                                                                       ( ( FAM ) == AF_INET6 ) ? "AF_INET6" : ""
-
-#define        DebugSocketProtocolToString( PROTO )    ( ( PROTO ) == IPPROTO_UDP ) ? "IPPROTO_UDP" : \
-                                                                                               ( ( PROTO ) == IPPROTO_TCP ) ? "IPPROTO_TCP" : ""
-
-#define        DebugNameSpaceToString( NS )                    ( ( NS ) == NS_DNS ) ? "NS_DNS" : ( ( NS ) == NS_ALL ) ? "NS_ALL" : ""
-
-void   DebugDumpQuerySet( DebugLevel inLevel, const WSAQUERYSETW *inQuerySet )
-{
-       DWORD           i;
-       
-       check( inQuerySet );
-
-       // Fixed portion of the QuerySet.
-               
-       dlog( inLevel, "QuerySet:\n" );
-       dlog( inLevel, "    dwSize:                  %d (expected %d)\n", inQuerySet->dwSize, sizeof( *inQuerySet ) );
-       if( inQuerySet->lpszServiceInstanceName )
-       {
-               dlog( inLevel, "    lpszServiceInstanceName: %S\n", inQuerySet->lpszServiceInstanceName );
-       }
-       else
-       {
-               dlog( inLevel, "    lpszServiceInstanceName: <null>\n" );
-       }
-       if( inQuerySet->lpServiceClassId )
-       {
-               dlog( inLevel, "    lpServiceClassId:        %U\n", inQuerySet->lpServiceClassId );
-       }
-       else
-       {
-               dlog( inLevel, "    lpServiceClassId:        <null>\n" );
-       }
-       if( inQuerySet->lpVersion )
-       {
-               dlog( inLevel, "    lpVersion:\n" );
-               dlog( inLevel, "        dwVersion:               %d\n", inQuerySet->lpVersion->dwVersion );
-               dlog( inLevel, "        dwVersion:               %d\n", inQuerySet->lpVersion->ecHow );
-       }
-       else
-       {
-               dlog( inLevel, "    lpVersion:               <null>\n" );
-       }
-       if( inQuerySet->lpszComment )
-       {
-               dlog( inLevel, "    lpszComment:             %S\n", inQuerySet->lpszComment );
-       }
-       else
-       {
-               dlog( inLevel, "    lpszComment:             <null>\n" );
-       }
-       dlog( inLevel, "    dwNameSpace:             %d %s\n", inQuerySet->dwNameSpace, 
-               DebugNameSpaceToString( inQuerySet->dwNameSpace ) );
-       if( inQuerySet->lpNSProviderId )
-       {
-               dlog( inLevel, "    lpNSProviderId:          %U\n", inQuerySet->lpNSProviderId );
-       }
-       else
-       {
-               dlog( inLevel, "    lpNSProviderId:          <null>\n" );
-       }
-       if( inQuerySet->lpszContext )
-       {
-               dlog( inLevel, "    lpszContext:             %S\n", inQuerySet->lpszContext );
-       }
-       else
-       {
-               dlog( inLevel, "    lpszContext:             <null>\n" );
-       }
-       dlog( inLevel, "    dwNumberOfProtocols:     %d\n", inQuerySet->dwNumberOfProtocols );
-       dlog( inLevel, "    lpafpProtocols:          %s\n", inQuerySet->lpafpProtocols ? "" : "<null>" );
-       for( i = 0; i < inQuerySet->dwNumberOfProtocols; ++i )
-       {
-               if( i != 0 )
-               {
-                       dlog( inLevel, "\n" );
-               }
-               dlog( inLevel, "        iAddressFamily:          %d %s\n", inQuerySet->lpafpProtocols[ i ].iAddressFamily, 
-                       DebugSocketFamilyToString( inQuerySet->lpafpProtocols[ i ].iAddressFamily ) );
-               dlog( inLevel, "        iProtocol:               %d %s\n", inQuerySet->lpafpProtocols[ i ].iProtocol, 
-                       DebugSocketProtocolToString( inQuerySet->lpafpProtocols[ i ].iProtocol ) );
-       }
-       if( inQuerySet->lpszQueryString )
-       {
-               dlog( inLevel, "    lpszQueryString:         %S\n", inQuerySet->lpszQueryString );
-       }
-       else
-       {
-               dlog( inLevel, "    lpszQueryString:         <null>\n" );
-       }
-       dlog( inLevel, "    dwNumberOfCsAddrs:       %d\n", inQuerySet->dwNumberOfCsAddrs );
-       dlog( inLevel, "    lpcsaBuffer:             %s\n", inQuerySet->lpcsaBuffer ? "" : "<null>" );
-       for( i = 0; i < inQuerySet->dwNumberOfCsAddrs; ++i )
-       {
-               if( i != 0 )
-               {
-                       dlog( inLevel, "\n" );
-               }
-               if( inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr && 
-                       ( inQuerySet->lpcsaBuffer[ i ].LocalAddr.iSockaddrLength > 0 ) )
-               {
-                       dlog( inLevel, "        LocalAddr:               %##a\n", 
-                               inQuerySet->lpcsaBuffer[ i ].LocalAddr.lpSockaddr );
-               }
-               else
-               {
-                       dlog( inLevel, "        LocalAddr:               <null/empty>\n" );
-               }
-               if( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr && 
-                       ( inQuerySet->lpcsaBuffer[ i ].RemoteAddr.iSockaddrLength > 0 ) )
-               {
-                       dlog( inLevel, "        RemoteAddr:              %##a\n", 
-                               inQuerySet->lpcsaBuffer[ i ].RemoteAddr.lpSockaddr );
-               }
-               else
-               {
-                       dlog( inLevel, "        RemoteAddr:              <null/empty>\n" );
-               }
-               dlog( inLevel, "        iSocketType:             %d\n", inQuerySet->lpcsaBuffer[ i ].iSocketType );
-               dlog( inLevel, "        iProtocol:               %d\n", inQuerySet->lpcsaBuffer[ i ].iProtocol );
-       }
-       dlog( inLevel, "    dwOutputFlags:           %d\n", inQuerySet->dwOutputFlags );
-       
-       // Blob portion of the QuerySet.
-       
-       if( inQuerySet->lpBlob )
-       {
-               dlog( inLevel, "    lpBlob:\n" );
-               dlog( inLevel, "        cbSize:                  %ld\n", inQuerySet->lpBlob->cbSize );
-               dlog( inLevel, "        pBlobData:               %#p\n", inQuerySet->lpBlob->pBlobData );
-               dloghex( inLevel, 12, NULL, 0, 0, NULL, 0, 
-                       inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->pBlobData, inQuerySet->lpBlob->cbSize, 
-                       kDebugFlagsNone, NULL, 0 );
-       }
-       else
-       {
-               dlog( inLevel, "    lpBlob:                  <null>\n" );
-       }
-}
-#endif
-
-
-//===========================================================================================================================
-//     InHostsTable
-//===========================================================================================================================
-
-DEBUG_LOCAL BOOL
-InHostsTable( const char * name )
-{
-       HostsFileInfo   *       node;
-       BOOL                            ret = FALSE;
-       OSStatus                        err;
-       
-       check( name );
-
-       if ( gHostsFileInfo == NULL )
-       {
-               TCHAR                           systemDirectory[MAX_PATH];
-               TCHAR                           hFileName[MAX_PATH];
-               HostsFile               *       hFile;
-
-               GetSystemDirectory( systemDirectory, sizeof( systemDirectory ) );
-               snprintf( hFileName, sizeof( hFileName ), "%s\\drivers\\etc\\hosts", systemDirectory );
-               err = HostsFileOpen( &hFile, hFileName );
-               require_noerr( err, exit );
-
-               while ( HostsFileNext( hFile, &node ) == 0 )
-               {
-                       if ( IsLocalName( node ) )
-                       {
-                               node->m_next = gHostsFileInfo;
-                               gHostsFileInfo = node;
-                       }
-                       else
-                       {
-                               HostsFileInfoFree( node );
-                       }
-               }
-
-               HostsFileClose( hFile );
-       }
-
-       for ( node = gHostsFileInfo; node; node = node->m_next )
-       {
-               if ( IsSameName( node, name ) )
-               {
-                       ret = TRUE;
-                       break;
-               }
-       }
-
-exit:
-
-       return ret;
-}
-
-
-//===========================================================================================================================
-//     IsLocalName
-//===========================================================================================================================
-
-DEBUG_LOCAL BOOL
-IsLocalName( HostsFileInfo * node )
-{
-       BOOL ret = TRUE;
-
-       check( node );
-
-       if ( strstr( node->m_host.h_name, ".local" ) == NULL )
-       {
-               int i;
-
-               for ( i = 0; node->m_host.h_aliases[i]; i++ )
-               {
-                       if ( strstr( node->m_host.h_aliases[i], ".local" ) )
-                       {
-                               goto exit;
-                       }
-               }
-
-               ret = FALSE;
-       }
-
-exit:
-
-       return ret;
-}
-
-
-//===========================================================================================================================
-//     IsSameName
-//===========================================================================================================================
-
-DEBUG_LOCAL BOOL
-IsSameName( HostsFileInfo * node, const char * name )
-{
-       BOOL ret = TRUE;
-
-       check( node );
-       check( name );
-
-       if ( strcmp( node->m_host.h_name, name ) != 0 )
-       {
-               int i;
-
-               for ( i = 0; node->m_host.h_aliases[i]; i++ )
-               {
-                       if ( strcmp( node->m_host.h_aliases[i], name ) == 0 )
-                       {
-                               goto exit;
-                       }
-               }
-
-               ret = FALSE;
-       }
-
-exit:
-
-       return ret;
-}
-
-
-//===========================================================================================================================
-//     HostsFileOpen
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-HostsFileOpen( HostsFile ** self, const char * fname )
-{
-       OSStatus err = kNoErr;
-
-       *self = (HostsFile*) malloc( sizeof( HostsFile ) );
-       require_action( *self, exit, err = kNoMemoryErr );
-       memset( *self, 0, sizeof( HostsFile ) );
-
-       (*self)->m_bufferSize = BUFFER_INITIAL_SIZE;
-       (*self)->m_buffer = (char*) malloc( (*self)->m_bufferSize );
-       require_action( (*self)->m_buffer, exit, err = kNoMemoryErr );
-
-       // check malloc
-
-       (*self)->m_fp = fopen( fname, "r" );
-       require_action( (*self)->m_fp, exit, err = kUnknownErr );
-
-exit:
-
-       if ( err && *self )
-       {
-               HostsFileClose( *self );
-               *self = NULL;
-       }
-               
-       return err;
-}
-
-
-//===========================================================================================================================
-//     HostsFileClose
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-HostsFileClose( HostsFile * self )
-{
-       check( self );
-
-       if ( self->m_buffer )
-       {
-               free( self->m_buffer );
-               self->m_buffer = NULL;
-       }
-
-       if ( self->m_fp )
-       {
-               fclose( self->m_fp );
-               self->m_fp = NULL;
-       }
-
-       free( self );
-
-       return kNoErr;
-} 
-
-
-//===========================================================================================================================
-//     HostsFileInfoFree
-//===========================================================================================================================
-
-DEBUG_LOCAL void
-HostsFileInfoFree( HostsFileInfo * info )
-{
-       while ( info )
-       {
-               HostsFileInfo * next = info->m_next;
-
-               if ( info->m_host.h_addr_list )
-               {
-                       if ( info->m_host.h_addr_list[0] )
-                       {
-                               free( info->m_host.h_addr_list[0] );
-                               info->m_host.h_addr_list[0] = NULL;
-                       }
-
-                       free( info->m_host.h_addr_list );
-                       info->m_host.h_addr_list = NULL;
-               }
-
-               if ( info->m_host.h_aliases )
-               {
-                       int i;
-
-                       for ( i = 0; info->m_host.h_aliases[i]; i++ )
-                       {
-                               free( info->m_host.h_aliases[i] );
-                       }
-
-                       free( info->m_host.h_aliases );
-               }
-
-               if ( info->m_host.h_name )
-               {
-                       free( info->m_host.h_name );
-                       info->m_host.h_name = NULL;
-               }
-                       
-               free( info );
-
-               info = next;
-       }
-}
-
-
-//===========================================================================================================================
-//     HostsFileNext
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-HostsFileNext( HostsFile * self, HostsFileInfo ** hInfo )
-{
-       struct sockaddr_in6     addr_6;
-       struct sockaddr_in      addr_4;
-       int                                     numAliases = ALIASES_INITIAL_SIZE;
-       char                    *       line;
-       char                    *       tok;
-       int                                     dwSize;
-       int                                     idx;
-       int                                     i;
-       short                           family;
-       size_t                          len;
-       OSStatus                        err = kNoErr;
-
-       check( self );
-       check( self->m_fp );
-       check( hInfo );
-
-       idx     = 0;
-
-       *hInfo = (HostsFileInfo*) malloc( sizeof( HostsFileInfo ) );
-       require_action( *hInfo, exit, err = kNoMemoryErr );
-       memset( *hInfo, 0, sizeof( HostsFileInfo ) );
-
-       for ( ; ; )
-       {
-               line = fgets( self->m_buffer + idx, self->m_bufferSize - idx, self->m_fp );
-               
-               if ( line == NULL )
-               {
-                       err = 1;
-                       goto exit;
-               }
-
-               // If there's no eol and no eof, then we didn't get the whole line
-
-               if ( !strchr( line, '\n' ) && !feof( self->m_fp ) )
-               {
-                       int                     bufferSize;
-                       char    *       buffer;
-
-                       /* Try and allocate space for longer line */
-
-                       bufferSize      = self->m_bufferSize * 2;
-                       buffer          = (char*) realloc( self->m_buffer, bufferSize );
-                       require_action( buffer, exit, err = kNoMemoryErr );
-                       self->m_bufferSize      = bufferSize;
-                       self->m_buffer          = buffer;
-                       idx                                     = (int) strlen( self->m_buffer );
-
-                       continue;
-               }
-
-               line    = self->m_buffer;
-               idx             = 0;
-
-               if (*line == '#')
-               {
-                       continue;
-               }
-
-               // Get rid of either comments or eol characters
-
-               if (( tok = strpbrk(line, "#\n")) != NULL )
-               {
-                       *tok = '\0';
-               }
-
-               // Make sure there is some whitespace on this line
-
-               if (( tok = strpbrk(line, " \t")) == NULL )
-               {
-                       continue;
-               }
-
-               // Create two strings, where p == the IP Address and tok is the name list
-
-               *tok++ = '\0';
-
-               while ( *tok == ' ' || *tok == '\t')
-               {
-                       tok++;
-               }
-
-               // Now we have the name
-
-               len = strlen( tok ) + 1;
-               (*hInfo)->m_host.h_name = (char*) malloc( len );
-               require_action( (*hInfo)->m_host.h_name, exit, err = kNoMemoryErr );
-               strcpy_s( (*hInfo)->m_host.h_name, len, tok );
-
-               // Now create the address (IPv6/IPv4)
-
-               addr_6.sin6_family      = family = AF_INET6;
-               dwSize                          = sizeof( addr_6 );
-
-               if ( WSAStringToAddress( line, AF_INET6, NULL, ( struct sockaddr*) &addr_6, &dwSize ) != 0 )
-               {
-                       addr_4.sin_family = family = AF_INET;
-                       dwSize = sizeof( addr_4 );
-
-                       if (WSAStringToAddress( line, AF_INET, NULL, ( struct sockaddr*) &addr_4, &dwSize ) != 0 )
-                       {
-                               continue;
-                       }
-               }
-
-               (*hInfo)->m_host.h_addr_list = (char**) malloc( sizeof( char**) * 2 );
-               require_action( (*hInfo)->m_host.h_addr_list, exit, err = kNoMemoryErr );
-
-               if ( family == AF_INET6 )
-               {
-                       (*hInfo)->m_host.h_length               = (short) sizeof( addr_6.sin6_addr );
-                       (*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
-                       require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
-                       memmove( (*hInfo)->m_host.h_addr_list[0], &addr_6.sin6_addr, sizeof( addr_6.sin6_addr ) );
-                       
-               }
-               else
-               {
-                       (*hInfo)->m_host.h_length               = (short) sizeof( addr_4.sin_addr );
-                       (*hInfo)->m_host.h_addr_list[0] = (char*) malloc( (*hInfo)->m_host.h_length );
-                       require_action( (*hInfo)->m_host.h_addr_list[0], exit, err = kNoMemoryErr );
-                       memmove( (*hInfo)->m_host.h_addr_list[0], &addr_4.sin_addr, sizeof( addr_4.sin_addr ) );
-               }
-
-               (*hInfo)->m_host.h_addr_list[1] = NULL;
-               (*hInfo)->m_host.h_addrtype             = family;
-
-               // Now get the aliases
-
-               if ((tok = strpbrk(tok, " \t")) != NULL)
-               {
-                       *tok++ = '\0';
-               }
-
-               i = 0;
-
-               (*hInfo)->m_host.h_aliases              = (char**) malloc( sizeof(char**) * numAliases );
-               require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
-               (*hInfo)->m_host.h_aliases[0]   = NULL;
-
-               while ( tok && *tok )
-               {
-                       // Skip over the whitespace, waiting for the start of the next alias name
-
-                       if (*tok == ' ' || *tok == '\t')
-                       {
-                               tok++;
-                               continue;
-                       }
-
-                       // Check to make sure we don't exhaust the alias buffer
-
-                       if ( i >= ( numAliases - 1 ) )
-                       {
-                               numAliases = numAliases * 2;
-                               (*hInfo)->m_host.h_aliases = (char**) realloc( (*hInfo)->m_host.h_aliases, numAliases * sizeof( char** ) );
-                               require_action( (*hInfo)->m_host.h_aliases, exit, err = kNoMemoryErr );
-                       }
-
-                       len = strlen( tok ) + 1;
-                       (*hInfo)->m_host.h_aliases[i] = (char*) malloc( len );
-                       require_action( (*hInfo)->m_host.h_aliases[i], exit, err = kNoMemoryErr );
-
-                       strcpy_s( (*hInfo)->m_host.h_aliases[i], len, tok );
-
-                       if (( tok = strpbrk( tok, " \t")) != NULL )
-                       {
-                               *tok++ = '\0';
-                       }
-
-                       (*hInfo)->m_host.h_aliases[++i] = NULL;
-               }
-
-               break;
-       }
-
-exit:
-
-       if ( err && ( *hInfo ) )
-       {
-               HostsFileInfoFree( *hInfo );
-               *hInfo = NULL;
-       }
-
-       return err;
-}
-
-
-#ifdef ENABLE_REVERSE_LOOKUP
-//===========================================================================================================================
-//     IsReverseLookup
-//===========================================================================================================================
-
-DEBUG_LOCAL OSStatus
-IsReverseLookup( LPCWSTR name, size_t size )
-{
-       LPCWSTR         p;
-       OSStatus        err = kNoErr;
-
-       // IPv6LL Reverse-mapping domains are {8,9,A,B}.E.F.ip6.arpa
-       require_action_quiet( size > sizeof_string( ".0.8.e.f.ip6.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
-       p = name + ( size - 1 );
-       p = ( *p == '.' ) ? ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) : ( ( p - sizeof_string( ".0.8.e.f.ip6.arpa" ) ) + 1 );
-       
-       if      ( ( ( p[ 0 ] != '.' )                                                   ||
-               ( ( p[ 1 ] != '0' ) )                                                   ||
-               ( ( p[ 2 ] != '.' ) )                                                   ||
-               ( ( p[ 3 ] != '8' ) )                                                   ||
-               ( ( p[ 4 ] != '.' ) )                                                   ||
-               ( ( p[ 5 ] != 'E' ) && ( p[ 5 ] != 'e' ) )              ||
-               ( ( p[ 6 ] != '.' ) )                                                   ||
-               ( ( p[ 7 ] != 'F' ) && ( p[ 7 ] != 'f' ) )              ||
-               ( ( p[ 8 ] != '.' ) )                                                   ||
-               ( ( p[ 9 ] != 'I' ) && ( p[ 9 ] != 'i' ) )              ||
-               ( ( p[ 10 ] != 'P' ) && ( p[ 10 ] != 'p' ) )    ||      
-               ( ( p[ 11 ] != '6' ) )                                                  ||
-               ( ( p[ 12 ] != '.' ) )                                                  ||
-               ( ( p[ 13 ] != 'A' ) && ( p[ 13 ] != 'a' ) )    ||
-               ( ( p[ 14 ] != 'R' ) && ( p[ 14 ] != 'r' ) )    ||
-               ( ( p[ 15 ] != 'P' ) && ( p[ 15 ] != 'p' ) )    ||
-               ( ( p[ 16 ] != 'A' ) && ( p[ 16 ] != 'a' ) ) ) )
-       {
-               require_action_quiet( size > sizeof_string( ".254.169.in-addr.arpa" ), exit, err = WSASERVICE_NOT_FOUND );
-               p = name + ( size - 1 );
-               p = ( *p == '.' ) ? ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) : ( ( p - sizeof_string( ".254.169.in-addr.arpa" ) ) + 1 );
-       
-               require_action_quiet( ( ( p[ 0 ] == '.' )                                                &&
-                                                               ( ( p[ 1 ] == '2' ) )                                                   &&
-                                                               ( ( p[ 2 ] == '5' ) )                                                   &&
-                                                               ( ( p[ 3 ] == '4' ) )                                                   &&
-                                                               ( ( p[ 4 ] == '.' ) )                                                   &&
-                                                               ( ( p[ 5 ] == '1' ) )                                                   &&
-                                                               ( ( p[ 6 ] == '6' ) )                                                   &&
-                                                               ( ( p[ 7 ] == '9' ) )                                                   &&
-                                                               ( ( p[ 8 ] == '.' ) )                                                   &&
-                                                               ( ( p[ 9 ] == 'I' ) || ( p[ 9 ] == 'i' ) )              &&
-                                                               ( ( p[ 10 ] == 'N' ) || ( p[ 10 ] == 'n' ) )    &&      
-                                                               ( ( p[ 11 ] == '-' ) )                                                  &&
-                                                               ( ( p[ 12 ] == 'A' ) || ( p[ 12 ] == 'a' ) )    &&
-                                                               ( ( p[ 13 ] == 'D' ) || ( p[ 13 ] == 'd' ) )    &&
-                                                               ( ( p[ 14 ] == 'D' ) || ( p[ 14 ] == 'd' ) )    &&
-                                                               ( ( p[ 15 ] == 'R' ) || ( p[ 15 ] == 'r' ) )    &&
-                                                               ( ( p[ 16 ] == '.' ) )                                                  &&
-                                                               ( ( p[ 17 ] == 'A' ) || ( p[ 17 ] == 'a' ) )    &&
-                                                               ( ( p[ 18 ] == 'R' ) || ( p[ 18 ] == 'r' ) )    &&
-                                                               ( ( p[ 19 ] == 'P' ) || ( p[ 19 ] == 'p' ) )    &&
-                                                               ( ( p[ 20 ] == 'A' ) || ( p[ 20 ] == 'a' ) ) ),
-                                                               exit, err = WSASERVICE_NOT_FOUND );
-       }
-
-       // It's a reverse lookup
-
-       check( err == kNoErr );
-
-exit:
-
-       return err;
-}
-#endif
-
-//===========================================================================================================================
-//     GetScopeId
-//===========================================================================================================================
-
-DEBUG_LOCAL DWORD
-GetScopeId( DWORD ifIndex )
-{
-       DWORD                                           err;
-       int                                                     i;
-       DWORD                                           flags;
-       struct ifaddrs *                        head;
-       struct ifaddrs **                       next;
-       IP_ADAPTER_ADDRESSES *          iaaList;
-       ULONG                                           iaaListSize;
-       IP_ADAPTER_ADDRESSES *          iaa;
-       DWORD                                           scopeId = 0;
-       
-       head    = NULL;
-       next    = &head;
-       iaaList = NULL;
-       
-       require( gGetAdaptersAddressesFunctionPtr, exit );
-
-       // Get the list of interfaces. The first call gets the size and the second call gets the actual data.
-       // This loops to handle the case where the interface changes in the window after getting the size, but before the
-       // second call completes. A limit of 100 retries is enforced to prevent infinite loops if something else is wrong.
-       
-       flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME;
-       i = 0;
-       for( ;; )
-       {
-               iaaListSize = 0;
-               err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, NULL, &iaaListSize );
-               check( err == ERROR_BUFFER_OVERFLOW );
-               check( iaaListSize >= sizeof( IP_ADAPTER_ADDRESSES ) );
-               
-               iaaList = (IP_ADAPTER_ADDRESSES *) malloc( iaaListSize );
-               require_action( iaaList, exit, err = ERROR_NOT_ENOUGH_MEMORY );
-               
-               err = gGetAdaptersAddressesFunctionPtr( AF_UNSPEC, flags, NULL, iaaList, &iaaListSize );
-               if( err == ERROR_SUCCESS ) break;
-               
-               free( iaaList );
-               iaaList = NULL;
-               ++i;
-               require( i < 100, exit );
-               dlog( kDebugLevelWarning, "%s: retrying GetAdaptersAddresses after %d failure(s) (%d %m)\n", __ROUTINE__, i, err, err );
-       }
-       
-       for( iaa = iaaList; iaa; iaa = iaa->Next )
-       {
-               DWORD ipv6IfIndex;
-
-               if ( iaa->IfIndex > 0xFFFFFF )
-               {
-                       continue;
-               }
-               if ( iaa->Ipv6IfIndex > 0xFF )
-               {
-                       continue;
-               }
-
-               // For IPv4 interfaces, there seems to be a bug in iphlpapi.dll that causes the 
-               // following code to crash when iterating through the prefix list.  This seems
-               // to occur when iaa->Ipv6IfIndex != 0 when IPv6 is not installed on the host.
-               // This shouldn't happen according to Microsoft docs which states:
-               //
-               //     "Ipv6IfIndex contains 0 if IPv6 is not available on the interface."
-               //
-               // So the data structure seems to be corrupted when we return from
-               // GetAdaptersAddresses(). The bug seems to occur when iaa->Length <
-               // sizeof(IP_ADAPTER_ADDRESSES), so when that happens, we'll manually
-               // modify iaa to have the correct values.
-
-               if ( iaa->Length >= sizeof( IP_ADAPTER_ADDRESSES ) )
-               {
-                       ipv6IfIndex = iaa->Ipv6IfIndex;
-               }
-               else
-               {
-                       ipv6IfIndex     = 0;
-               }
-
-               // Skip psuedo and tunnel interfaces.
-               
-               if( ( ipv6IfIndex == 1 ) || ( iaa->IfType == IF_TYPE_TUNNEL ) )
-               {
-                       continue;
-               }
-
-               if ( iaa->IfIndex == ifIndex )
-               {
-                       scopeId = iaa->Ipv6IfIndex;
-                       break;
-               }
-       } 
-
-exit:
-
-       if( iaaList )
-       {
-               free( iaaList );
-       }
-
-       return scopeId;
-}
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.def b/mDNSWindows/mdnsNSP/mdnsNSP.def
deleted file mode 100644 (file)
index 822213d..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-; -*- tab-width: 4 -*-
-;
-; Copyright (c) 2003-2004 Apple Computer, Inc. All rights reserved.
-;
-; Licensed under the Apache License, Version 2.0 (the "License");
-; you may not use this file except in compliance with the License.
-; You may obtain a copy of the License at
-; 
-;     http://www.apache.org/licenses/LICENSE-2.0
-; 
-; Unless required by applicable law or agreed to in writing, software
-; distributed under the License is distributed on an "AS IS" BASIS,
-; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-; See the License for the specific language governing permissions and
-; limitations under the License.
-;
-
-LIBRARY                mdnsNSP
-
-EXPORTS
-       NSPStartup
-       NSPCleanup
-       DllRegisterServer       PRIVATE
-       DllUnregisterServer     PRIVATE
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.rc b/mDNSWindows/mdnsNSP/mdnsNSP.rc
deleted file mode 100644 (file)
index c090f0c..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-// Microsoft Visual C++ generated resource script.
-//
-#include "resource.h"
-
-#define APSTUDIO_READONLY_SYMBOLS
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 2 resource.
-//
-#include "afxres.h"
-#include "WinVersRes.h"
-
-/////////////////////////////////////////////////////////////////////////////
-#undef APSTUDIO_READONLY_SYMBOLS
-
-/////////////////////////////////////////////////////////////////////////////
-// English (U.S.) resources
-
-#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
-#ifdef _WIN32
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-#pragma code_page(1252)
-#endif //_WIN32
-
-#ifdef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// TEXTINCLUDE
-//
-
-1 TEXTINCLUDE 
-BEGIN
-    "resource.h\0"
-END
-
-2 TEXTINCLUDE 
-BEGIN
-    "#include ""afxres.h""\r\n"
-    "#include ""WinVersRes.h""\r\n"
-    "\0"
-END
-
-3 TEXTINCLUDE 
-BEGIN
-    "\r\n"
-    "\0"
-END
-
-#endif    // APSTUDIO_INVOKED
-
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Version
-//
-
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION MASTER_PROD_VERS
- PRODUCTVERSION MASTER_PROD_VERS
- FILEFLAGSMASK 0x17L
-#ifdef _DEBUG
- FILEFLAGS 0x1L
-#else
- FILEFLAGS 0x0L
-#endif
- FILEOS 0x4L
- FILETYPE 0x2L
- FILESUBTYPE 0x0L
-BEGIN
-    BLOCK "StringFileInfo"
-    BEGIN
-        BLOCK "040904b0"
-        BEGIN
-            VALUE "CompanyName", MASTER_COMPANY_NAME
-            VALUE "FileDescription", "Bonjour Namespace Provider"
-            VALUE "FileVersion", MASTER_PROD_VERS_STR
-            VALUE "InternalName", "mdnsNSP.dll"
-            VALUE "LegalCopyright", MASTER_LEGAL_COPYRIGHT
-            VALUE "OriginalFilename", "mdnsNSP.dll"
-            VALUE "ProductName", MASTER_PROD_NAME
-            VALUE "ProductVersion", MASTER_PROD_VERS_STR
-        END
-    END
-    BLOCK "VarFileInfo"
-    BEGIN
-        VALUE "Translation", 0x409, 1200
-    END
-END
-
-#endif    // English (U.S.) resources
-/////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef APSTUDIO_INVOKED
-/////////////////////////////////////////////////////////////////////////////
-//
-// Generated from the TEXTINCLUDE 3 resource.
-//
-
-
-/////////////////////////////////////////////////////////////////////////////
-#endif    // not APSTUDIO_INVOKED
-
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.vcproj b/mDNSWindows/mdnsNSP/mdnsNSP.vcproj
deleted file mode 100644 (file)
index 1d6f563..0000000
+++ /dev/null
@@ -1,457 +0,0 @@
-<?xml version="1.0" encoding="Windows-1252"?>\r
-<VisualStudioProject\r
-       ProjectType="Visual C++"\r
-       Version="8.00"\r
-       Name="mdnsNSP"\r
-       ProjectGUID="{F4F15529-F0EB-402F-8662-73C5797EE557}"\r
-       Keyword="Win32Proj"\r
-       >\r
-       <Platforms>\r
-               <Platform\r
-                       Name="Win32"\r
-               />\r
-               <Platform\r
-                       Name="x64"\r
-               />\r
-       </Platforms>\r
-       <ToolFiles>\r
-       </ToolFiles>\r
-       <Configurations>\r
-               <Configuration\r
-                       Name="Debug|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
-                               OutputFile="$(OutDir)/mdnsNSP.dll"\r
-                               LinkIncremental="2"\r
-                               ModuleDefinitionFile="mdnsNSP.def"\r
-                               DelayLoadDLLs="dnssd.dll"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"\r
-                               SubSystem="2"\r
-                               BaseAddress="0x64000000"\r
-                               ImportLibrary="$(OutDir)/mdnsNSP.lib"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Debug|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               Optimization="0"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="3"\r
-                               SmallerTypeCheck="true"\r
-                               RuntimeLibrary="1"\r
-                               BufferSecurityCheck="true"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
-                               OutputFile="$(OutDir)/mdnsNSP.dll"\r
-                               LinkIncremental="2"\r
-                               ModuleDefinitionFile="mdnsNSP.def"\r
-                               DelayLoadDLLs="dnssd.dll"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(OutDir)/mdnsNSP.pdb"\r
-                               SubSystem="2"\r
-                               BaseAddress="0x64000000"\r
-                               ImportLibrary="$(OutDir)/mdnsNSP.lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|Win32"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="0"\r
-                               SmallerTypeCheck="false"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE /SAFESEH"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
-                               OutputFile="$(OutDir)/mdnsNSP.dll"\r
-                               LinkIncremental="1"\r
-                               ModuleDefinitionFile="mdnsNSP.def"\r
-                               DelayLoadDLLs="dnssd.dll"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               BaseAddress="0x64000000"\r
-                               ImportLibrary="$(IntDir)/mdnsNSP.lib"\r
-                               TargetMachine="1"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-               <Configuration\r
-                       Name="Release|x64"\r
-                       OutputDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"\r
-                       ConfigurationType="2"\r
-                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
-                       CharacterSet="2"\r
-                       >\r
-                       <Tool\r
-                               Name="VCPreBuildEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCustomBuildTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXMLDataGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebServiceProxyGeneratorTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCMIDLTool"\r
-                               TargetEnvironment="3"\r
-                       />\r
-                       <Tool\r
-                               Name="VCCLCompilerTool"\r
-                               AdditionalIncludeDirectories=".;../;../../mDNSShared;../../Clients"\r
-                               PreprocessorDefinitions="WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1"\r
-                               StringPooling="true"\r
-                               MinimalRebuild="true"\r
-                               ExceptionHandling="0"\r
-                               BasicRuntimeChecks="0"\r
-                               SmallerTypeCheck="false"\r
-                               RuntimeLibrary="0"\r
-                               UsePrecompiledHeader="0"\r
-                               AssemblerListingLocation="$(IntDir)\"\r
-                               WarningLevel="4"\r
-                               Detect64BitPortabilityProblems="true"\r
-                               DebugInformationFormat="3"\r
-                               CallingConvention="2"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManagedResourceCompilerTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCResourceCompilerTool"\r
-                               AdditionalIncludeDirectories="../"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPreLinkEventTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCLinkerTool"\r
-                               AdditionalOptions="/NXCOMPAT /DYNAMICBASE"\r
-                               AdditionalDependencies="../DLL/$(PlatformName)/$(ConfigurationName)/dnssd.lib ws2_32.lib iphlpapi.lib shlwapi.lib"\r
-                               OutputFile="$(OutDir)/mdnsNSP.dll"\r
-                               LinkIncremental="1"\r
-                               ModuleDefinitionFile="mdnsNSP.def"\r
-                               DelayLoadDLLs="dnssd.dll"\r
-                               GenerateDebugInformation="true"\r
-                               ProgramDatabaseFile="$(IntDir)/$(ProjectName).pdb"\r
-                               SubSystem="2"\r
-                               OptimizeReferences="0"\r
-                               EnableCOMDATFolding="0"\r
-                               BaseAddress="0x64000000"\r
-                               ImportLibrary="$(IntDir)/mdnsNSP.lib"\r
-                               TargetMachine="17"\r
-                       />\r
-                       <Tool\r
-                               Name="VCALinkTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCManifestTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCXDCMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCBscMakeTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCFxCopTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCAppVerifierTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCWebDeploymentTool"\r
-                       />\r
-                       <Tool\r
-                               Name="VCPostBuildEventTool"\r
-                               CommandLine="if not &quot;%RC_XBS%&quot; == &quot;YES&quot; goto END&#x0D;&#x0A;if not exist &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;   mkdir &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;xcopy /I/Y &quot;$(TargetPath)&quot;                                                                  &quot;$(DSTROOT)\Program Files\Bonjour\$(PlatformName)&quot;&#x0D;&#x0A;:END&#x0D;&#x0A;"\r
-                       />\r
-               </Configuration>\r
-       </Configurations>\r
-       <References>\r
-       </References>\r
-       <Files>\r
-               <Filter\r
-                       Name="Source Files"\r
-                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
-                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\Clients\ClientCommon.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\mdnsNSP.c"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\mdnsNSP.def"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Header Files"\r
-                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
-                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
-                       >\r
-                       <File\r
-                               RelativePath="..\..\Clients\ClientCommon.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\CommonServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\mDNSShared\DebugServices.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath="..\..\..\mDNSShared\dns_sd.h"\r
-                               >\r
-                       </File>\r
-                       <File\r
-                               RelativePath=".\resource.h"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-               <Filter\r
-                       Name="Resource Files"\r
-                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
-                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
-                       >\r
-                       <File\r
-                               RelativePath=".\mdnsNSP.rc"\r
-                               >\r
-                       </File>\r
-               </Filter>\r
-       </Files>\r
-       <Globals>\r
-       </Globals>\r
-</VisualStudioProject>\r
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.vcxproj b/mDNSWindows/mdnsNSP/mdnsNSP.vcxproj
deleted file mode 100755 (executable)
index 71b2b98..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup Label="ProjectConfigurations">\r
-    <ProjectConfiguration Include="Debug|Win32">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Debug|x64">\r
-      <Configuration>Debug</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|Win32">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>Win32</Platform>\r
-    </ProjectConfiguration>\r
-    <ProjectConfiguration Include="Release|x64">\r
-      <Configuration>Release</Configuration>\r
-      <Platform>x64</Platform>\r
-    </ProjectConfiguration>\r
-  </ItemGroup>\r
-  <PropertyGroup Label="Globals">\r
-    <ProjectGuid>{F4F15529-F0EB-402F-8662-73C5797EE557}</ProjectGuid>\r
-    <Keyword>Win32Proj</Keyword>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">\r
-    <ConfigurationType>DynamicLibrary</ConfigurationType>\r
-    <CharacterSet>MultiByte</CharacterSet>\r
-  </PropertyGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />\r
-  <ImportGroup Label="ExtensionSettings">\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">\r
-    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />\r
-    <Import Project="$(VCTargetsPath)Microsoft.CPP.UpgradeFromVC71.props" />\r
-  </ImportGroup>\r
-  <PropertyGroup Label="UserMacros" />\r
-  <PropertyGroup>\r
-    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>\r
-    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>\r
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>\r
-    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>\r
-  </PropertyGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
-      <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
-      <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)mdnsNSP.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <BaseAddress>0x64000000</BaseAddress>\r
-      <ImportLibrary>$(OutDir)mdnsNSP.lib</ImportLibrary>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <Optimization>Disabled</Optimization>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NSP_EXPORTS;DEBUG;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>true</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\r
-      <BufferSecurityCheck>true</BufferSecurityCheck>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
-      <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
-      <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(OutDir)mdnsNSP.pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <BaseAddress>0x64000000</BaseAddress>\r
-      <ImportLibrary>$(OutDir)mdnsNSP.lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>false</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE /SAFESEH %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
-      <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
-      <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <BaseAddress>0x64000000</BaseAddress>\r
-      <ImportLibrary>$(IntDir)mdnsNSP.lib</ImportLibrary>\r
-      <TargetMachine>MachineX86</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)"   mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                  "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">\r
-    <Midl>\r
-      <TargetEnvironment>X64</TargetEnvironment>\r
-    </Midl>\r
-    <ClCompile>\r
-      <AdditionalIncludeDirectories>.;../;../../mDNSShared;../../Clients;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-      <PreprocessorDefinitions>WIN32;_WINDOWS;_USRDLL;NSP_EXPORTS;WIN32_LEAN_AND_MEAN;_CRT_SECURE_NO_DEPRECATE;_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>\r
-      <StringPooling>true</StringPooling>\r
-      <MinimalRebuild>true</MinimalRebuild>\r
-      <ExceptionHandling>\r
-      </ExceptionHandling>\r
-      <BasicRuntimeChecks>Default</BasicRuntimeChecks>\r
-      <SmallerTypeCheck>false</SmallerTypeCheck>\r
-      <RuntimeLibrary>MultiThreaded</RuntimeLibrary>\r
-      <PrecompiledHeader>\r
-      </PrecompiledHeader>\r
-      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\r
-      <WarningLevel>Level4</WarningLevel>\r
-      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\r
-      <CallingConvention>StdCall</CallingConvention>\r
-    </ClCompile>\r
-    <ResourceCompile>\r
-      <AdditionalIncludeDirectories>../;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\r
-    </ResourceCompile>\r
-    <Link>\r
-      <AdditionalOptions>/NXCOMPAT /DYNAMICBASE %(AdditionalOptions)</AdditionalOptions>\r
-      <AdditionalDependencies>../DLL/$(Platform)/$(Configuration)/dnssd.lib;ws2_32.lib;iphlpapi.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>\r
-      <OutputFile>$(OutDir)mdnsNSP.dll</OutputFile>\r
-      <ModuleDefinitionFile>mdnsNSP.def</ModuleDefinitionFile>\r
-      <DelayLoadDLLs>dnssd.dll;%(DelayLoadDLLs)</DelayLoadDLLs>\r
-      <GenerateDebugInformation>true</GenerateDebugInformation>\r
-      <ProgramDatabaseFile>$(IntDir)$(ProjectName).pdb</ProgramDatabaseFile>\r
-      <SubSystem>Windows</SubSystem>\r
-      <OptimizeReferences>\r
-      </OptimizeReferences>\r
-      <EnableCOMDATFolding>\r
-      </EnableCOMDATFolding>\r
-      <BaseAddress>0x64000000</BaseAddress>\r
-      <ImportLibrary>$(IntDir)mdnsNSP.lib</ImportLibrary>\r
-      <TargetMachine>MachineX64</TargetMachine>\r
-    </Link>\r
-    <PostBuildEvent>\r
-      <Command>if not "%RC_XBS%" == "YES" goto END\r
-if not exist "$(DSTROOT)\Program Files\Bonjour\$(Platform)"   mkdir "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-xcopy /I/Y "$(TargetPath)"                                                                  "$(DSTROOT)\Program Files\Bonjour\$(Platform)"\r
-:END\r
-</Command>\r
-    </PostBuildEvent>\r
-  </ItemDefinitionGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\Clients\ClientCommon.c" />\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c" />\r
-    <ClCompile Include="mdnsNSP.c" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="mdnsNSP.def" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\Clients\ClientCommon.h" />\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h" />\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h" />\r
-    <ClInclude Include="..\..\..\mDNSShared\dns_sd.h" />\r
-    <ClInclude Include="resource.h" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="mdnsNSP.rc" />\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ProjectReference Include="..\DLL\dnssd.vcxproj">\r
-      <Project>{ab581101-18f0-46f6-b56a-83a6b1ea657e}</Project>\r
-      <ReferenceOutputAssembly>false</ReferenceOutputAssembly>\r
-    </ProjectReference>\r
-  </ItemGroup>\r
-  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
-  <ImportGroup Label="ExtensionTargets">\r
-  </ImportGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/mdnsNSP/mdnsNSP.vcxproj.filters b/mDNSWindows/mdnsNSP/mdnsNSP.vcxproj.filters
deleted file mode 100755 (executable)
index f09d07a..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>\r
-<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
-  <ItemGroup>\r
-    <Filter Include="Source Files">\r
-      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\r
-      <Extensions>cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\r
-    </Filter>\r
-    <Filter Include="Header Files">\r
-      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\r
-      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>\r
-    </Filter>\r
-    <Filter Include="Resource Files">\r
-      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\r
-      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx</Extensions>\r
-    </Filter>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClCompile Include="..\..\Clients\ClientCommon.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="..\..\mDNSShared\DebugServices.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-    <ClCompile Include="mdnsNSP.c">\r
-      <Filter>Source Files</Filter>\r
-    </ClCompile>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <None Include="mdnsNSP.def">\r
-      <Filter>Source Files</Filter>\r
-    </None>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ClInclude Include="..\..\Clients\ClientCommon.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\CommonServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\mDNSShared\DebugServices.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="..\..\..\mDNSShared\dns_sd.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-    <ClInclude Include="resource.h">\r
-      <Filter>Header Files</Filter>\r
-    </ClInclude>\r
-  </ItemGroup>\r
-  <ItemGroup>\r
-    <ResourceCompile Include="mdnsNSP.rc">\r
-      <Filter>Resource Files</Filter>\r
-    </ResourceCompile>\r
-  </ItemGroup>\r
-</Project>
\ No newline at end of file
diff --git a/mDNSWindows/mdnsNSP/resource.h b/mDNSWindows/mdnsNSP/resource.h
deleted file mode 100644 (file)
index 818f083..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//{{NO_DEPENDENCIES}}
-// Microsoft Visual C++ generated include file.
-// Used by mdnsNSP.rc
-//
-#define IDS_PROJNAME                    100
-#define IDR_WMDMLOGGER                  101
-#define IDS_LOG_SEV_INFO                201
-#define IDS_LOG_SEV_WARN                202
-#define IDS_LOG_SEV_ERROR               203
-#define IDS_LOG_DATETIME                204
-#define IDS_LOG_SRCNAME                 205
-#define IDS_DEF_LOGFILE                 301
-#define IDS_DEF_MAXSIZE                 302
-#define IDS_DEF_SHRINKTOSIZE            303
-#define IDS_DEF_LOGENABLED              304
-#define IDS_MUTEX_TIMEOUT               401
-
-// Next default values for new objects
-// 
-#ifdef APSTUDIO_INVOKED
-#ifndef APSTUDIO_READONLY_SYMBOLS
-#define _APS_NEXT_RESOURCE_VALUE        201
-#define _APS_NEXT_COMMAND_VALUE         32768
-#define _APS_NEXT_CONTROL_VALUE         201
-#define _APS_NEXT_SYMED_VALUE           101
-#endif
-#endif
diff --git a/unittests/CNameRecordTests.c b/unittests/CNameRecordTests.c
deleted file mode 100644 (file)
index bb23c07..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-#include "CNameRecordTests.h"
-#include "unittest_common.h"
-
-mDNSlocal int InitThisUnitTest(void);
-mDNSlocal int StartClientQueryRequest(void);
-mDNSlocal int PopulateCacheWithClientResponseRecords(void);
-mDNSlocal int SimulateNetworkChangeAndVerifyTest(void);
-mDNSlocal int FinalizeUnitTest(void);
-mDNSlocal mStatus AddDNSServer(void);
-
-// This unit test's variables
-static UDPSocket* local_socket;
-static request_state* client_request_message;
-
-struct UDPSocket_struct
-{
-       mDNSIPPort port; // MUST BE FIRST FIELD -- mDNSCoreReceive expects every UDPSocket_struct to begin with mDNSIPPort port
-};
-typedef struct UDPSocket_struct UDPSocket;
-
-// This client request was generated using the following command: "dns-sd -Q 123server.dotbennu.com. A".
-uint8_t query_client_msgbuf[35] = {
-       0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x73, 0x65, 0x72, 0x76, 0x65,
-       0x72, 0x2e, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x00,
-       0x01, 0x00, 0x01
-};
-
-// This uDNS message is a canned response that was originally captured by wireshark.
-uint8_t query_response_msgbuf[108] = {
-    0x69, 0x41, // transaction id
-       0x85, 0x80, // flags
-       0x00, 0x01, // 1 question for 123server.dotbennu.com. Addr
-       0x00, 0x02,     // 2 anwsers: 123server.dotbennu.com. CNAME test212.dotbennu.com., test212.dotbennu.com. Addr 10.100.0.1,
-       0x00, 0x01,     // 1 authorities anwser: dotbennu.com. NS cardinal2.apple.com.
-       0x00, 0x00, 0x09, 0x31, 0x32, 0x33,
-    0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x08, 0x64, 0x6f, 0x74, 0x62, 0x65, 0x6e, 0x6e, 0x75, 0x03,
-    0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
-    0x02, 0x56, 0x00, 0x0a, 0x07, 0x74, 0x65, 0x73, 0x74, 0x32, 0x31, 0x32, 0xc0, 0x16, 0xc0, 0x34,
-    0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x04, 0x0a, 0x64, 0x00, 0x01, 0xc0, 0x16,
-    0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x51, 0x80, 0x00, 0x12, 0x09, 0x63, 0x61, 0x72, 0x64, 0x69,
-    0x6e, 0x61, 0x6c, 0x32, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x65, 0xc0, 0x1f
-};
-
-// Variables associated with contents of the above uDNS message
-#define uDNS_TargetQID 16745
-char udns_original_domainname_cstr[] = "123server.dotbennu.com.";
-char udns_cname_domainname_cstr[] = "test212.dotbennu.com.";
-static const mDNSv4Addr dns_response_ipv4 = {{ 10, 100, 0, 1 }};
-
-UNITTEST_HEADER(CNameRecordTests)
-       UNITTEST_TEST(InitThisUnitTest)
-       UNITTEST_TEST(StartClientQueryRequest)
-    UNITTEST_TEST(PopulateCacheWithClientResponseRecords)
-    UNITTEST_TEST(SimulateNetworkChangeAndVerifyTest)
-    UNITTEST_TEST(FinalizeUnitTest)
-UNITTEST_FOOTER
-
-// The InitThisUnitTest() initializes the mDNSResponder environment as well as
-// a DNSServer. It also allocates memory for a local_socket and client request.
-// Note: This unit test does not send packets on the wire and it does not open sockets.
-UNITTEST_HEADER(InitThisUnitTest)
-       // Init unit test environment and verify no error occurred.
-       mStatus result = init_mdns_environment(mDNStrue);
-       UNITTEST_ASSERT(result == mStatus_NoError);
-
-       // Add one DNS server and verify it was added.
-       AddDNSServer();
-       UNITTEST_ASSERT(NumUnicastDNSServers == 1);
-
-       // Create memory for a socket that is never used or opened.
-       local_socket = mDNSPlatformMemAllocate(sizeof(UDPSocket));
-       mDNSPlatformMemZero(local_socket, sizeof(UDPSocket));
-
-       // Create memory for a request that is used to make this unit test's client request.
-       client_request_message = calloc(1, sizeof(request_state));
-UNITTEST_FOOTER
-
-// This test simulates a uds client request by setting up a client request and then
-// calling mDNSResponder's handle_client_request.  The handle_client_request function
-// processes the request and starts a query.  This unit test verifies
-// the client request and query were setup as expected.  This unit test also calls
-// mDNS_execute which determines the cache does not contain the new question's
-// answer.
-UNITTEST_HEADER(StartClientQueryRequest)
-    mDNS *const m = &mDNSStorage;
-    request_state* req = client_request_message;
-       char *msgptr = (char *)query_client_msgbuf;
-       size_t msgsz = sizeof(query_client_msgbuf);
-       mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
-    DNSQuestion *q;
-    mStatus err = mStatus_NoError;
-       char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-
-    // Process the unit test's client request
-       start_client_request(req, msgptr, msgsz, query_request, local_socket);
-    UNITTEST_ASSERT(err == mStatus_NoError);
-
-       // Verify the request fields were set as expected
-       UNITTEST_ASSERT(req->next == mDNSNULL);
-       UNITTEST_ASSERT(req->primary == mDNSNULL);
-       UNITTEST_ASSERT(req->sd == client_req_sd);
-       UNITTEST_ASSERT(req->process_id == client_req_process_id);
-       UNITTEST_ASSERT(!strcmp(req->pid_name, client_req_pid_name));
-       UNITTEST_ASSERT(req->validUUID == mDNSfalse);
-       UNITTEST_ASSERT(req->errsd == 0);
-       UNITTEST_ASSERT(req->uid == client_req_uid);
-       UNITTEST_ASSERT(req->ts == t_complete);
-       UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
-       UNITTEST_ASSERT(req->msgend == msgptr+msgsz);
-       UNITTEST_ASSERT(req->msgbuf == mDNSNULL);
-    UNITTEST_ASSERT(req->hdr.version == VERSION);
-    UNITTEST_ASSERT(req->replies == mDNSNULL);
-    UNITTEST_ASSERT(req->terminate != mDNSNULL);
-       UNITTEST_ASSERT(req->flags == kDNSServiceFlagsReturnIntermediates);
-    UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexAny);
-
-       // Verify the query fields were set as expected
-       q = &req->u.queryrecord.q;
-    UNITTEST_ASSERT(q != mDNSNULL);
-    UNITTEST_ASSERT(q == m->Questions);
-    UNITTEST_ASSERT(q == m->NewQuestions);
-    UNITTEST_ASSERT(q->SuppressUnusable == mDNSfalse);
-    UNITTEST_ASSERT(q->ReturnIntermed == mDNStrue);
-    UNITTEST_ASSERT(q->SuppressQuery == mDNSfalse);
-
-       UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
-       ConvertDomainNameToCString(&q->qname, qname_cstr);
-       UNITTEST_ASSERT(!strcmp(qname_cstr, udns_original_domainname_cstr));
-       UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
-
-       UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_Any);
-    UNITTEST_ASSERT(q->flags == req->flags);
-    UNITTEST_ASSERT(q->qtype == 1);
-    UNITTEST_ASSERT(q->qclass == 1);
-    UNITTEST_ASSERT(q->LongLived == 0);
-    UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
-    UNITTEST_ASSERT(q->ForceMCast == 0);
-    UNITTEST_ASSERT(q->TimeoutQuestion == 0);
-    UNITTEST_ASSERT(q->WakeOnResolve == 0);
-    UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
-    UNITTEST_ASSERT(q->ValidationRequired == 0);
-    UNITTEST_ASSERT(q->ValidatingResponse == 0);
-    UNITTEST_ASSERT(q->ProxyQuestion == 0);
-    UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
-    UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
-    UNITTEST_ASSERT(q->QuestionContext == req);
-    UNITTEST_ASSERT(q->SearchListIndex == 0);
-    UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
-    UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
-    UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
-    UNITTEST_ASSERT(q->AppendSearchDomains == 0);
-    UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
-    UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
-
-    // Call mDNS_Execute to see if the new question, q, has an answer in the cache.
-       // It won't be yet because the cache is empty.
-       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-    mDNS_Execute(m);
-
-    // Verify mDNS_Execute processed the new question.
-       UNITTEST_ASSERT(m->NewQuestions == mDNSNULL);
-
-       // Verify the cache is empty and the request got no reply.
-       UNITTEST_ASSERT(m->rrcache_totalused == 0);
-    UNITTEST_ASSERT(req->replies == mDNSNULL);
-
-UNITTEST_FOOTER
-
-// This unit test receives a canned uDNS response message by calling the mDNSCoreReceive() function.
-// It then verifies cache entries were added for the CNAME and A records that were contained in the
-// answers of the canned response, query_response_msgbuf.  This unit test also verifies that
-// 2 add events were generated for the client.
-UNITTEST_HEADER(PopulateCacheWithClientResponseRecords)
-    mDNS *const m = &mDNSStorage;
-       DNSMessage *msgptr = (DNSMessage *)query_response_msgbuf;
-       size_t msgsz = sizeof(query_response_msgbuf);
-    struct reply_state *reply;
-    request_state* req = client_request_message;
-    DNSQuestion *q = &req->u.queryrecord.q;
-    const char *data;
-       const char *end;
-    char name[kDNSServiceMaxDomainName];
-    uint16_t rrtype, rrclass, rdlen;
-    const char *rdata;
-    size_t len;
-    char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-
-       // Receive and populate the cache with canned response
-    receive_response(req, msgptr, msgsz);
-
-    // Verify 2 cache entries for CName and A record are present
-    mDNSu32 CacheUsed =0, notUsed =0;
-    LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
-    UNITTEST_ASSERT(CacheUsed == m->rrcache_totalused);
-    UNITTEST_ASSERT(CacheUsed  == 4); // 2 for the CacheGroup object plus 2 for the A and CNAME records
-    UNITTEST_ASSERT(m->PktNum  == 1); // one packet was received
-
-       // Verify question's qname is now set with the A record's domainname
-       UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
-       ConvertDomainNameToCString(&q->qname, domainname_cstr);
-       UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
-       UNITTEST_ASSERT(!strcmp(domainname_cstr, udns_cname_domainname_cstr));
-
-       // Verify client's add event for CNAME is properly formed
-    reply = req->replies;
-    UNITTEST_ASSERT(reply != mDNSNULL);
-    UNITTEST_ASSERT(reply->next == mDNSNULL);
-
-    data    = (char *)&reply->rhdr[1];
-    end     = data+reply->totallen;
-    get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
-    rrtype  = get_uint16(&data, end);
-    rrclass = get_uint16(&data, end);
-    rdlen   = get_uint16(&data, end);
-    rdata   = get_rdata(&data, end, rdlen);
-       len     = get_reply_len(name, rdlen);
-
-    UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
-    UNITTEST_ASSERT(reply->mhdr->version == VERSION);
-    UNITTEST_ASSERT(reply->mhdr->datalen == len);
-    UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
-    UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
-    UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
-    UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
-    UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
-    UNITTEST_ASSERT(rrtype == kDNSType_CNAME);
-    UNITTEST_ASSERT(rrclass == kDNSClass_IN);
-    ConvertDomainNameToCString((const domainname *const)rdata, domainname_cstr);
-    UNITTEST_ASSERT(!strcmp(domainname_cstr, "test212.dotbennu.com."));
-
-    // The mDNS_Execute call generates an add event for the A record
-    m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-    mDNS_Execute(m);
-
-    // Verify the client's reply contains a properly formed add event for the A record.
-    reply = req->replies;
-    UNITTEST_ASSERT(reply != mDNSNULL);
-    UNITTEST_ASSERT(reply->next != mDNSNULL);
-    reply = reply->next;
-
-    data    = (char *)&reply->rhdr[1];
-    end     = data+reply->totallen;
-    get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
-    rrtype  = get_uint16(&data, end);
-    rrclass = get_uint16(&data, end);
-    rdlen   = get_uint16(&data, end);
-    rdata   = get_rdata(&data, end, rdlen);
-       len     = get_reply_len(name, rdlen);
-
-    UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
-    UNITTEST_ASSERT(reply->mhdr->version == VERSION);
-    UNITTEST_ASSERT(reply->mhdr->datalen == len);
-
-    UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
-    UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
-    UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
-    UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
-    UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
-    UNITTEST_ASSERT(rrtype == kDNSType_A);
-    UNITTEST_ASSERT(rrclass == kDNSClass_IN);
-       UNITTEST_ASSERT(rdata[0] == dns_response_ipv4.b[0]);
-       UNITTEST_ASSERT(rdata[1] == dns_response_ipv4.b[1]);
-       UNITTEST_ASSERT(rdata[2] == dns_response_ipv4.b[2]);
-       UNITTEST_ASSERT(rdata[3] == dns_response_ipv4.b[3]);
-
-UNITTEST_FOOTER
-
-// This function verifies the cache and event handling occurred as expected when a network change happened.
-// The uDNS_SetupDNSConfig is called to simulate a network change and two outcomes occur. First the A record
-// query is restarted and sent to a new DNS server. Second the cache records are purged. Then mDNS_Execute
-// is called and it removes the purged cache records and generates a remove event for the A record.
-// The following are verified:
-//     1.) The restart of query for A record.
-//     2.) The cache is empty after mDNS_Execute removes the cache entres.
-//  3.) The remove event is verified by examining the request's reply data.
-UNITTEST_HEADER(SimulateNetworkChangeAndVerifyTest)
-    mDNS *const m = &mDNSStorage;
-    request_state*  req = client_request_message;
-    DNSQuestion*    q = &req->u.queryrecord.q;
-    mDNSu32 CacheUsed =0, notUsed =0;
-    const char *data;  const char *end;
-    char name[kDNSServiceMaxDomainName];
-    uint16_t rrtype, rrclass, rdlen;
-    const char *rdata;
-    size_t len;
-
-    // The uDNS_SetupDNSConfig reconfigures the resolvers so the A record query is restarted and
-    // both the CNAME and A record are purged.
-    uDNS_SetupDNSConfig(m);
-
-    // Verify the A record query was restarted.  This is done indirectly by noticing the transaction id and interval have changed.
-    UNITTEST_ASSERT(q->ThisQInterval == InitialQuestionInterval);
-    UNITTEST_ASSERT(q->TargetQID.NotAnInteger != uDNS_TargetQID);
-
-    // Then mDNS_Execute removes both records from the cache and calls the client back with a remove event for A record.
-    m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-    mDNS_Execute(m);
-
-    // Verify the cache entries are removed
-    LogCacheRecords_ut(mDNS_TimeNow(m), &CacheUsed, &notUsed);
-    UNITTEST_ASSERT(CacheUsed == m->rrcache_totalused);
-    UNITTEST_ASSERT(CacheUsed == 0);
-
-    // Verify the A record's remove event is setup as expected in the reply data
-    struct reply_state *reply;
-    reply = req->replies;
-    UNITTEST_ASSERT(reply != mDNSNULL);
-
-    UNITTEST_ASSERT(reply != mDNSNULL);
-    UNITTEST_ASSERT(reply->next != mDNSNULL);
-    UNITTEST_ASSERT(reply->next->next != mDNSNULL);
-
-    reply = reply->next->next; // Get to last event to verify remove event
-    data    = (char *)&reply->rhdr[1];
-    end     = data+reply->totallen;
-    get_string(&data, data+reply->totallen, name, kDNSServiceMaxDomainName);
-    rrtype  = get_uint16(&data, end);
-    rrclass = get_uint16(&data, end);
-    rdlen   = get_uint16(&data, end);
-    rdata   = get_rdata(&data, end, rdlen);
-       len     = get_reply_len(name, rdlen);
-
-    UNITTEST_ASSERT(reply->totallen == reply->mhdr->datalen + sizeof(ipc_msg_hdr));
-    UNITTEST_ASSERT(reply->mhdr->version == VERSION);
-    UNITTEST_ASSERT(reply->mhdr->datalen == len);
-    UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
-    UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
-    UNITTEST_ASSERT(reply->rhdr->flags != htonl(kDNSServiceFlagsAdd));
-    UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexAny);
-    UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
-    UNITTEST_ASSERT(rrtype == kDNSType_A);
-    UNITTEST_ASSERT(rrclass == kDNSClass_IN);
-       UNITTEST_ASSERT(rdata[0] == dns_response_ipv4.b[0]);
-       UNITTEST_ASSERT(rdata[1] == dns_response_ipv4.b[1]);
-       UNITTEST_ASSERT(rdata[2] == dns_response_ipv4.b[2]);
-       UNITTEST_ASSERT(rdata[3] == dns_response_ipv4.b[3]);
-
-UNITTEST_FOOTER
-
-// This function does memory cleanup and no verification.
-UNITTEST_HEADER(FinalizeUnitTest)
-    mDNS *m = &mDNSStorage;
-    request_state* req = client_request_message;
-    DNSServer   *ptr, **p = &m->DNSServers;
-
-    while (req->replies)
-    {
-        reply_state *reply = req->replies;
-        req->replies = req->replies->next;
-               mDNSPlatformMemFree(reply);
-    }
-    mDNSPlatformMemFree(req);
-
-    mDNSPlatformMemFree(local_socket);
-
-    while (*p)
-    {
-        ptr = *p;
-        *p = (*p)->next;
-        LogInfo("FinalizeUnitTest: Deleting server %p %#a:%d (%##s)", ptr, &ptr->addr, mDNSVal16(ptr->port), ptr->domain.c);
-        mDNSPlatformMemFree(ptr);
-    }
-UNITTEST_FOOTER
-
-// The mDNS_AddDNSServer function adds a dns server to mDNSResponder's list.
-mDNSlocal mStatus AddDNSServer(void)
-{
-    mDNS *m = &mDNSStorage;
-    m->timenow = 0;
-    mDNS_Lock(m);
-    domainname d;
-    mDNSAddr   addr;
-    mDNSIPPort port;
-    mDNSs32            serviceID               = 0;
-    mDNSu32            scoped                  = 0;
-    mDNSu32            timeout                 = dns_server_timeout;
-    mDNSBool   cellIntf                = 0;
-    mDNSBool   isExpensive             = 0;
-    mDNSBool   isCLAT46                = mDNSfalse;
-    mDNSu16            resGroupID              = dns_server_resGroupID;
-    mDNSBool   reqA                    = mDNStrue;
-    mDNSBool   reqAAAA                 = mDNStrue;
-    mDNSBool   reqDO                   = mDNSfalse;
-    d.c[0]                                             = 0;
-    addr.type                                  = mDNSAddrType_IPv4;
-    addr.ip.v4.NotAnInteger            = dns_server_ipv4.NotAnInteger;
-    port.NotAnInteger                  = client_resp_src_port;
-       mDNS_AddDNSServer(m, &d, primary_interfaceID, serviceID, &addr, port, scoped, timeout,
-                      cellIntf, isExpensive, isCLAT46, resGroupID,
-                                         reqA, reqAAAA, reqDO);
-       mDNS_Unlock(m);
-       return mStatus_NoError;
-}
-
-
diff --git a/unittests/CNameRecordTests.h b/unittests/CNameRecordTests.h
deleted file mode 100644 (file)
index 2c2a3a1..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#ifndef ReconfirmRecordTests_h
-#define ReconfirmRecordTests_h
-
-#include "unittest.h"
-
-int  CNameRecordTests(void);
-
-#endif /* ReconfirmRecordTests_h */
diff --git a/unittests/DNSMessageTest.c b/unittests/DNSMessageTest.c
deleted file mode 100644 (file)
index fedfed3..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "mDNSEmbeddedAPI.h"
-#include "DNSMessageTest.h"
-#include "../mDNSCore/DNSCommon.h"
-
-int SizeTest(void);
-int InitializeTest(void);
-int PutDomainNameAsLabels(void);
-int PutRData(void);
-int Finalize(void);
-
-
-DNSMessage *msg;
-
-
-UNITTEST_HEADER(DNSMessageTest)
-    UNITTEST_TEST(SizeTest)
-    UNITTEST_TEST(InitializeTest)
-    UNITTEST_TEST(Finalize)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(SizeTest)
-    msg = (DNSMessage *)malloc (sizeof(DNSMessage));
-    UNITTEST_ASSERT_RETURN(msg != NULL);
-
-    // message header should be 12 bytes
-    UNITTEST_ASSERT(sizeof(msg->h) == 12);
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(InitializeTest)
-    // Initialize the message
-    InitializeDNSMessage(&msg->h, onesID, QueryFlags);
-
-    // Check that the message is initialized properly
-    UNITTEST_ASSERT(msg->h.numAdditionals  == 0);
-    UNITTEST_ASSERT(msg->h.numAnswers      == 0);
-    UNITTEST_ASSERT(msg->h.numQuestions    == 0);
-    UNITTEST_ASSERT(msg->h.numAuthorities  == 0);
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(PutDomainNameAsLabels)
-
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(Finalize)
-    UNITTEST_ASSERT_RETURN(msg != NULL)
-    free(msg);
-UNITTEST_FOOTER
\ No newline at end of file
diff --git a/unittests/DNSMessageTest.h b/unittests/DNSMessageTest.h
deleted file mode 100644 (file)
index 147175f..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef DNSMessageTest_h
-#define DNSMessageTest_h
-
-#include "unittest.h"
-
-int DNSMessageTest(void);
-
-#endif /* DNSMessageTest_h */
\ No newline at end of file
diff --git a/unittests/DomainNameTest.c b/unittests/DomainNameTest.c
deleted file mode 100644 (file)
index 571725a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "DomainNameTest.h"
-#include "mDNSEmbeddedAPI.h"
-#include "../mDNSCore/DNSCommon.h"
-
-int SameDomainNameTest(void);
-int SameDomainLabelTest(void);
-int LocalDomainTest(void);
-
-
-UNITTEST_HEADER(DomainNameTest)
-    UNITTEST_TEST(SameDomainLabelTest)
-    UNITTEST_TEST(SameDomainNameTest)
-    UNITTEST_TEST(LocalDomainTest)
-UNITTEST_FOOTER
-
-
-
-
-UNITTEST_HEADER(SameDomainLabelTest)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(SameDomainNameTest)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(LocalDomainTest)
-UNITTEST_FOOTER
\ No newline at end of file
diff --git a/unittests/DomainNameTest.h b/unittests/DomainNameTest.h
deleted file mode 100644 (file)
index 1c429c2..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef DomainNameTest_h
-#define DomainNameTest_h
-
-#include "unittest.h"
-int DomainNameTest(void);
-
-#endif /* DomainNameTest_h */
diff --git a/unittests/InterfaceTest.c b/unittests/InterfaceTest.c
deleted file mode 100644 (file)
index a973814..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "InterfaceTest.h"
-#include "mDNSEmbeddedAPI.h"
-
-
-NetworkInterfaceInfo *intf;
-mDNS *m;
-
-int LocalSubnetTest(void);
-
-UNITTEST_HEADER(InterfaceTest)
-    UNITTEST_TEST(LocalSubnetTest)
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(LocalSubnetTest)
-    // need a way to initialize m before we call into the class of APIs that use a ptr to mDNS
-    // should that pointer be common to all tests?
-    // mDNS_AddressIsLocalSubnet(mDNS *const m, const mDNSInterfaceID InterfaceID, const mDNSAddr *addr)
-    // TEST_ASSERT_RETURN (for IPv4/IPv6 local subnet)
-UNITTEST_FOOTER
diff --git a/unittests/InterfaceTest.h b/unittests/InterfaceTest.h
deleted file mode 100644 (file)
index f94b3da..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#ifndef InterfaceTest_h
-#define InterfaceTest_h
-
-#include "unittest.h"
-
-int InterfaceTest(void);
-
-#endif /* InterfaceTest_h */
diff --git a/unittests/LocalOnlyTimeoutTests.c b/unittests/LocalOnlyTimeoutTests.c
deleted file mode 100644 (file)
index e295948..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-#include "LocalOnlyTimeoutTests.h"
-#include "unittest_common.h"
-
-mDNSlocal int InitUnitTest(void);
-mDNSlocal int StartLocalOnlyClientQueryRequest(void);
-mDNSlocal int PopulateCacheWithClientLOResponseRecords(void);
-mDNSlocal int RestartLocalOnlyClientQueryRequest(void);
-mDNSlocal int FinalizeUnitTest(void);
-mDNSlocal mStatus InitEtcHostsRecords();
-
-// This unit test's variables
-static request_state* client_request_message;
-static UDPSocket* local_socket;
-static char domainname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-
-// This query request message was generated from the following command: "dns-sd -lo -timeout -Q cardinal2.apple.com. A"
-char query_req_msgbuf[33]= {
-       0x00, 0x01, 0x90, 0x00,
-       // DNSServiceFlags.L = (kDNSServiceFlagsReturnIntermediates |kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsTimeout)
-       0xff, 0xff, 0xff, 0xff,
-       // interfaceIndex = mDNSInterface_LocalOnly
-       0x63, 0x61, 0x72, 0x64, 0x69, 0x6e, 0x61, 0x6c,
-       0x32, 0x2e, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x00, 0x00, 0x01, 0x00,
-       0x01
-};
-
-UNITTEST_HEADER(LocalOnlyTimeoutTests)
-       UNITTEST_TEST(InitUnitTest)
-       UNITTEST_TEST(StartLocalOnlyClientQueryRequest)
-       UNITTEST_TEST(PopulateCacheWithClientLOResponseRecords)
-       UNITTEST_TEST(RestartLocalOnlyClientQueryRequest)
-       UNITTEST_TEST(FinalizeUnitTest)
-UNITTEST_FOOTER
-
-// The InitUnitTest() initializes a minimal mDNSResponder environment as
-// well as allocates memory for a local_socket and client request.
-// It also sets the domainname_cstr specified in the client's query request.
-// Note: This unit test does not send packets on the wire and it does not open sockets.
-UNITTEST_HEADER(InitUnitTest)
-
-       // Init mDNSStorage
-       mStatus result = init_mdns_storage();
-       if (result != mStatus_NoError)
-               return result;
-
-       // Allocate a client request
-       local_socket = calloc(1, sizeof(request_state));
-
-       // Allocate memory for a request that is used to make client requests.
-       client_request_message = calloc(1, sizeof(request_state));
-
-       // Init domainname that is used by unit tests
-       strlcpy(domainname_cstr, "cardinal2.apple.com.", sizeof(domainname_cstr));
-
-UNITTEST_FOOTER
-
-// This unit test starts a local only request for "cardinal2.apple.com.".  It first
-// calls start_client_request to start a query, it then verifies the
-// req and query data structures are set as expected. Next, the cache is verified to
-// be empty by AnswerNewLocalOnlyQuestion() and so results in GenerateNegativeResponse()
-// getting called which sets up a reply with a negative answer in it for the client.
-// On return from mDNS_Execute, the client's reply structure is verified to be set as
-// expected. Lastly the timeout is simulated and mDNS_Execute is called. This results
-// in a call to TimeoutQuestions(). And again, the GenerateNegativeResponse() is called
-// which returns a negative response to the client.  This time the client reply is verified
-// to be setup with a timeout result.
-UNITTEST_HEADER(StartLocalOnlyClientQueryRequest)
-
-       mDNS *const m = &mDNSStorage;
-    request_state* req = client_request_message;
-       char *msgptr = (char *)query_req_msgbuf;
-       size_t msgsz = sizeof(query_req_msgbuf);
-       DNSQuestion *q;
-       mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
-       mStatus err = mStatus_NoError;
-       char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-       struct reply_state *reply;
-       size_t len;
-
-       // Process the unit test's client request
-       start_client_request(req, msgptr, msgsz, query_request, local_socket);
-       UNITTEST_ASSERT(err == mStatus_NoError);
-
-       // Verify the query initialized and request fields were set as expected
-       UNITTEST_ASSERT(err == mStatus_NoError);
-       UNITTEST_ASSERT(req->hdr.version == VERSION);
-       UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
-       UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
-       UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
-       UNITTEST_ASSERT(req->terminate != mDNSNULL);
-
-       q = &req->u.queryrecord.q;
-       UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
-       UNITTEST_ASSERT(m->Questions == NULL);
-       UNITTEST_ASSERT(m->NewQuestions == NULL);
-       UNITTEST_ASSERT(q->SuppressUnusable == 1);
-       UNITTEST_ASSERT(q->ReturnIntermed == 1);
-       UNITTEST_ASSERT(q->SuppressQuery == 0);                                                                 // Regress <rdar://problem/27571734>
-
-       UNITTEST_ASSERT(q->qnameOrig == mDNSNULL);
-       ConvertDomainNameToCString(&q->qname, qname_cstr);
-       UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
-       UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
-
-       UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
-       UNITTEST_ASSERT(q->flags == req->flags);
-       UNITTEST_ASSERT(q->qtype == 1);
-       UNITTEST_ASSERT(q->qclass == 1);
-       UNITTEST_ASSERT(q->LongLived == 0);
-       UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
-       UNITTEST_ASSERT(q->ForceMCast == 0);
-       UNITTEST_ASSERT(q->TimeoutQuestion == 1);
-       UNITTEST_ASSERT(q->WakeOnResolve == 0);
-       UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
-       UNITTEST_ASSERT(q->ValidationRequired == 0);
-       UNITTEST_ASSERT(q->ValidatingResponse == 0);
-       UNITTEST_ASSERT(q->ProxyQuestion == 0);
-       UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
-       UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
-       UNITTEST_ASSERT(q->QuestionContext == req);
-       UNITTEST_ASSERT(q->SearchListIndex == 0);
-       UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
-       UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
-       UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
-       UNITTEST_ASSERT(q->StopTime != 0);
-       UNITTEST_ASSERT(q->AppendSearchDomains == 0);
-       UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
-       UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
-
-       // At this point the the cache is empty. Calling mDNS_Execute will answer the local-only
-       // question with a negative response.
-       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-       mDNS_Execute(m);  // Regress <rdar://problem/28721294>
-
-       // Verify reply is a negative response and error code is set to kDNSServiceErr_NoSuchRecord error.
-       reply = req->replies;
-       UNITTEST_ASSERT(reply != mDNSNULL);
-
-       UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
-       UNITTEST_ASSERT(q->LOAddressAnswers == 0);
-
-       len = get_reply_len(qname_cstr, 0);
-
-       UNITTEST_ASSERT(reply->next == mDNSNULL);
-       UNITTEST_ASSERT(reply->totallen == reply->mhdr->datalen + sizeof(ipc_msg_hdr));
-       UNITTEST_ASSERT(reply->mhdr->version == VERSION);
-       UNITTEST_ASSERT(reply->mhdr->datalen == len);
-       UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
-       UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-
-       UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
-       UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly);        // Regress <rdar://problem/27340874>
-       UNITTEST_ASSERT(reply->rhdr->error ==
-                                       (DNSServiceErrorType)htonl(kDNSServiceErr_NoSuchRecord));       // Regress <rdar://problem/24827555>
-
-       // Simulate what udsserver_idle normally does for clean up
-       freeL("StartLocalOnlyClientQueryRequest:reply", reply);
-       req->replies = NULL;
-
-       // Simulate the query time out of the local-only question.
-       // The expected behavior is a negative answer with time out error
-       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-       q->StopTime = mDNS_TimeNow_NoLock(m);
-       m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
-       mDNS_Execute(m);
-
-       // Verify the reply is a negative response with timeout error.
-       reply = req->replies;
-       UNITTEST_ASSERT(reply != NULL);
-       UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
-       UNITTEST_ASSERT(q->LOAddressAnswers == 0);
-
-       len = get_reply_len(qname_cstr, 0);
-
-       UNITTEST_ASSERT(reply->next == mDNSNULL);
-       UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
-       UNITTEST_ASSERT(reply->mhdr->version == VERSION);
-       UNITTEST_ASSERT(reply->mhdr->datalen == len);
-       UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
-       UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-       UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
-       UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly);        // Regress <rdar://problem/27340874>
-       UNITTEST_ASSERT(reply->rhdr->error ==
-                                       (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout));            // Regress <rdar://problem/27562965>
-
-       // Free request and reallocate to use when query is restarted
-       free_req(req);
-       client_request_message = calloc(1, sizeof(request_state));
-
-UNITTEST_FOOTER
-
-// This unit test populates the cache with four /etc/hosts records and then
-// verifies there are four entries in the cache.
-UNITTEST_HEADER(PopulateCacheWithClientLOResponseRecords)
-
-       mDNS *const m = &mDNSStorage;
-
-       // Verify cache is empty
-       int count = LogEtcHosts_ut(m);
-       UNITTEST_ASSERT(count == 0);
-
-       // Populate /etc/hosts
-       mStatus result = InitEtcHostsRecords();
-       UNITTEST_ASSERT(result == mStatus_NoError);
-
-       // mDNS_Execute is called to populate the /etc/hosts cache.
-       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-       mDNS_Execute(m);
-
-       count = LogEtcHosts_ut(m);
-       UNITTEST_ASSERT(count == 4);
-
-UNITTEST_FOOTER
-
-// This unit test starts a local only request for "cardinal2.apple.com.".  It first
-// calls start_client_request to start a query, it then verifies the
-// req and query data structures are set as expected. Next, the cache is verified to
-// contain the answer by AnswerNewLocalOnlyQuestion() and so results in setting up an
-// answer reply to the client. On return from mDNS_Execute, the client's reply structure
-// is verified to be set as expected. Lastly the timeout is simulated and mDNS_Execute is
-// called. This results in a call to TimeoutQuestions(). And this time, the
-// GenerateNegativeResponse() is called which returns a negative response to the client
-// which specifies the timeout occurred. Again, the answer reply is verified to
-// to specify a timeout.
-UNITTEST_HEADER(RestartLocalOnlyClientQueryRequest)
-
-       mDNS *const m = &mDNSStorage;
-       request_state* req = client_request_message;
-       char *msgptr = (char *)query_req_msgbuf;
-       size_t msgsz = sizeof(query_req_msgbuf);        DNSQuestion *q;
-       mDNSs32 min_size = sizeof(DNSServiceFlags) + sizeof(mDNSu32) + 4;
-       mStatus err = mStatus_NoError;
-       char qname_cstr[MAX_ESCAPED_DOMAIN_NAME];
-       struct reply_state *reply;
-       size_t len;
-
-       // Process the unit test's client request
-       start_client_request(req, msgptr, msgsz, query_request, local_socket);
-       UNITTEST_ASSERT(err == mStatus_NoError);
-
-       UNITTEST_ASSERT(err == mStatus_NoError);
-       UNITTEST_ASSERT(req->hdr.version == VERSION);
-       UNITTEST_ASSERT((mDNSs32)req->data_bytes > min_size);
-       UNITTEST_ASSERT(req->flags == (kDNSServiceFlagsSuppressUnusable | kDNSServiceFlagsReturnIntermediates | kDNSServiceFlagsTimeout));
-       UNITTEST_ASSERT(req->interfaceIndex == kDNSServiceInterfaceIndexLocalOnly);
-       UNITTEST_ASSERT(req->terminate != mDNSNULL);
-       UNITTEST_ASSERT(m->Questions == NULL);
-
-       q = &req->u.queryrecord.q;
-       UNITTEST_ASSERT(q == m->NewLocalOnlyQuestions);
-       UNITTEST_ASSERT(q->SuppressUnusable == 1);
-       UNITTEST_ASSERT(q->ReturnIntermed == 1);
-       UNITTEST_ASSERT(q->SuppressQuery == 0);                                                                         // Regress <rdar://problem/27571734>
-       UNITTEST_ASSERT(q->qnamehash == DomainNameHashValue(&q->qname));
-       UNITTEST_ASSERT(q->InterfaceID == mDNSInterface_LocalOnly);
-       UNITTEST_ASSERT(q->flags == req->flags);
-       UNITTEST_ASSERT(q->qtype == 1);
-       UNITTEST_ASSERT(q->qclass == 1);
-       UNITTEST_ASSERT(q->LongLived == 0);
-       UNITTEST_ASSERT(q->ExpectUnique == mDNSfalse);
-       UNITTEST_ASSERT(q->ForceMCast == 0);
-       UNITTEST_ASSERT(q->TimeoutQuestion == 1);
-       UNITTEST_ASSERT(q->WakeOnResolve == 0);
-       UNITTEST_ASSERT(q->UseBackgroundTrafficClass == 0);
-       UNITTEST_ASSERT(q->ValidationRequired == 0);
-       UNITTEST_ASSERT(q->ValidatingResponse == 0);
-       UNITTEST_ASSERT(q->ProxyQuestion == 0);
-       UNITTEST_ASSERT(q->AnonInfo == mDNSNULL);
-       UNITTEST_ASSERT(q->QuestionCallback != mDNSNULL);
-       UNITTEST_ASSERT(q->QuestionContext == req);
-       UNITTEST_ASSERT(q->SearchListIndex == 0);
-       UNITTEST_ASSERT(q->DNSSECAuthInfo == mDNSNULL);
-       UNITTEST_ASSERT(q->DAIFreeCallback == mDNSNULL);
-       UNITTEST_ASSERT(q->RetryWithSearchDomains == 0);
-       UNITTEST_ASSERT(q->StopTime != 0);
-       UNITTEST_ASSERT(q->AppendSearchDomains == 0);
-       UNITTEST_ASSERT(q->AppendLocalSearchDomains == 0);
-       UNITTEST_ASSERT(q->DuplicateOf == mDNSNULL);
-       ConvertDomainNameToCString(&q->qname, qname_cstr);
-       UNITTEST_ASSERT(!strcmp(qname_cstr, domainname_cstr));
-
-       // Answer local-only question with found cache entry
-       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-       mDNS_Execute(m);                                                                                                                        // Regress <rdar://problem/28721294>
-       UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
-       UNITTEST_ASSERT(req->u.queryrecord.ans == 1);
-       UNITTEST_ASSERT(q->LOAddressAnswers == 1);
-       UNITTEST_ASSERT(q == m->LocalOnlyQuestions);
-
-       reply = req->replies;
-       len = get_reply_len(qname_cstr, 4);
-
-       UNITTEST_ASSERT(reply->next == mDNSNULL);
-       UNITTEST_ASSERT(reply->totallen == len + sizeof(ipc_msg_hdr));
-       UNITTEST_ASSERT(reply->mhdr->version == VERSION);
-       UNITTEST_ASSERT(reply->mhdr->datalen == len);
-       UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
-       UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-       UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
-       UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly);        // Regress <rdar://problem/27340874>
-       UNITTEST_ASSERT(reply->rhdr->error == kDNSServiceErr_NoError);
-
-       // Simulate the query time out of the local-only question.
-       // The expected behavior is a negative answer with time out error
-       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-       q->StopTime = mDNS_TimeNow_NoLock(m);
-       m->NextScheduledStopTime -= mDNSPlatformOneSecond*5;
-       mDNS_Execute(m);
-
-       reply = req->replies->next;
-       UNITTEST_ASSERT(reply != NULL);
-       UNITTEST_ASSERT(reply->next == NULL);
-       UNITTEST_ASSERT(m->NewLocalOnlyQuestions == NULL);
-       UNITTEST_ASSERT(q->LOAddressAnswers == 0);
-       len = get_reply_len(qname_cstr, 0);
-
-       UNITTEST_ASSERT(reply->next == mDNSNULL);
-       UNITTEST_ASSERT(reply->totallen == len + + sizeof(ipc_msg_hdr));
-       UNITTEST_ASSERT(reply->mhdr->version == VERSION);
-       UNITTEST_ASSERT(reply->mhdr->datalen == len);
-       UNITTEST_ASSERT(reply->mhdr->ipc_flags == 0);
-       UNITTEST_ASSERT(reply->mhdr->op == query_reply_op);
-       UNITTEST_ASSERT(reply->rhdr->flags == htonl(kDNSServiceFlagsAdd));
-       UNITTEST_ASSERT(reply->rhdr->ifi == kDNSServiceInterfaceIndexLocalOnly);        // Regress <rdar://problem/27340874>
-       UNITTEST_ASSERT(reply->rhdr->error ==
-                                       (DNSServiceErrorType)htonl(kDNSServiceErr_Timeout));            // Regress <rdar://problem/27562965>
-
-       free_req(req);
-UNITTEST_FOOTER
-
-// This function does memory cleanup and no verification.
-UNITTEST_HEADER(FinalizeUnitTest)
-       mDNSPlatformMemFree(local_socket);
-UNITTEST_FOOTER
-
-mDNSlocal mStatus InitEtcHostsRecords(void)
-{
-       mDNS *m = &mDNSStorage;
-       struct sockaddr_storage hostaddr;
-
-       AuthHash newhosts;
-       mDNSPlatformMemZero(&newhosts, sizeof(AuthHash));
-
-       memset(&hostaddr, 0, sizeof(hostaddr));
-       get_ip("127.0.0.1", &hostaddr);
-
-       domainname domain;
-       MakeDomainNameFromDNSNameString(&domain, "localhost");
-
-       mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
-
-       memset(&hostaddr, 0, sizeof(hostaddr));
-       get_ip("0000:0000:0000:0000:0000:0000:0000:0001", &hostaddr);
-
-       MakeDomainNameFromDNSNameString(&domain, "localhost");
-
-       mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
-
-       memset(&hostaddr, 0, sizeof(hostaddr));
-       get_ip("255.255.255.255", &hostaddr);
-
-       MakeDomainNameFromDNSNameString(&domain, "broadcasthost");
-
-       mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
-
-       memset(&hostaddr, 0, sizeof(hostaddr));
-       get_ip("17.226.40.200", &hostaddr);
-
-       MakeDomainNameFromDNSNameString(&domain, "cardinal2.apple.com");
-
-       mDNSMacOSXCreateEtcHostsEntry_ut(&domain, (struct sockaddr *) &hostaddr, mDNSNULL, mDNSNULL, &newhosts);
-       UpdateEtcHosts_ut(&newhosts);
-
-       m->NextScheduledEvent = mDNS_TimeNow_NoLock(m);
-       mDNS_Execute(m);
-
-       return mStatus_NoError;
-}
diff --git a/unittests/LocalOnlyTimeoutTests.h b/unittests/LocalOnlyTimeoutTests.h
deleted file mode 100644 (file)
index 3ff5608..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#ifndef LocalOnlyTimeoutTests_h
-#define LocalOnlyTimeoutTests_h
-
-#include "unittest.h"
-
-int LocalOnlyTimeoutTests(void);
-
-#endif /* LocalOnlyTimeoutTests_h */
diff --git a/unittests/ResourceRecordTest.c b/unittests/ResourceRecordTest.c
deleted file mode 100644 (file)
index 3c976c3..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#include "mDNSEmbeddedAPI.h"
-#include "../mDNSCore/DNSCommon.h"
-#include "ResourceRecordTest.h"
-
-int TXTSetupTest(void);
-int ASetupTest(void);
-int OPTSetupTest(void);
-
-
-UNITTEST_HEADER(ResourceRecordTest)
-    UNITTEST_TEST(TXTSetupTest)
-    UNITTEST_TEST(ASetupTest)
-    UNITTEST_TEST(OPTSetupTest)
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(TXTSetupTest)
-
-    AuthRecord authRec;
-    mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_TXT, kStandardTTL, kDNSRecordTypeShared, AuthRecordAny,mDNSNULL, mDNSNULL);
-   // This fails >> UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_TXT);
-    UNITTEST_ASSERT_RETURN(authRec.resrec.rdata->MaxRDLength == sizeof(RDataBody));
-
-    // Retest with a RDataStorage set to a a buffer
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(ASetupTest)
-    AuthRecord authRec;
-    mDNS_SetupResourceRecord(&authRec, mDNSNULL, mDNSInterface_Any, kDNSType_A, kHostNameTTL, kDNSRecordTypeUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
-
-    // This fails >> UNITTEST_ASSERT_RETURN(authRec.resrec.RecordType == kDNSType_A);
-    // Add more verifications
-
-UNITTEST_FOOTER
-
-
-UNITTEST_HEADER(OPTSetupTest)
-    AuthRecord opt;
-    mDNSu32    updatelease = 7200;
-/*  mDNSu8     data[AbsoluteMaxDNSMessageData];
-    mDNSu8     *p = data;
-    mDNSu16    numAdditionals;
-*/
-    // Setup the OPT Record
-    mDNS_SetupResourceRecord(&opt, mDNSNULL, mDNSInterface_Any, kDNSType_OPT, kStandardTTL, kDNSRecordTypeKnownUnique, AuthRecordAny, mDNSNULL, mDNSNULL);
-
-    // Verify the basic initialization is all ok
-
-    opt.resrec.rrclass    = NormalMaxDNSMessageData;
-    opt.resrec.rdlength   = sizeof(rdataOPT);   // One option in this OPT record
-    opt.resrec.rdestimate = sizeof(rdataOPT);
-    opt.resrec.rdata->u.opt[0].opt           = kDNSOpt_Lease;
-    opt.resrec.rdata->u.opt[0].u.updatelease = updatelease;
-
-    // Put the resource record in and verify everything is fine
-    // p = PutResourceRecordTTLWithLimit(&data, p, &numAdditionals, &opt.resrec, opt.resrec.rroriginalttl, data + AbsoluteMaxDNSMessageData);
-
-
-    // Repeat with bad data to make sure it bails out cleanly
-UNITTEST_FOOTER
\ No newline at end of file
diff --git a/unittests/ResourceRecordTest.h b/unittests/ResourceRecordTest.h
deleted file mode 100644 (file)
index d762d01..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-#ifndef ResourceRecordTest_h
-#define ResourceRecordTest_h
-
-#include "unittest.h"
-
-int ResourceRecordTest(void);
-
-#endif /* ResourceRecordTest_h */
index 526b351371ac89c44df6ec75c4468ec297bfb28d..dbe29f8a86a5f9dbf7e4b89ab0f0332a6144b5a1 100644 (file)
@@ -1,4 +1,5 @@
 #include "DNSCommon.h"
+#include "unittest_common.h"
 
 mDNSexport void init_logging_ut(void)
 {
diff --git a/unittests/mDNSCoreReceiveTest.c b/unittests/mDNSCoreReceiveTest.c
deleted file mode 100644 (file)
index 856eb4e..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#include "mDNSCoreReceiveTest.h"
-#include "unittest_common.h"
-
-int InitmDNSCoreReceiveTest(void);
-int ValidQueryReqTest(void);
-int NullDstQueryReqTest(void);
-void InitmDNSStorage(mDNS *const m);
-
-// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
-uint8_t udns_query_request_message[28] = {                     // contains 1 question for www.f5.com
-       0x31, 0xca, // transaction id
-       0x01, 0x00,     // flags
-       0x00, 0x01,     // 1 question
-       0x00, 0x00,     // no anwsers
-       0x00, 0x00,     // no authoritative answers
-       0x00, 0x00, // no additionals
-       0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
-};
-
-// This DNS message was gleaned from a uDNS query request packet that was captured with Wireshark.
-// Then the header id (more specifically, the msg->h.id) was deliberately cleared to force code
-// path to traverse regression case, <rdar://problem/28556513>.
-uint8_t udns_query_request_message_with_invalid_id[28] = {  // contains 1 question for www.f5.com, msg->h.id = 0
-       0x00, 0x00,     // transaction id
-       0x01, 0x00, // flags
-       0x00, 0x01, // 1 question
-       0x00, 0x00, // no anwsers
-       0x00, 0x00, // no authoritative answers
-       0x00, 0x00, // no additionals
-       0x03, 0x77, 0x77, 0x77, 0x02, 0x66, 0x35, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01
-};
-
-uint8_t arp_request_packet[28] = {  // contains 1 question for www.f5.com, msg->h.id = 0
-    0x00, 0x01, // hardware type: enet
-    0x08, 0x00, // protocol type: IP
-    0x06, // hardware size
-    0x04, // Protcol size
-    0x00, 0x01, // opcode request
-    0x24, 0x01, 0xc7, 0x24, 0x35, 0x00, // Sender mac addr
-    0x11, 0xe2, 0x14, 0x01,    // Sender ip addr
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00,        // target mac addr
-    0x11, 0xe2, 0x17, 0xbe     // target ip addr
-};
-UNITTEST_HEADER(mDNSCoreReceiveTest)
-    UNITTEST_TEST(InitmDNSCoreReceiveTest)
-    UNITTEST_TEST(ValidQueryReqTest)
-    UNITTEST_TEST(NullDstQueryReqTest)
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(InitmDNSCoreReceiveTest)
-       mDNSPlatformTimeInit();
-       init_logging_ut();
-       mDNS_LoggingEnabled = 0;
-       mDNS_PacketLoggingEnabled = 0;
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(ValidQueryReqTest)
-       mDNS *const m = &mDNSStorage;
-       mDNSAddr srcaddr, dstaddr;
-       mDNSIPPort srcport, dstport;
-       DNSMessage * msg;
-       const mDNSu8 * end;
-
-    // Init unit test environment and verify no error occurred.
-    mStatus result = init_mdns_environment(mDNStrue);
-    UNITTEST_ASSERT(result == mStatus_NoError);
-
-       // Used random values for srcaddr and srcport
-       srcaddr.type       = mDNSAddrType_IPv4;
-       srcaddr.ip.v4.b[0] = 192;
-       srcaddr.ip.v4.b[1] = 168;
-       srcaddr.ip.v4.b[2] = 1;
-       srcaddr.ip.v4.b[3] = 10;
-       srcport.NotAnInteger = swap16((mDNSu16)53);
-
-       // Used random values for dstaddr and dstport
-       dstaddr.type       = mDNSAddrType_IPv4;
-       dstaddr.ip.v4.b[0] = 192;
-       dstaddr.ip.v4.b[1] = 168;
-       dstaddr.ip.v4.b[2] = 1;
-       dstaddr.ip.v4.b[3] = 20;
-       dstport.NotAnInteger = swap16((mDNSu16)49339);
-
-       // Set message to a DNS message (copied from a WireShark packet)
-       msg = (DNSMessage *)udns_query_request_message;
-       end = udns_query_request_message + sizeof(udns_query_request_message);
-
-       // Execute mDNSCoreReceive using a valid DNS message
-       mDNSCoreReceive(m, msg, end, &srcaddr, srcport, &dstaddr, dstport, if_nametoindex("en0"));
-
-       // Verify that mDNSCoreReceiveQuery traversed the normal code path
-       UNITTEST_ASSERT(m->mDNSStats.NormalQueries == 1);
-
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(NullDstQueryReqTest)
-
-       mDNS *const m = &mDNSStorage;
-       mDNSAddr srcaddr;
-       mDNSIPPort srcport, dstport;
-       DNSMessage * msg;
-       const mDNSu8 * end;
-
-       // This test case does not require setup of interfaces, the record's cache, or pending questions
-       // so m is initialized to all zeros.
-       InitmDNSStorage(m);
-
-       // Used random values for srcaddr and srcport
-       srcaddr.type       = mDNSAddrType_IPv4;
-       srcaddr.ip.v4.b[0] = 192;
-       srcaddr.ip.v4.b[1] = 168;
-       srcaddr.ip.v4.b[2] = 1;
-       srcaddr.ip.v4.b[3] = 10;
-       srcport.NotAnInteger = swap16((mDNSu16)53);
-
-       // Used random value for dstport
-       dstport.NotAnInteger = swap16((mDNSu16)49339);
-
-       // Set message to a DNS message (copied from a WireShark packet)
-       msg = (DNSMessage *)udns_query_request_message_with_invalid_id;
-       end = udns_query_request_message_with_invalid_id + sizeof(udns_query_request_message_with_invalid_id);
-
-       // Execute mDNSCoreReceive to regress <rdar://problem/28556513>
-       mDNSCoreReceive(m, msg, end, &srcaddr, srcport, NULL, dstport, if_nametoindex("en0"));
-
-       // Verify that mDNSCoreReceiveQuery was NOT traversed through the normal code path
-       UNITTEST_ASSERT(m->mDNSStats.NormalQueries == 0);
-
-       // Verify code path that previously crashed, in <rdar://problem/28556513>, now traverses successfully
-       // by checking a counter that was incremented on code path that crashed.
-       UNITTEST_ASSERT(m->MPktNum == 1);
-
-UNITTEST_FOOTER
-
-void InitmDNSStorage(mDNS *const m)
-{
-       memset(m, 0, sizeof(mDNS));
-}
-
diff --git a/unittests/mDNSCoreReceiveTest.h b/unittests/mDNSCoreReceiveTest.h
deleted file mode 100644 (file)
index 7c7274e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-
-#ifndef mDNSCoreReceiveTest_h
-#define mDNSCoreReceiveTest_h
-
-#include "unittest.h"
-
-int mDNSCoreReceiveTest(void);
-
-#endif /* mDNSCoreReceiveTest_h */
diff --git a/unittests/main.c b/unittests/main.c
deleted file mode 100644 (file)
index 9b30ab4..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 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.
- */
-
-
-#include "unittest.h"
-#include "DNSMessageTest.h"
-#include "ResourceRecordTest.h"
-#include "mDNSCoreReceiveTest.h"
-#include "CNameRecordTests.h"
-#include "LocalOnlyTimeoutTests.h"
-
-const char *HWVersionString  = "unittestMac1,1";
-const char *OSVersionString  = "unittest 1.1.1 (1A111)";
-const char *BinaryNameString = "unittest";
-const char *VersionString    = "unittest mDNSResponer-00 (Jan  1 1970 00:00:00)";
-
-
-
-UNITTEST_HEADER(run_tests)
-UNITTEST_GROUP(DNSMessageTest)
-UNITTEST_GROUP(ResourceRecordTest)
-UNITTEST_GROUP(mDNSCoreReceiveTest)
-//UNITTEST_GROUP(CNameRecordTests) // Commenting out until issue reported in <rdar://problem/30589360> is debugged.
-UNITTEST_GROUP(LocalOnlyTimeoutTests)
-UNITTEST_FOOTER
-
-// UNITTEST_MAIN is run in daemon.c
-
index 9dae75a0b03ac2b9e45f90cfce23230c5d18f6fc..163ccc429da36c307a5902abac87cb295d18007e 100644 (file)
@@ -1,4 +1,5 @@
 #include "DNSCommon.h"                  // Defines general DNS utility routines
+#include "unittest_common.h"
 
 // To match *either* a v4 or v6 instance of this interface
 mDNSlocal mDNSInterfaceID SearchForInterfaceByAddr(mDNSAddr* addr)
@@ -64,3 +65,8 @@ mDNSexport void UpdateEtcHosts_ut(void *context)
        UpdateEtcHosts(&mDNSStorage, context);
        mDNS_Unlock(&mDNSStorage);
 }
+
+mDNSexport void mDNSDomainLabelFromCFString_ut(CFStringRef cfs, domainlabel *const namelabel)
+{
+    mDNSDomainLabelFromCFString(cfs, namelabel);
+}
index 0384d2c103445074f4cd27dca4f56e7bbd23b889..ac9615b6bd9a4132e290be5c02cff69d9ce9af19 100644 (file)
@@ -1,4 +1,5 @@
 #include "DNSCommon.h"                  // Defines general DNS utility routines
+#include "unittest_common.h"
 
 mDNSexport mStatus mDNS_InitStorage_ut(mDNS *const m, mDNS_PlatformSupport *const p,
                                                                           CacheEntity *rrcachestorage, mDNSu32 rrcachesize,
index 971a14194f0a6ccec07c94707e9bd0e5d49bf8e8..b96379577b7e1c2d2a86123df32be9a04783e1b7 100644 (file)
@@ -1,4 +1,5 @@
 #include "DNSCommon.h"                  // Defines general DNS utility routines
+#include "unittest_common.h"
 
 mDNSexport mStatus handle_client_request_ut(void *req)
 {
@@ -27,8 +28,8 @@ mDNSexport void LogCacheRecords_ut(mDNSs32 now, mDNSu32* retCacheUsed, mDNSu32*
                                        InterfaceID = cr->resrec.rDNSServer->interface;
                                ifname = InterfaceNameForID(&mDNSStorage, InterfaceID);
                                if (cr->CRActiveQuestion) CacheActive++;
-                               PrintOneCacheRecord(cr, slot, remain, ifname, &CacheUsed);
-                               PrintCachedRecords(cr, slot, remain, ifname, &CacheUsed);
+                               PrintOneCacheRecordToFD(STDOUT_FILENO, cr, slot, remain, ifname, &CacheUsed);
+                               PrintCachedRecordsToFD(STDOUT_FILENO, cr, slot, remain, ifname, &CacheUsed);
                        }
                }
        }
@@ -39,5 +40,5 @@ mDNSexport void LogCacheRecords_ut(mDNSs32 now, mDNSu32* retCacheUsed, mDNSu32*
 
 mDNSexport int LogEtcHosts_ut(mDNS *const m)
 {
-       return LogEtcHosts(m);
+       return LogEtcHostsToFD(STDOUT_FILENO, m);
 }
diff --git a/unittests/unittest.c b/unittests/unittest.c
deleted file mode 100644 (file)
index 1ad4b03..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/* -*- Mode: C; tab-width: 4 -*-
- *
- * Copyright (c) 2015 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.
- */
-#include <stdlib.h>
-#include "unittest.h"
-
-int _unittest_assert_i(const int condition, const int i, const char * const conditionStr,
-                       const char * const filename, const unsigned int linenum,
-                       const char * const functionname, __test_item ** __i, int * const __success)
-{
-    if (!condition)
-    {
-        __test_item* tba = malloc(sizeof(__test_item));
-        tba->next = *__i;
-        tba->file = filename;
-        tba->line = linenum;
-        tba->func = functionname;
-        tba->s = conditionStr;
-        tba->iter_count = i;
-        *__i = tba;
-        *__success = 0;
-        printf("F");
-    }
-    else
-    {
-        printf(".");
-    }
-
-    fflush(NULL);
-    return condition;
-}
-
-void _unittest_print_list(__test_item* __i)
-{
-    __test_item* __tmp = NULL;
-    while (__i)
-    {
-        __test_item* __o = __i->next;
-        __i->next = __tmp;
-        __tmp = __i;
-        __i = __o;
-    }
-    __i = __tmp;
-
-    while(__i)
-    {
-        printf("%s: In function `%s':\n%s:%d: error: failed UNITTEST_ASSERT", __i->file, __i->func, __i->file, __i->line);
-        if (__i->iter_count != -1) printf(" at iteration %d", __i->iter_count);
-        printf(": %s\n", __i->s);
-        __test_item* tbd = __i;
-        __i = __i->next;
-        free(tbd);
-    }
-}
-
-// test by building like:
-//   gcc -g -Wall -Werror -DTEST_UNITTEST_SCAFFOLD unittest.c
-// #define TEST_UNITTEST_SCAFFOLD 1
-#if TEST_UNITTEST_SCAFFOLD
-
-// modify this test as necessary to test the scaffold
-UNITTEST_HEADER(test1)
-    int i = 0;
-    int j = 1;
-    int k = 2;
-
-    UNITTEST_ASSERT(i==j);
-    UNITTEST_ASSERTI(j==i, k);
-    UNITTEST_ASSERT(i==i);
-    UNITTEST_ASSERTI(j==j, k);
-    UNITTEST_ASSERT_RETURN(j==j);
-    UNITTEST_ASSERTI_RETURN(j==j, k);
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(test2)
-    UNITTEST_ASSERT(1);
-    UNITTEST_ASSERT(0);
-    UNITTEST_ASSERT(1);
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(unittest_tests)
-UNITTEST_TEST(test1)
-UNITTEST_TEST(test2)
-UNITTEST_FOOTER
-
-UNITTEST_HEADER(run_tests)
-UNITTEST_GROUP(unittest_tests)
-UNITTEST_FOOTER
-
-UNITTEST_MAIN
-
-#endif // TEST_UNITTEST_SCAFFOLD
index 84dd5d778f410f96f32f46ed22a839a071bab450..4b6f1eb10b32ff0eff35ff746886d76e696ff043 100644 (file)
@@ -23,6 +23,7 @@
 #include "unittest_common.h"
 
 #include <MacTypes.h>
+
 #ifndef _UNITTEST_H_
 #define _UNITTEST_H_
 
 extern "C" {
 #endif
 
-typedef struct __test_item_
-{
-    struct     __test_item_*   next;
-    const      char*           file;
-    unsigned   int             line;
-    const      char*           func;
-    const      char*           s;
-    int        iter_count;
-}   __test_item;
-
-int run_tests(void);
-
-#define UNITTEST_HEADER(X) int X() { int __success = 1; __test_item* __i = NULL;
-
-#define UNITTEST_GROUP(X) { printf("== %s ==\n", #X); __success = X() && __success; }
-#define UNITTEST_TEST(X)  { printf("%s: ", #X); fflush(NULL); __success = X() && __success; }
-
-int _unittest_assert_i(const int condition, const int i, const char * const conditionStr,
-                       const char * const filename, const unsigned int linenum,
-                       const char * const functionname, __test_item ** __i, int * const __success);
-#define UNITTEST_ASSERTI(X,I) (_unittest_assert_i((X)!=0, (I), #X, __FILE__, __LINE__, __func__, &__i, &__success))
-#define UNITTEST_ASSERT(X)    UNITTEST_ASSERTI(X, -1)
-#define UNITTEST_ASSERTI_RETURN(X,I) { if (!UNITTEST_ASSERTI(X,I)) goto __unittest_footer__; }
-#define UNITTEST_ASSERT_RETURN(X) UNITTEST_ASSERTI_RETURN(X, -1)
-
-void _unittest_print_list(__test_item* __i);
-#define UNITTEST_FOOTER       goto __unittest_footer__; __unittest_footer__: printf("\n"); fflush(NULL); _unittest_print_list(__i); return __success; }
-
-#define UNITTEST_MAIN     int main (int argc, char** argv) \
-                          { \
-                              (void)(argv); \
-                              signal(SIGPIPE, SIG_IGN); \
-                              FILE* fp; \
-                              unlink("unittest_success"); \
-                              if (!run_tests()) \
-                              { \
-                                  printf("unit test FAILED\n"); \
-                                  return -1; \
-                              } \
-                              fp = fopen("unittest_success", "w"); \
-                              if (!fp) return -2; \
-                              fprintf(fp, "unit test %s\n", "SUCCEEDED"); \
-                              fclose(fp); \
-                              printf("unit test SUCCESS\n"); \
-                              if (argc != 1) \
-                              { \
-                                  char c; \
-                                  printf("run leaks now\n"); \
-                                  read(STDIN_FILENO, &c, 1); \
-                              } \
-                              return 0; \
-                          }
-#define UNITTEST_SENDDNSMESSAGE mStatus mDNSSendDNSMessage(mDNS *const m, DNSMessage *const msg, mDNSu8 *end,  \
-       mDNSInterfaceID InterfaceID, UDPSocket *src, const mDNSAddr *dst,  \
-       mDNSIPPort dstport, TCPSocket *sock, DomainAuthInfo *authInfo,  \
-       mDNSBool useBackgroundTrafficClass) \
-       { \
-               (void)(m); \
-               (void)(msg); \
-               (void)(end); \
-               (void)(InterfaceID); \
-               (void)(src); \
-               (void)(dst); \
-               (void)(dstport); \
-               (void)(sock); \
-               (void)(authInfo); \
-               (void)(useBackgroundTrafficClass); \
-               return 0; \
-       }
-
 #define UNITTEST_SETSOCKOPT void mDNSPlatformSetSocktOpt(void *sockCxt, mDNSTransport_Type transType, \
     mDNSAddr_Type addrType, const DNSQuestion *q) \
     { \
@@ -115,8 +46,6 @@ void _unittest_print_list(__test_item* __i);
         (void)(sock); \
     }
 
-#define UNITTEST_FAIL_ASSERT { assert(((void*)__func__) == 0); }
-
 #ifdef __cplusplus
 }
 #endif
index 397180598c2ac7f042fc30e2d6f0c15061ffde6d..774b8e9ba1afe65d4265fb8ec2858a869f8d51ad 100644 (file)
@@ -82,7 +82,7 @@ mDNSexport mStatus start_client_request(request_state* req, char *msgbuf, size_t
        init_client_request(req, msgbuf, msgsz, op);
 
        mStatus result = handle_client_request_ut((void*)req);
-       DNSQuestion* q = &req->u.queryrecord.q;
+       DNSQuestion* q = &req->u.queryrecord.op.q;
        q->LocalSocket = socket;
        return result;
 }
@@ -94,7 +94,7 @@ mDNSexport void receive_response(const request_state* req, DNSMessage *msg, size
        mDNSAddr srcaddr;
        mDNSIPPort srcport, dstport;
        const mDNSu8 * end;
-       DNSQuestion *q = (DNSQuestion *)&req->u.queryrecord.q;
+       DNSQuestion *q = (DNSQuestion *)&req->u.queryrecord.op.q;
        UInt8* data = (UInt8*)msg;
 
        // Used same values for DNS server as specified during init of unit test
@@ -155,3 +155,33 @@ mDNSexport void get_ip(const char *const name, struct sockaddr_storage *result)
        if (aiList) freeaddrinfo(aiList);
 }
 
+// The AddDNSServer_ut function adds a dns server to mDNSResponder's list.
+mDNSexport mStatus AddDNSServer_ut(void)
+{
+    mDNS *m = &mDNSStorage;
+    m->timenow = 0;
+    mDNS_Lock(m);
+    domainname  d;
+    mDNSAddr    addr;
+    mDNSIPPort  port;
+    mDNSs32     serviceID      = 0;
+    mDNSu32     scoped         = 0;
+    mDNSu32     timeout        = dns_server_timeout;
+    mDNSBool    cellIntf       = 0;
+    mDNSBool    isExpensive    = 0;
+    mDNSBool    isConstrained  = 0;
+    mDNSBool    isCLAT46       = mDNSfalse;
+    mDNSu32     resGroupID     = dns_server_resGroupID;
+    mDNSBool    reqA           = mDNStrue;
+    mDNSBool    reqAAAA        = mDNStrue;
+    mDNSBool    reqDO          = mDNSfalse;
+    d.c[0]                     = 0;
+    addr.type                  = mDNSAddrType_IPv4;
+    addr.ip.v4.NotAnInteger    = dns_server_ipv4.NotAnInteger;
+    port.NotAnInteger          = client_resp_src_port;
+    mDNS_AddDNSServer(m, &d, primary_interfaceID, serviceID, &addr, port, scoped, timeout,
+                      cellIntf, isExpensive, isConstrained, isCLAT46, resGroupID,
+                      reqA, reqAAAA, reqDO);
+    mDNS_Unlock(m);
+    return mStatus_NoError;
+}
index 4b62bb956d08778579c2dc77311e94dc149c9423..b22c10441d4fcf9d1a66483f83dc3a810c427510 100644 (file)
@@ -8,6 +8,7 @@
 #include <netdb.h>                  // for getaddrinfo
 #include <net/if.h>
 #include <pthread.h>
+#include <CoreFoundation/CoreFoundation.h>
 
 // Primary interface info that is used when simulating the receive of the response packet
 extern mDNSInterfaceID primary_interfaceID;
@@ -51,5 +52,9 @@ extern int      LogEtcHosts_ut(mDNS *const m);
 extern mDNSBool mDNSMacOSXCreateEtcHostsEntry_ut(const domainname *domain, const struct sockaddr *sa,
                                                  const domainname *cname, char *ifname, AuthHash *auth);
 extern void     UpdateEtcHosts_ut(void *context);
+extern mStatus  AddDNSServer_ut(void);
+
+// HelperFunctionTest
+extern void mDNSDomainLabelFromCFString_ut(CFStringRef cfs, domainlabel *const namelabel);
 
 #endif /* UNITTEST_COMMON_H */